root/src/modules/lua.c

Revision de520024f8801f5cc271ac9301e66f7c3690558e, 27.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

Don't assert on double runs, just log an error

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007-2010, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include "noit_conf.h"
36 #include "noit_module.h"
37 #include "noit_check.h"
38 #include "noit_check_tools.h"
39 #include "utils/noit_log.h"
40 #include "lua_noit.h"
41
42 #ifdef HAVE_ALLOCA_H
43 #include <alloca.h>
44 #endif
45 #include <assert.h>
46
47 static noit_log_stream_t nlerr = NULL;
48 static noit_log_stream_t nldeb = NULL;
49 static noit_hash_table noit_coros = NOIT_HASH_EMPTY;
50
51 struct loader_conf {
52   char *script_dir;
53 };
54 static struct loader_conf *__get_loader_conf(noit_module_loader_t *self) {
55   struct loader_conf *c;
56   c = noit_image_get_userdata(&self->hdr);
57   if(!c) {
58     c = calloc(1, sizeof(*c));
59     noit_image_set_userdata(&self->hdr, c);
60   }
61   return c;
62 }
63 static void
64 noit_lua_loader_set_directory(noit_module_loader_t *self, const char *dir) {
65   struct loader_conf *c = __get_loader_conf(self);
66   if(c->script_dir) free(c->script_dir);
67   c->script_dir = strdup(dir);
68 }
69 static const char *
70 noit_lua_loader_get_directory(noit_module_loader_t *self) {
71   struct loader_conf *c = __get_loader_conf(self);
72   return c->script_dir;
73 }
74
75 void
76 cancel_coro(noit_lua_check_info_t *ci) {
77   lua_getglobal(ci->lmc->lua_state, "noit_coros");
78   luaL_unref(ci->lmc->lua_state, -1, ci->coro_state_ref);
79   lua_pop(ci->lmc->lua_state, 1);
80   lua_gc(ci->lmc->lua_state, LUA_GCCOLLECT, 0);
81   noit_hash_delete(&noit_coros,
82                    (const char *)&ci->coro_state, sizeof(ci->coro_state),
83                    NULL, NULL);
84 }
85
86 noit_lua_check_info_t *
87 get_ci(lua_State *L) {
88   void *v = NULL;
89   if(noit_hash_retrieve(&noit_coros, (const char *)&L, sizeof(L), &v))
90     return (noit_lua_check_info_t *)v;
91   return NULL;
92 }
93 static void
94 int_cl_free(void *vcl) {
95   free(vcl);
96 }
97
98 static void
99 noit_event_dispose(void *ev) {
100   int mask;
101   eventer_t *value = ev;
102   eventer_t removed, e = *value;
103   noitL(nldeb, "lua check cleanup: dropping (%p)->fd (%d)\n", e, e->fd);
104   removed = eventer_remove(e);
105   noitL(nldeb, "    remove from eventer system %s\n",
106         removed ? "succeeded" : "failed");
107   if(e->mask & (EVENTER_READ|EVENTER_WRITE|EVENTER_EXCEPTION)) {
108     noitL(nldeb, "    closing down fd %d\n", e->fd);
109     e->opset->close(e->fd, &mask, e);
110   }
111   if(e->closure) {
112     struct nl_generic_cl *cl;
113     cl = e->closure;
114     if(cl->free) cl->free(cl);
115   }
116   eventer_free(e);
117   free(ev);
118 }
119 void
120 noit_lua_check_register_event(noit_lua_check_info_t *ci, eventer_t e) {
121   eventer_t *eptr;
122   eptr = calloc(1, sizeof(*eptr));
123   memcpy(eptr, &e, sizeof(*eptr));
124   if(!ci->events) ci->events = calloc(1, sizeof(*ci->events));
125   assert(noit_hash_store(ci->events, (const char *)eptr, sizeof(*eptr), eptr));
126 }
127 void
128 noit_lua_check_deregister_event(noit_lua_check_info_t *ci, eventer_t e,
129                                 int tofree) {
130   assert(ci->events);
131   assert(noit_hash_delete(ci->events, (const char *)&e, sizeof(e),
132                           NULL, tofree ? noit_event_dispose : free));
133 }
134 void
135 noit_lua_check_clean_events(noit_lua_check_info_t *ci) {
136   if(ci->events == NULL) return;
137   noit_hash_destroy(ci->events, NULL, noit_event_dispose);
138   free(ci->events);
139   ci->events = NULL;
140 }
141
142 static void
143 noit_lua_pushmodule(lua_State *L, const char *m) {
144   int stack_pos = LUA_GLOBALSINDEX;
145   char *copy, *part, *brkt;
146   copy = alloca(strlen(m)+1);
147   assert(copy);
148   memcpy(copy,m,strlen(m)+1);
149
150   for(part = strtok_r(copy, ".", &brkt);
151       part;
152       part = strtok_r(NULL, ".", &brkt)) {
153     lua_getfield(L, stack_pos, part);
154     if(stack_pos == -1) lua_remove(L, -2);
155     else stack_pos = -1;
156   }
157 }
158 static void
159 noit_lua_hash_to_table(lua_State *L,
160                        noit_hash_table *t) {
161   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
162   const char *key, *value;
163   int klen;
164   lua_createtable(L, 0, t ? t->size : 0);
165   if(t) {
166     while(noit_hash_next_str(t, &iter, &key, &klen, &value)) {
167       lua_pushlstring(L, value, strlen(value));
168       lua_setfield(L, -2, key);
169     }
170   }
171   return;
172 }
173 static int
174 noit_lua_module_set_description(lua_State *L) {
175   noit_module_t *module;
176   module = lua_touserdata(L, lua_upvalueindex(1));
177   if(lua_gettop(L) == 1)
178     module->hdr.description = strdup(lua_tostring(L, 1));
179   else if(lua_gettop(L) > 1)
180     luaL_error(L, "wrong number of arguments");
181   lua_pushstring(L, module->hdr.description);
182   return 1;
183 }
184 static int
185 noit_lua_module_set_name(lua_State *L) {
186   noit_module_t *module;
187   module = lua_touserdata(L, lua_upvalueindex(1));
188   if(lua_gettop(L) == 1)
189     module->hdr.name = strdup(lua_tostring(L, 1));
190   else if(lua_gettop(L) > 1)
191     luaL_error(L, "wrong number of arguments");
192   lua_pushstring(L, module->hdr.name);
193   return 1;
194 }
195 static int
196 noit_lua_module_set_xml_description(lua_State *L) {
197   noit_module_t *module;
198   module = lua_touserdata(L, lua_upvalueindex(1));
199   if(lua_gettop(L) == 1)
200     module->hdr.xml_description = strdup(lua_tostring(L, 1));
201   else if(lua_gettop(L) > 1)
202     luaL_error(L, "wrong number of arguments");
203   lua_pushstring(L, module->hdr.xml_description);
204   return 1;
205 }
206 static int
207 noit_module_index_func(lua_State *L) {
208   noit_module_t **udata, *module;
209   const char *k;
210   int n;
211   n = lua_gettop(L);    /* number of arguments */
212   assert(n == 2);
213   if(!luaL_checkudata(L, 1, "noit_module_t")) {
214     luaL_error(L, "metatable error, arg1 not a noit_module_t!");
215   }
216   udata = lua_touserdata(L, 1);
217   module = *udata;
218   if(!lua_isstring(L, 2)) {
219     luaL_error(L, "metatable error, arg2 not a string!");
220   }
221   k = lua_tostring(L, 2);
222   switch(*k) {
223     case 'd':
224       if(!strcmp(k, "description")) {
225         lua_pushlightuserdata(L, module);
226         lua_pushcclosure(L, noit_lua_module_set_description, 1);
227       }
228       else break;
229       return 1;
230     case 'n':
231       if(!strcmp(k, "name")) {
232         lua_pushlightuserdata(L, module);
233         lua_pushcclosure(L, noit_lua_module_set_name, 1);
234       }
235       else break;
236       return 1;
237     case 'x':
238       if(!strcmp(k, "xml_description")) {
239         lua_pushlightuserdata(L, module);
240         lua_pushcclosure(L, noit_lua_module_set_xml_description, 1);
241       }
242       else break;
243       return 1;
244     default:
245       break;
246   }
247   luaL_error(L, "noit_module_t no such element: %s", k);
248   return 0;
249 }
250 static int
251 noit_lua_get_available(lua_State *L) {
252   char av[2] = { '\0', '\0' };
253   noit_check_t *check;
254   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
255   check = lua_touserdata(L, lua_upvalueindex(1));
256   av[0] = (char)check->stats.current.available;
257   lua_pushstring(L, av);
258   return 1;
259 }
260 static int
261 noit_lua_set_available(lua_State *L) {
262   noit_check_t *check;
263   noit_lua_check_info_t *ci;
264   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
265   check = lua_touserdata(L, lua_upvalueindex(1));
266   ci = check->closure;
267   ci->current.available = lua_tointeger(L, lua_upvalueindex(2));
268   return 0;
269 }
270 static int
271 noit_lua_get_state(lua_State *L) {
272   char status[2] = { '\0', '\0' };
273   noit_check_t *check;
274   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
275   check = lua_touserdata(L, lua_upvalueindex(1));
276   status[0] = (char)check->stats.current.state;
277   lua_pushstring(L, status);
278   return 1;
279 }
280 static int
281 noit_lua_set_state(lua_State *L) {
282   noit_check_t *check;
283   noit_lua_check_info_t *ci;
284   if(lua_gettop(L)) luaL_error(L, "wrong number of arguments");
285   check = lua_touserdata(L, lua_upvalueindex(1));
286   ci = check->closure;
287   ci->current.state = lua_tointeger(L, lua_upvalueindex(2));
288   return 0;
289 }
290 static int
291 noit_lua_set_status(lua_State *L) {
292   const char *ns;
293   noit_check_t *check;
294   noit_lua_check_info_t *ci;
295   if(lua_gettop(L) != 1) luaL_error(L, "wrong number of arguments");
296   check = lua_touserdata(L, lua_upvalueindex(1));
297   ci = check->closure;
298   /* strdup here... but free later */
299   if(ci->current.status) free(ci->current.status);
300   ns = lua_tostring(L, 1);
301   ci->current.status = ns ? strdup(ns) : NULL;
302   return 0;
303 }
304 static int
305 noit_lua_set_metric_json(lua_State *L) {
306   noit_check_t *check;
307   noit_lua_check_info_t *ci;
308   const char *json;
309   size_t jsonlen;
310   int rv;
311
312   if(lua_gettop(L) != 1) luaL_error(L, "wrong number of arguments");
313   check = lua_touserdata(L, lua_upvalueindex(1));
314   ci = check->closure;
315   if(!lua_isstring(L, 1)) luaL_error(L, "argument #1 must be a string");
316   json = lua_tolstring(L, 1, &jsonlen);
317   rv = noit_check_stats_from_json_str(check, &ci->current, json, (int)jsonlen);
318   lua_pushinteger(L, rv);
319   return 1;
320 }
321 static int
322 noit_lua_set_metric(lua_State *L) {
323   noit_check_t *check;
324   noit_lua_check_info_t *ci;
325   const char *metric_name;
326   metric_type_t metric_type;
327
328   double __n = 0.0;
329   int32_t __i = 0;
330   u_int32_t __I = 0;
331   int64_t __l = 0;
332   u_int64_t __L = 0;
333
334   if(lua_gettop(L) != 2) luaL_error(L, "wrong number of arguments");
335   check = lua_touserdata(L, lua_upvalueindex(1));
336   ci = check->closure;
337   if(!lua_isstring(L, 1)) luaL_error(L, "argument #1 must be a string");
338   metric_name = lua_tostring(L, 1);
339   metric_type = lua_tointeger(L, lua_upvalueindex(2));
340   if(lua_isnil(L, 2)) {
341     noit_stats_set_metric(check, &ci->current, metric_name, metric_type, NULL);
342     lua_pushboolean(L, 1);
343     return 1;
344   }
345   switch(metric_type) {
346     case METRIC_INT32:
347     case METRIC_UINT32:
348     case METRIC_INT64:
349     case METRIC_UINT64:
350     case METRIC_DOUBLE:
351       if(!lua_isnumber(L, 2)) {
352         noit_stats_set_metric(check, &ci->current, metric_name, metric_type, NULL);
353         lua_pushboolean(L, 0);
354         return 1;
355       }
356     default:
357     break;
358   }
359   switch(metric_type) {
360     case METRIC_GUESS:
361     case METRIC_STRING:
362       noit_stats_set_metric(check, &ci->current, metric_name, metric_type,
363                             (void *)lua_tostring(L, 2));
364       break;
365     case METRIC_INT32:
366       __i = strtol(lua_tostring(L, 2), NULL, 10);
367       noit_stats_set_metric(check, &ci->current, metric_name, metric_type, &__i);
368       break;
369     case METRIC_UINT32:
370       __I = strtoul(lua_tostring(L, 2), NULL, 10);
371       noit_stats_set_metric(check, &ci->current, metric_name, metric_type, &__I);
372       break;
373     case METRIC_INT64:
374       __l = strtoll(lua_tostring(L, 2), NULL, 10);
375       noit_stats_set_metric(check, &ci->current, metric_name, metric_type, &__l);
376       break;
377     case METRIC_UINT64:
378       __L = strtoull(lua_tostring(L, 2), NULL, 10);
379       noit_stats_set_metric(check, &ci->current, metric_name, metric_type, &__L);
380       break;
381     case METRIC_DOUBLE:
382       __n = luaL_optnumber(L, 2, 0);
383       noit_stats_set_metric(check, &ci->current, metric_name, metric_type, &__n);
384       break;
385   }
386   lua_pushboolean(L, 1);
387   return 1;
388 }
389 static int
390 noit_check_index_func(lua_State *L) {
391   int n;
392   const char *k;
393   noit_check_t **udata, *check;
394   n = lua_gettop(L);    /* number of arguments */
395   assert(n == 2);
396   if(!luaL_checkudata(L, 1, "noit_check_t")) {
397     luaL_error(L, "metatable error, arg1 not a noit_check_t!");
398   }
399   udata = lua_touserdata(L, 1);
400   check = *udata;
401   if(!lua_isstring(L, 2)) {
402     luaL_error(L, "metatable error, arg2 not a string!");
403   }
404   k = lua_tostring(L, 2);
405   switch(*k) {
406     case 'a':
407       if(!strcmp(k, "available")) {
408         lua_pushlightuserdata(L, check);
409         lua_pushinteger(L, NP_AVAILABLE);
410         lua_pushcclosure(L, noit_lua_set_available, 2);
411       }
412       else if(!strcmp(k, "availability")) {
413         lua_pushlightuserdata(L, check);
414         lua_pushcclosure(L, noit_lua_get_available, 1);
415       }
416       else break;
417       return 1;
418     case 'b':
419       if(!strcmp(k, "bad")) {
420         lua_pushlightuserdata(L, check);
421         lua_pushinteger(L, NP_BAD);
422         lua_pushcclosure(L, noit_lua_set_state, 2);
423       }
424       else break;
425       return 1;
426     case 'c':
427       if(!strcmp(k, "config")) noit_lua_hash_to_table(L, check->config);
428       else break;
429       return 1;
430     case 'g':
431       if(!strcmp(k, "good")) {
432         lua_pushlightuserdata(L, check);
433         lua_pushinteger(L, NP_GOOD);
434         lua_pushcclosure(L, noit_lua_set_state, 2);
435       }
436       else break;
437       return 1;
438     case 'm':
439       if(!strcmp(k, "module")) lua_pushstring(L, check->module);
440
441 #define IF_METRIC_BLOCK(name,type) \
442       if(!strcmp(k, name)) { \
443         lua_pushlightuserdata(L, check); \
444         lua_pushinteger(L, type); \
445         lua_pushcclosure(L, noit_lua_set_metric, 2); \
446       }
447
448       else IF_METRIC_BLOCK("metric", METRIC_GUESS)
449       else IF_METRIC_BLOCK("metric_string", METRIC_STRING)
450       else IF_METRIC_BLOCK("metric_int32", METRIC_INT32)
451       else IF_METRIC_BLOCK("metric_uint32", METRIC_UINT32)
452       else IF_METRIC_BLOCK("metric_int64", METRIC_INT64)
453       else IF_METRIC_BLOCK("metric_uint64", METRIC_UINT64)
454       else IF_METRIC_BLOCK("metric_double", METRIC_DOUBLE)
455       else if(!strcmp(k, "metric_json")) {
456         lua_pushlightuserdata(L, check);
457         lua_pushcclosure(L, noit_lua_set_metric_json, 1);
458       }
459       else break;
460       return 1;
461     case 'n':
462       if(!strcmp(k, "name")) lua_pushstring(L, check->name);
463       else break;
464       return 1;
465     case 'p':
466       if(!strcmp(k, "period")) lua_pushinteger(L, check->period);
467       else break;
468       return 1;
469     case 's':
470       if(!strcmp(k, "state")) {
471         lua_pushlightuserdata(L, check);
472         lua_pushcclosure(L, noit_lua_get_state, 1);
473       }
474       else if(!strcmp(k, "status")) {
475         lua_pushlightuserdata(L, check);
476         lua_pushcclosure(L, noit_lua_set_status, 1);
477       }
478       else break;
479       return 1;
480     case 't':
481       if(!strcmp(k, "target")) lua_pushstring(L, check->target);
482       else if(!strcmp(k, "target_ip")) {
483         if(check->target_ip[0] == '\0') lua_pushnil(L);
484         else lua_pushstring(L, check->target_ip);
485       }
486       else if(!strcmp(k, "timeout")) lua_pushinteger(L, check->timeout);
487       else break;
488       return 1;
489     case 'u':
490       if(!strcmp(k, "unavailable")) {
491         lua_pushlightuserdata(L, check);
492         lua_pushinteger(L, NP_UNAVAILABLE);
493         lua_pushcclosure(L, noit_lua_set_available, 2);
494       }
495       else break;
496       return 1;
497     default:
498       break;
499   }
500   luaL_error(L, "noit_check_t no such element: %s", k);
501   return 0;
502 }
503 static void
504 noit_lua_setup_module(lua_State *L,
505                       noit_module_t *mod) {
506   noit_module_t **addr;
507   addr = (noit_module_t **)lua_newuserdata(L, sizeof(mod));
508   *addr = mod;
509   if(luaL_newmetatable(L, "noit_module_t") == 1) {
510     lua_pushcclosure(L, noit_module_index_func, 0);
511     lua_setfield(L, -2, "__index");
512   }
513   lua_setmetatable(L, -2);
514 }
515 static void
516 noit_lua_setup_check(lua_State *L,
517                      noit_check_t *check) {
518   noit_check_t **addr;
519   addr = (noit_check_t **)lua_newuserdata(L, sizeof(check));
520   *addr = check;
521   if(luaL_newmetatable(L, "noit_check_t") == 1) {
522     lua_pushcclosure(L, noit_check_index_func, 0);
523     lua_setfield(L, -2, "__index");
524   }
525   lua_setmetatable(L, -2);
526 }
527 static int
528 noit_lua_module_onload(noit_image_t *i) {
529   int rv;
530   lua_State *L;
531   lua_module_closure_t *lmc;
532
533   noit_lua_init();
534
535   lmc = noit_image_get_userdata(i);
536   L = lmc->lua_state;
537   lua_getglobal(L, "require");
538   lua_pushstring(L, lmc->object);
539   rv = lua_pcall(L, 1, 1, 0);
540   if(rv) {
541     int i;
542     noitL(nlerr, "lua: %s.onload failed\n", lmc->object);
543     i = lua_gettop(L);
544     if(i>0) {
545       if(lua_isstring(L, i)) {
546         const char *err;
547         size_t len;
548         err = lua_tolstring(L, i, &len);
549         noitL(nlerr, "lua: %s\n", err);
550       }
551     }
552     lua_pop(L,i);
553     return -1;
554   }
555   lua_pop(L, lua_gettop(L));
556
557   noit_lua_pushmodule(L, lmc->object);
558   if(lua_isnil(L, -1)) {
559     lua_pop(L, 1);
560     noitL(nlerr, "lua: no such object %s\n", lmc->object);
561     return -1;
562   }
563   lua_getfield(L, -1, "onload");
564   lua_remove(L, -2);
565   if(!lua_isfunction(L, -1)) {
566     lua_pop(L, 1);
567     /* No onload */
568     return 0;
569   }
570   noit_lua_setup_module(L, (noit_module_t *)i);
571   lua_pcall(L, 1, 1, 0);
572   if(lua_isnumber(L, -1)) {
573     int rv;
574     rv = lua_tointeger(L, -1);
575     lua_pop(L, 1);
576     return rv;
577   }
578   lua_pop(L,1);
579   noitL(nlerr, "%s.onload must return a integer\n", lmc->object);
580   return -1;
581 }
582 #define LMC_DECL(L, mod) \
583   lua_State *L; \
584   lua_module_closure_t *lmc; \
585   lmc = noit_module_get_userdata(mod); \
586   L = lmc->lua_state
587 #define SETUP_CALL(L, func, failure) do { \
588   noit_lua_pushmodule(L, lmc->object); \
589   lua_getfield(L, -1, func); \
590   lua_remove(L, -2); \
591   if(!lua_isfunction(L, -1)) { \
592     lua_pop(L, 1); \
593     failure; \
594   } \
595 } while(0)
596 #define RETURN_INT(L, func, expr) do { \
597   int base = lua_gettop(L); \
598   assert(base == 1); \
599   if(lua_isnumber(L, -1)) { \
600     int rv; \
601     rv = lua_tointeger(L, -1); \
602     lua_pop(L, 1); \
603     expr \
604     return rv; \
605   } \
606   lua_pop(L,1); \
607   noitL(nlerr, "%s.%s must return a integer\n", lmc->object, func); \
608 } while(0)
609
610 static int
611 noit_lua_module_config(noit_module_t *mod,
612                        noit_hash_table *options) {
613   LMC_DECL(L, mod);
614   SETUP_CALL(L, "config", return 0);
615
616   noit_lua_setup_module(L, mod);
617   noit_lua_hash_to_table(L, options);
618   noit_hash_destroy(options, free, free);
619   free(options);
620   lua_pcall(L, 2, 1, 0);
621
622   /* If rv == 0, the caller will free options. We've
623    * already freed options, that would be bad. fudge -> 1 */
624   RETURN_INT(L, "config", { rv = (rv == 0) ? 1 : rv; });
625   return -1;
626 }
627 static int
628 noit_lua_module_init(noit_module_t *mod) {
629   LMC_DECL(L, mod);
630   SETUP_CALL(L, "init", return 0);
631
632   noit_lua_setup_module(L, mod);
633   lua_pcall(L, 1, 1, 0);
634
635   RETURN_INT(L, "init", );
636   return -1;
637 }
638 static void
639 noit_lua_module_cleanup(noit_module_t *mod, noit_check_t *check) {
640   noit_lua_check_info_t *ci = check->closure;
641   LMC_DECL(L, mod);
642   SETUP_CALL(L, "cleanup", goto clean);
643
644   noit_lua_setup_module(L, mod);
645   noit_lua_setup_check(L, check);
646   lua_pcall(L, 2, 0, 0);
647
648  clean:
649   if(ci) {
650     noit_lua_check_clean_events(ci);
651     free(ci);
652     check->closure = NULL;
653   }
654 }
655
656 /* Here is where the magic starts */
657 static void
658 noit_lua_log_results(noit_module_t *self, noit_check_t *check) {
659   noit_lua_check_info_t *ci = check->closure;
660   struct timeval duration;
661
662   gettimeofday(&ci->finish_time, NULL);
663   sub_timeval(ci->finish_time, check->last_fire_time, &duration);
664
665   memcpy(&ci->current.whence, &ci->finish_time, sizeof(ci->current.whence));
666   ci->current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;
667
668   /* Only set out stats/log if someone has actually performed a check */
669   if(ci->current.state != NP_UNKNOWN ||
670      ci->current.available != NP_UNKNOWN)
671     noit_check_set_stats(check, &ci->current);
672   free(ci->current.status);
673 }
674 int
675 noit_lua_yield(noit_lua_check_info_t *ci, int nargs) {
676   noitL(nldeb, "lua: %p yielding\n", ci->coro_state);
677   return lua_yield(ci->coro_state, nargs);
678 }
679 int
680 noit_lua_resume(noit_lua_check_info_t *ci, int nargs) {
681   int result = -1, base;
682   noit_module_t *self;
683   noit_check_t *check;
684
685   noitL(nldeb, "lua: %p resuming(%d)\n", ci->coro_state, nargs);
686   result = lua_resume(ci->coro_state, nargs);
687   switch(result) {
688     case 0: /* success */
689       break;
690     case LUA_YIELD: /* The complicated case */
691       /* The person yielding had better setup an event
692        * to wake up the coro...
693        */
694       lua_gc(ci->lmc->lua_state, LUA_GCCOLLECT, 0);
695       goto done;
696     default: /* Errors */
697       noitL(nldeb, "lua resume returned: %d\n", result);
698       ci->current.status = strdup(ci->timed_out ? "timeout" : "unknown error");
699       ci->current.available = NP_UNAVAILABLE;
700       ci->current.state = NP_BAD;
701       base = lua_gettop(ci->coro_state);
702       if(base>0) {
703         if(lua_isstring(ci->coro_state, base)) {
704           const char *err, *nerr;
705           err = lua_tostring(ci->coro_state, base);
706           nerr = lua_tostring(ci->coro_state, base - 2);
707           if(err) noitL(nldeb, "err -> %s\n", err);
708           if(nerr) noitL(nldeb, "nerr -> %s\n", nerr);
709           if(nerr && *nerr == 31) nerr = NULL; // 31? WTF lua?
710           if(err) {
711             nerr = strchr(err, ' '); /* advance past the file */
712             if(nerr) nerr += 1;
713           }
714           if(nerr) {
715             free(ci->current.status);
716             ci->current.status = strdup(nerr);
717           }
718         }
719       }
720       break;
721   }
722
723   self = ci->self;
724   check = ci->check;
725   cancel_coro(ci);
726   noit_lua_log_results(self, check);
727   noit_lua_module_cleanup(self, check);
728   ci = NULL; /* we freed it... explode if someone uses it before we return */
729   check->flags &= ~NP_RUNNING;
730
731  done:
732   return result;
733 }
734 static int
735 noit_lua_check_timeout(eventer_t e, int mask, void *closure,
736                        struct timeval *now) {
737   noit_module_t *self;
738   noit_check_t *check;
739   struct nl_intcl *int_cl = closure;
740   noit_lua_check_info_t *ci = int_cl->ci;
741   noitL(nldeb, "lua: %p ->check_timeout\n", ci->coro_state);
742   ci->timed_out = 1;
743   noit_lua_check_deregister_event(ci, e, 0);
744
745   self = ci->self;
746   check = ci->check;
747
748   if(ci->coro_state) {
749     /* Our coro is still "in-flight". To fix this we will unreference
750      * it, garbage collect it and then ensure that it failes a resume
751      */
752     cancel_coro(ci);
753   }
754   ci->current.status = strdup("timeout");
755   ci->current.available = NP_UNAVAILABLE;
756   ci->current.state = NP_BAD;
757
758   noit_lua_log_results(self, check);
759   noit_lua_module_cleanup(self, check);
760   check->flags &= ~NP_RUNNING;
761
762   if(int_cl->free) int_cl->free(int_cl);
763   return 0;
764 }
765 static int
766 noit_lua_initiate(noit_module_t *self, noit_check_t *check,
767                   noit_check_t *cause) {
768   LMC_DECL(L, self);
769   struct nl_intcl *int_cl;
770   noit_lua_check_info_t *ci;
771   struct timeval p_int, __now;
772   eventer_t e;
773
774   if(!check->closure) check->closure = calloc(1, sizeof(noit_lua_check_info_t));
775   ci = check->closure;
776
777   /* We cannot be running */
778   BAIL_ON_RUNNING_CHECK(check);
779   check->flags |= NP_RUNNING;
780
781   ci->self = self;
782   ci->check = check;
783   ci->cause = cause;
784   noit_check_stats_clear(check, &ci->current);
785
786   gettimeofday(&__now, NULL);
787   memcpy(&check->last_fire_time, &__now, sizeof(__now));
788
789   e = eventer_alloc();
790   e->mask = EVENTER_TIMER;
791   e->callback = noit_lua_check_timeout;
792   /* We wrap this in an alloc so we can blindly free it later */
793   int_cl = calloc(1, sizeof(*int_cl));
794   int_cl->ci = ci;
795   int_cl->free = int_cl_free;
796   e->closure = int_cl;
797   memcpy(&e->whence, &__now, sizeof(__now));
798   p_int.tv_sec = check->timeout / 1000;
799   p_int.tv_usec = (check->timeout % 1000) * 1000;
800   add_timeval(e->whence, p_int, &e->whence);
801   noit_lua_check_register_event(ci, e);
802   eventer_add(e);
803
804   ci->lmc = lmc;
805   lua_getglobal(L, "noit_coros");
806   ci->coro_state = lua_newthread(L);
807   ci->coro_state_ref = luaL_ref(L, -2);
808   lua_pop(L, 1); /* pops noit_coros */
809   noit_hash_store(&noit_coros,
810                   (const char *)&ci->coro_state, sizeof(ci->coro_state),
811                   ci);
812
813   SETUP_CALL(ci->coro_state, "initiate", goto fail);
814   noit_lua_setup_module(ci->coro_state, ci->self);
815   noit_lua_setup_check(ci->coro_state, ci->check);
816   if(cause)
817     noit_lua_setup_check(ci->coro_state, ci->cause);
818   else
819     lua_pushnil(ci->coro_state);
820   noit_lua_resume(ci, 3);
821   return 0;
822
823  fail:
824   noit_lua_log_results(ci->self, ci->check);
825   noit_lua_module_cleanup(ci->self, ci->check);
826   check->flags &= ~NP_RUNNING;
827   return -1;
828 }
829 /* This is the standard wrapper */
830 static int
831 noit_lua_module_initiate_check(noit_module_t *self, noit_check_t *check,
832                                int once, noit_check_t *cause) {
833   if(!check->closure) check->closure = calloc(1, sizeof(noit_lua_check_info_t));
834   INITIATE_CHECK(noit_lua_initiate, self, check, cause);
835   return 0;
836 }
837 static int noit_lua_panic(lua_State *L) {
838   assert(L == NULL);
839   return 0;
840 }
841 static noit_module_t *
842 noit_lua_loader_load(noit_module_loader_t *loader,
843                      char *module_name,
844                      noit_conf_section_t section) {
845   int rv;
846   noit_module_t *m;
847   lua_State *L;
848   lua_module_closure_t *lmc;
849   char *object;
850  
851   noitL(nldeb, "Loading lua module: %s\n", module_name);
852   if(noit_conf_get_string(section, "@object", &object) == 0) {
853     noitL(nlerr, "Lua module %s require object attribute.\n", module_name);
854     return NULL;
855   }
856
857   m = noit_blank_module();
858   m->hdr.magic = NOIT_MODULE_MAGIC;
859   m->hdr.version = NOIT_MODULE_ABI_VERSION;
860   m->hdr.name = strdup(module_name);
861   m->hdr.description = strdup("Lua module");
862   m->hdr.onload = noit_lua_module_onload;
863   lmc = calloc(1, sizeof(*lmc));
864   lmc->object = object;
865
866   L = lmc->lua_state = lua_open();
867   lua_atpanic(L, &noit_lua_panic);
868
869   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
870   luaL_openlibs(L);  /* open libraries */
871   luaopen_pack(L);
872   luaopen_bit(L);
873   luaopen_noit(L);
874
875   lua_newtable(L);
876   lua_setglobal(L, "noit_coros");
877
878   lua_getfield(L, LUA_GLOBALSINDEX, "package");
879   lua_pushfstring(L, "%s", noit_lua_loader_get_directory(loader));
880   lua_setfield(L, -2, "path");
881   lua_pop(L, 1);
882
883 #define require(a) do { \
884   lua_getglobal(L, "require"); \
885   lua_pushstring(L, #a); \
886   rv = lua_pcall(L, 1, 1, 0); \
887   if(rv != 0) { \
888     noitL(noit_stderr, "Loading: %d\n", rv); \
889     goto load_failed; \
890   } \
891   lua_pop(L, 1); \
892 } while(0)
893
894   require(noit.timeval);
895   require(noit.extras);
896
897   lua_gc(L, LUA_GCRESTART, 0);
898
899   noit_image_set_userdata(&m->hdr, lmc);
900   if(m->hdr.onload(&m->hdr) == -1) {
901    load_failed:
902     lua_close(L);
903     free(m->hdr.name);
904     free(m->hdr.description);
905     free(lmc->object);
906     free(lmc);
907     /* FIXME: We leak the opaque_handler in the module here... */
908     free(m);
909     return NULL;
910   }
911
912   m->config = noit_lua_module_config;
913   m->init = noit_lua_module_init;
914   m->initiate_check = noit_lua_module_initiate_check;
915   m->cleanup = noit_lua_module_cleanup;
916
917   noit_register_module(m);
918   return m;
919 }
920
921 static int
922 noit_lua_loader_config(noit_module_loader_t *self, noit_hash_table *o) {
923   const char *dir = ".";
924   noit_hash_retr_str(o, "directory", strlen("directory"), &dir);
925   noit_lua_loader_set_directory(self, dir);
926   return 0;
927 }
928 static int
929 noit_lua_loader_onload(noit_image_t *self) {
930   nlerr = noit_log_stream_find("error/lua");
931   nldeb = noit_log_stream_find("debug/lua");
932   if(!nlerr) nlerr = noit_stderr;
933   if(!nldeb) nldeb = noit_debug;
934   eventer_name_callback("lua/check_timeout", noit_lua_check_timeout);
935   return 0;
936 }
937
938 #include "lua.xmlh"
939 noit_module_loader_t lua = {
940   {
941     NOIT_LOADER_MAGIC,
942     NOIT_LOADER_ABI_VERSION,
943     "lua",
944     "Lua check loader",
945     lua_xml_description,
946     noit_lua_loader_onload,
947   },
948   noit_lua_loader_config,
949   NULL,
950   noit_lua_loader_load
951 };
Note: See TracBrowser for help on using the browser.