root/src/modules/lua_noit.c

Revision 0be295055302f1118f893a50937072790a2c35bb, 35.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 years ago)

add some more xml helpers

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, 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 <assert.h>
36 #include <math.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #ifdef HAVE_SYS_FILIO_H
42 #include <sys/filio.h>
43 #endif
44 #include <zlib.h>
45 #include <libxml/parser.h>
46 #include <libxml/xpath.h>
47 #include <libxml/tree.h>
48 #include <openssl/md5.h>
49
50 #include "noit_conf.h"
51 #include "noit_module.h"
52 #include "noit_check.h"
53 #include "noit_check_tools.h"
54 #include "utils/noit_log.h"
55 #include "utils/noit_str.h"
56 #include "utils/noit_b64.h"
57 #include "eventer/eventer.h"
58 #include "lua_noit.h"
59
60 #define DEFLATE_CHUNK_SIZE 32768
61
62 static void
63 nl_extended_free(void *vcl) {
64   struct nl_slcl *cl = vcl;
65   if(cl->inbuff) free(cl->inbuff);
66   free(cl);
67 }
68 static void
69 inbuff_addlstring(struct nl_slcl *cl, const char *b, int l) {
70   int newsize = 0;
71   char *newbuf;
72   if(cl->inbuff_len + l > cl->inbuff_allocd)
73     newsize = cl->inbuff_len + l;
74   if(newsize) {
75     newbuf = cl->inbuff_allocd ? realloc(cl->inbuff, newsize) : malloc(newsize);
76     assert(newbuf);
77     cl->inbuff = newbuf;
78     cl->inbuff_allocd = newsize;
79   }
80   memcpy(cl->inbuff + cl->inbuff_len, b, l);
81   cl->inbuff_len += l;
82 }
83
84 static int
85 noit_lua_socket_connect_complete(eventer_t e, int mask, void *vcl,
86                                  struct timeval *now) {
87   noit_lua_check_info_t *ci;
88   struct nl_slcl *cl = vcl;
89   int args = 0, aerrno;
90   socklen_t aerrno_len = sizeof(aerrno);
91
92   ci = get_ci(cl->L);
93   assert(ci);
94   noit_lua_check_deregister_event(ci, e, 0);
95
96   *(cl->eptr) = eventer_alloc();
97   memcpy(*cl->eptr, e, sizeof(*e));
98   noit_lua_check_register_event(ci, *cl->eptr);
99
100   if(getsockopt(e->fd,SOL_SOCKET,SO_ERROR, &aerrno, &aerrno_len) == 0)
101     if(aerrno != 0) goto connerr;
102
103   if(!(mask & EVENTER_EXCEPTION) &&
104      mask & EVENTER_WRITE) {
105     /* Connect completed successfully */
106     lua_pushinteger(cl->L, 0);
107     args = 1;
108   }
109   else {
110     aerrno = errno;
111    connerr:
112     lua_pushinteger(cl->L, -1);
113     lua_pushstring(cl->L, strerror(aerrno));
114     args = 2;
115   }
116   noit_lua_resume(ci, args);
117   return 0;
118 }
119 static int
120 noit_lua_socket_connect(lua_State *L) {
121   noit_lua_check_info_t *ci;
122   eventer_t e, *eptr;
123   const char *target;
124   unsigned short port;
125   int8_t family;
126   int rv;
127   union {
128     struct sockaddr_in sin4;
129     struct sockaddr_in6 sin6;
130   } a;
131
132   ci = get_ci(L);
133   assert(ci);
134
135   eptr = lua_touserdata(L, lua_upvalueindex(1));
136   if(eptr != lua_touserdata(L, 1))
137     luaL_error(L, "must be called as method");
138   e = *eptr;
139   target = lua_tostring(L, 2);
140   port = lua_tointeger(L, 3);
141
142   family = AF_INET;
143   rv = inet_pton(family, target, &a.sin4.sin_addr);
144   if(rv != 1) {
145     family = AF_INET6;
146     rv = inet_pton(family, target, &a.sin6.sin6_addr);
147     if(rv != 1) {
148       noitL(noit_stderr, "Cannot translate '%s' to IP\n", target);
149       memset(&a, 0, sizeof(a));
150       lua_pushinteger(L, -1);
151       lua_pushfstring(L, "Cannot translate '%s' to IP\n", target);
152       return 2;
153     }
154     else {
155       /* We've IPv6 */
156       a.sin6.sin6_family = AF_INET6;
157       a.sin6.sin6_port = htons(port);
158     }
159   }
160   else {
161     a.sin4.sin_family = family;
162     a.sin4.sin_port = htons(port);
163   }
164
165   rv = connect(e->fd, (struct sockaddr *)&a,
166                family==AF_INET ? sizeof(a.sin4) : sizeof(a.sin6));
167   if(rv == 0) {
168     lua_pushinteger(L, 0);
169     return 1;
170   }
171   if(rv == -1 && errno == EINPROGRESS) {
172     /* Need completion */
173     e->callback = noit_lua_socket_connect_complete;
174     e->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
175     eventer_add(e);
176     return noit_lua_yield(ci, 0);
177   }
178   lua_pushinteger(L, -1);
179   lua_pushstring(L, strerror(errno));
180   return 2;
181 }
182 static int
183 noit_lua_ssl_upgrade(eventer_t e, int mask, void *vcl,
184                      struct timeval *now) {
185   noit_lua_check_info_t *ci;
186   struct nl_slcl *cl = vcl;
187   int rv;
188  
189   rv = eventer_SSL_connect(e, &mask);
190   if(rv <= 0 && errno == EAGAIN) return mask | EVENTER_EXCEPTION;
191
192   ci = get_ci(cl->L);
193   assert(ci);
194   noit_lua_check_deregister_event(ci, e, 0);
195  
196   *(cl->eptr) = eventer_alloc();
197   memcpy(*cl->eptr, e, sizeof(*e));
198   noit_lua_check_register_event(ci, *cl->eptr);
199
200   /* Upgrade completed successfully */
201   lua_pushinteger(cl->L, (rv > 0) ? 0 : -1);
202   noit_lua_resume(ci, 1);
203   return 0;
204 }
205 static int
206 noit_lua_socket_connect_ssl(lua_State *L) {
207   const char *ca, *ciphers, *cert, *key;
208   eventer_ssl_ctx_t *sslctx;
209   noit_lua_check_info_t *ci;
210   eventer_t e, *eptr;
211   struct timeval now;
212
213   ci = get_ci(L);
214   assert(ci);
215
216   eptr = lua_touserdata(L, lua_upvalueindex(1));
217   if(eptr != lua_touserdata(L, 1))
218     luaL_error(L, "must be called as method");
219   e = *eptr;
220   cert = lua_tostring(L, 2);
221   key = lua_tostring(L, 3);
222   ca = lua_tostring(L, 4);
223   ciphers = lua_tostring(L, 5);
224
225   sslctx = eventer_ssl_ctx_new(SSL_CLIENT, cert, key, ca, ciphers);
226   if(!sslctx) {
227     lua_pushinteger(L, -1);
228     return 1;
229   }
230
231   eventer_ssl_ctx_set_verify(sslctx, eventer_ssl_verify_cert, NULL);
232   EVENTER_ATTACH_SSL(e, sslctx);
233   e->callback = noit_lua_ssl_upgrade;
234   gettimeofday(&now, NULL);
235   e->mask = e->callback(e, EVENTER_READ|EVENTER_WRITE, e->closure, &now);
236   if(e->mask & (EVENTER_READ|EVENTER_WRITE)) {
237     /* Need completion */
238     eventer_add(e);
239     return noit_lua_yield(ci, 0);
240   }
241   lua_pushinteger(L, 0);
242   return 1;
243 }
244
245 static int
246 noit_lua_socket_do_read(eventer_t e, int *mask, struct nl_slcl *cl,
247                         int *read_complete) {
248   char buff[4096];
249   int len;
250   *read_complete = 0;
251   while((len = e->opset->read(e->fd, buff, sizeof(buff), mask, e)) > 0) {
252     if(cl->read_goal) {
253       int remaining = cl->read_goal - cl->read_sofar;
254       /* copy up to the goal into the inbuff */
255       inbuff_addlstring(cl, buff, MIN(len, remaining));
256       cl->read_sofar += len;
257       if(cl->read_sofar >= cl->read_goal) { /* We're done */
258         lua_pushlstring(cl->L, cl->inbuff, cl->read_goal);
259         *read_complete = 1;
260         cl->read_sofar -= cl->read_goal;
261         cl->inbuff_len = 0;
262         if(cl->read_sofar > 0) {  /* We have to buffer this for next read */
263           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
264         }
265         break;
266       }
267     }
268     else if(cl->read_terminator) {
269       const char *cp;
270       int remaining = len;
271       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
272                     buff, len);
273       if(cp) remaining = cp - buff + strlen(cl->read_terminator);
274       inbuff_addlstring(cl, buff, MIN(len, remaining));
275       cl->read_sofar += len;
276       if(cp) {
277         lua_pushlstring(cl->L, cl->inbuff, cl->inbuff_len);
278         *read_complete = 1;
279        
280         cl->read_sofar = len - remaining;
281         cl->inbuff_len = 0;
282         if(cl->read_sofar > 0) { /* We have to buffer this for next read */
283           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
284         }
285         break;
286       }
287     }
288   }
289   return len;
290 }
291 static int
292 noit_lua_socket_read_complete(eventer_t e, int mask, void *vcl,
293                               struct timeval *now) {
294   noit_lua_check_info_t *ci;
295   struct nl_slcl *cl = vcl;
296   int len;
297   int args = 0;
298
299   ci = get_ci(cl->L);
300   assert(ci);
301
302   len = noit_lua_socket_do_read(e, &mask, cl, &args);
303   if(len >= 0) {
304     /* We broke out, cause we read enough... */
305   }
306   else if(len == -1 && errno == EAGAIN) {
307     return mask | EVENTER_EXCEPTION;
308   }
309   else {
310     lua_pushnil(cl->L);
311     args = 1;
312   }
313   eventer_remove_fd(e->fd);
314   noit_lua_check_deregister_event(ci, e, 0);
315   *(cl->eptr) = eventer_alloc();
316   memcpy(*cl->eptr, e, sizeof(*e));
317   noit_lua_check_register_event(ci, *cl->eptr);
318   noit_lua_resume(ci, args);
319   return 0;
320 }
321
322 static int
323 noit_lua_socket_read(lua_State *L) {
324   int args, mask, len;
325   struct nl_slcl *cl;
326   noit_lua_check_info_t *ci;
327   eventer_t e, *eptr;
328
329   ci = get_ci(L);
330   assert(ci);
331
332   eptr = lua_touserdata(L, lua_upvalueindex(1));
333   if(eptr != lua_touserdata(L, 1))
334     luaL_error(L, "must be called as method");
335   e = *eptr;
336   cl = e->closure;
337   cl->read_goal = 0;
338   cl->read_terminator = NULL;
339
340   if(lua_isnumber(L, 2)) {
341     cl->read_goal = lua_tointeger(L, 2);
342     if(cl->read_goal <= cl->read_sofar) {
343       int base;
344      i_know_better:
345       base = lua_gettop(L);
346       /* We have enough, we can service this right here */
347       lua_pushlstring(L, cl->inbuff, cl->read_goal);
348       cl->read_sofar -= cl->read_goal;
349       if(cl->read_sofar) {
350         memmove(cl->inbuff, cl->inbuff + cl->read_goal, cl->read_sofar);
351       }
352       cl->inbuff_len = cl->read_sofar;
353       return 1;
354     }
355   }
356   else {
357     cl->read_terminator = lua_tostring(L, 2);
358     if(cl->read_sofar) {
359       const char *cp;
360       /* Ugh... inernalism */
361       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
362                     cl->inbuff, cl->read_sofar);
363       if(cp) {
364         /* Here we matched... and we _know_ that someone actually wants:
365          * strlen(cl->read_terminator) + cp - cl->inbuff.buffer bytes...
366          * give it to them.
367          */
368         cl->read_goal = strlen(cl->read_terminator) + cp - cl->inbuff;
369         cl->read_terminator = NULL;
370         assert(cl->read_goal <= cl->read_sofar);
371         goto i_know_better;
372       }
373     }
374   }
375
376   len = noit_lua_socket_do_read(e, &mask, cl, &args);
377   if(args == 1) return 1; /* completed read, return result */
378   if(len == -1 && errno == EAGAIN) {
379     /* we need to drop into eventer */
380   }
381   else {
382     lua_pushnil(cl->L);
383     args = 1;
384     return args;
385   }
386
387   e->callback = noit_lua_socket_read_complete;
388   e->mask = mask | EVENTER_EXCEPTION;
389   eventer_add(e);
390   return noit_lua_yield(ci, 0);
391 }
392 static int
393 noit_lua_socket_write_complete(eventer_t e, int mask, void *vcl,
394                                struct timeval *now) {
395   noit_lua_check_info_t *ci;
396   struct nl_slcl *cl = vcl;
397   int rv;
398   int args = 0;
399
400   ci = get_ci(cl->L);
401   assert(ci);
402
403   if(mask & EVENTER_EXCEPTION) {
404     lua_pushinteger(cl->L, -1);
405     args = 1;
406     goto alldone;
407   }
408   while((rv = e->opset->write(e->fd,
409                               cl->outbuff + cl->write_sofar,
410                               MIN(cl->send_size, cl->write_goal),
411                               &mask, e)) > 0) {
412     cl->write_sofar += rv;
413     assert(cl->write_sofar <= cl->write_goal);
414     if(cl->write_sofar == cl->write_goal) break;
415   }
416   if(rv > 0) {
417     lua_pushinteger(cl->L, cl->write_goal);
418     args = 1;
419   }
420   else if(rv == -1 && errno == EAGAIN) {
421     return mask | EVENTER_EXCEPTION;
422   }
423   else {
424     lua_pushinteger(cl->L, -1);
425     args = 1;
426     if(rv == -1) {
427       lua_pushstring(cl->L, strerror(errno));
428       args++;
429     }
430   }
431
432  alldone:
433   eventer_remove_fd(e->fd);
434   noit_lua_check_deregister_event(ci, e, 0);
435   *(cl->eptr) = eventer_alloc();
436   memcpy(*cl->eptr, e, sizeof(*e));
437   noit_lua_check_register_event(ci, *cl->eptr);
438   noit_lua_resume(ci, args);
439   return 0;
440 }
441 static int
442 noit_lua_socket_write(lua_State *L) {
443   int rv, mask;
444   struct nl_slcl *cl;
445   noit_lua_check_info_t *ci;
446   eventer_t e, *eptr;
447
448   ci = get_ci(L);
449   assert(ci);
450
451   eptr = lua_touserdata(L, lua_upvalueindex(1));
452   if(eptr != lua_touserdata(L, 1))
453     luaL_error(L, "must be called as method");
454   e = *eptr;
455   cl = e->closure;
456   cl->write_sofar = 0;
457   cl->outbuff = lua_tolstring(L, 2, &cl->write_goal);
458
459   while((rv = e->opset->write(e->fd,
460                               cl->outbuff + cl->write_sofar,
461                               MIN(cl->send_size, cl->write_goal),
462                               &mask, e)) > 0) {
463     cl->write_sofar += rv;
464     assert(cl->write_sofar <= cl->write_goal);
465     if(cl->write_sofar == cl->write_goal) break;
466   }
467   if(rv > 0) {
468     lua_pushinteger(L, cl->write_goal);
469     return 1;
470   }
471   if(rv == -1 && errno == EAGAIN) {
472     e->callback = noit_lua_socket_write_complete;
473     e->mask = mask | EVENTER_EXCEPTION;
474     eventer_add(e);
475     return noit_lua_yield(ci, 0);
476   }
477   lua_pushinteger(L, -1);
478   return 1;
479 }
480 static int
481 noit_lua_socket_ssl_ctx(lua_State *L) {
482   eventer_t *eptr, e;
483   eventer_ssl_ctx_t **ssl_ctx_holder, *ssl_ctx;
484
485   eptr = lua_touserdata(L, lua_upvalueindex(1));
486   if(eptr != lua_touserdata(L, 1))
487     luaL_error(L, "must be called as method");
488   e = *eptr;
489
490   ssl_ctx = eventer_get_eventer_ssl_ctx(e);
491   if(!ssl_ctx) {
492     lua_pushnil(L);
493     return 1;
494   }
495
496   ssl_ctx_holder = (eventer_ssl_ctx_t **)lua_newuserdata(L, sizeof(ssl_ctx));
497   *ssl_ctx_holder = ssl_ctx;
498   luaL_getmetatable(L, "noit.eventer.ssl_ctx");
499   lua_setmetatable(L, -2);
500   return 1;
501 }
502 static int
503 noit_eventer_index_func(lua_State *L) {
504   int n;
505   const char *k;
506   eventer_t *udata, e;
507   n = lua_gettop(L); /* number of arguments */
508   assert(n == 2);
509   if(!luaL_checkudata(L, 1, "noit.eventer")) {
510     luaL_error(L, "metatable error, arg1 not a noit.eventer!");
511   }
512   udata = lua_touserdata(L, 1);
513   e = *udata;
514   if(!lua_isstring(L, 2)) {
515     luaL_error(L, "metatable error, arg2 not a string!");
516   }
517   k = lua_tostring(L, 2);
518   switch(*k) {
519     case 'c':
520      if(!strcmp(k, "connect")) {
521        lua_pushlightuserdata(L, udata);
522        lua_pushcclosure(L, noit_lua_socket_connect, 1);
523        return 1;
524      }
525      break;
526     case 'r':
527      if(!strcmp(k, "read")) {
528        lua_pushlightuserdata(L, udata);
529        lua_pushcclosure(L, noit_lua_socket_read, 1);
530        return 1;
531      }
532      break;
533     case 's':
534      if(!strcmp(k, "ssl_upgrade_socket")) {
535        lua_pushlightuserdata(L, udata);
536        lua_pushcclosure(L, noit_lua_socket_connect_ssl, 1);
537        return 1;
538      }
539      if(!strcmp(k, "ssl_ctx")) {
540        lua_pushlightuserdata(L, udata);
541        lua_pushcclosure(L, noit_lua_socket_ssl_ctx, 1);
542        return 1;
543      }
544      break;
545     case 'w':
546      if(!strcmp(k, "write")) {
547        lua_pushlightuserdata(L, udata);
548        lua_pushcclosure(L, noit_lua_socket_write, 1);
549        return 1;
550      }
551      break;
552     default:
553       break;
554   }
555   luaL_error(L, "noit.eventer no such element: %s", k);
556   return 0;
557 }
558
559 static eventer_t *
560 noit_lua_event(lua_State *L, eventer_t e) {
561   eventer_t *addr;
562   addr = (eventer_t *)lua_newuserdata(L, sizeof(e));
563   *addr = e;
564   luaL_getmetatable(L, "noit.eventer");
565   lua_setmetatable(L, -2);
566   return addr;
567 }
568
569 static int
570 noit_ssl_ctx_index_func(lua_State *L) {
571   int n;
572   const char *k;
573   eventer_ssl_ctx_t **udata, *ssl_ctx;
574   n = lua_gettop(L); /* number of arguments */
575   assert(n == 2);
576   if(!luaL_checkudata(L, 1, "noit.eventer.ssl_ctx")) {
577     luaL_error(L, "metatable error, arg1 not a noit.eventer.ssl_ctx!");
578   }
579   udata = lua_touserdata(L, 1);
580   ssl_ctx = *udata;
581   if(!lua_isstring(L, 2)) {
582     luaL_error(L, "metatable error, arg2 not a string!");
583   }
584   k = lua_tostring(L, 2);
585   switch(*k) {
586     case 'e':
587       if(!strcmp(k,"error")) {
588         lua_pushstring(L,eventer_ssl_get_peer_error(ssl_ctx));
589         return 1;
590       }
591       if(!strcmp(k,"end_time")) {
592         lua_pushinteger(L,eventer_ssl_get_peer_end_time(ssl_ctx));
593         return 1;
594       }
595       break;
596     case 'i':
597       if(!strcmp(k,"issuer")) {
598         lua_pushstring(L,eventer_ssl_get_peer_issuer(ssl_ctx));
599         return 1;
600       }
601       break;
602     case 's':
603       if(!strcmp(k,"subject")) {
604         lua_pushstring(L,eventer_ssl_get_peer_subject(ssl_ctx));
605         return 1;
606       }
607       if(!strcmp(k,"start_time")) {
608         lua_pushinteger(L,eventer_ssl_get_peer_start_time(ssl_ctx));
609         return 1;
610       }
611       break;
612     default:
613       break;
614   }
615   luaL_error(L, "noit.eventer.ssl_ctx no such element: %s", k);
616   return 0;
617 }
618
619 static int
620 nl_sleep_complete(eventer_t e, int mask, void *vcl, struct timeval *now) {
621   noit_lua_check_info_t *ci;
622   struct nl_slcl *cl = vcl;
623   struct timeval diff;
624   double p_int;
625
626   ci = get_ci(cl->L);
627   assert(ci);
628   noit_lua_check_deregister_event(ci, e, 0);
629
630   sub_timeval(*now, cl->start, &diff);
631   p_int = diff.tv_sec + diff.tv_usec / 1000000.0;
632   lua_pushnumber(cl->L, p_int);
633   free(cl);
634   noit_lua_resume(ci, 1);
635   return 0;
636 }
637
638 static int
639 nl_sleep(lua_State *L) {
640   noit_lua_check_info_t *ci;
641   struct nl_slcl *cl;
642   struct timeval diff;
643   eventer_t e;
644   double p_int;
645
646   ci = get_ci(L);
647   assert(ci);
648
649   p_int = lua_tonumber(L, 1);
650   cl = calloc(1, sizeof(*cl));
651   cl->free = nl_extended_free;
652   cl->L = L;
653   gettimeofday(&cl->start, NULL);
654
655   e = eventer_alloc();
656   e->mask = EVENTER_TIMER;
657   e->callback = nl_sleep_complete;
658   e->closure = cl;
659   memcpy(&e->whence, &cl->start, sizeof(cl->start));
660   diff.tv_sec = floor(p_int);
661   diff.tv_usec = (p_int - floor(p_int)) * 1000000;
662   add_timeval(e->whence, diff, &e->whence);
663   noit_lua_check_register_event(ci, e);
664   eventer_add(e);
665   return noit_lua_yield(ci, 0);
666 }
667
668 static int
669 nl_log(lua_State *L) {
670   int i, n;
671   const char *log_dest, *message;
672   noit_log_stream_t ls;
673
674   if(lua_gettop(L) < 2) luaL_error(L, "bad call to noit.log");
675
676   log_dest = lua_tostring(L, 1);
677   ls = noit_log_stream_find(log_dest);
678   if(!ls) {
679     noitL(noit_stderr, "Cannot find log stream: '%s'\n", log_dest);
680     return 0;
681   }
682
683   n = lua_gettop(L);
684   lua_pushstring(L, "string");
685   lua_gettable(L, LUA_GLOBALSINDEX);
686   lua_pushstring(L, "format");
687   lua_gettable(L, -1);
688   for(i=2;i<=n;i++)
689     lua_pushvalue(L, i);
690   lua_call(L, n-1, 1);
691   message = lua_tostring(L, -1);
692   noitL(ls, "%s", message);
693   lua_pop(L, 1); /* formatted string */
694   lua_pop(L, 1); /* "string" table */
695   return 0;
696 }
697 static int
698 nl_base64_decode(lua_State *L) {
699   size_t inlen, decoded_len;
700   const char *message;
701   unsigned char *decoded;
702
703   if(lua_gettop(L) != 1) luaL_error(L, "bad call to noit.decode");
704
705   message = lua_tolstring(L, 1, &inlen);
706   decoded = malloc(MAX(1,inlen));
707   if(!decoded) luaL_error(L, "out-of-memory");
708   decoded_len = noit_b64_decode(message, inlen, decoded, MAX(1,inlen));
709   lua_pushlstring(L, (char *)decoded, decoded_len);
710   return 1;
711 }
712 static int
713 nl_base64_encode(lua_State *L) {
714   size_t inlen, encoded_len;
715   const unsigned char *message;
716   char *encoded;
717
718   if(lua_gettop(L) != 1) luaL_error(L, "bad call to noit.encode");
719
720   message = (const unsigned char *)lua_tolstring(L, 1, &inlen);
721   encoded_len = (((inlen + 2) / 3) * 4) + 1;
722   encoded = malloc(encoded_len);
723   if(!encoded) luaL_error(L, "out-of-memory");
724   encoded_len = noit_b64_encode(message, inlen, encoded, encoded_len);
725   lua_pushlstring(L, (char *)encoded, encoded_len);
726   return 1;
727 }
728 static const char _hexchars[16] =
729   {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
730 static int
731 nl_md5_hex(lua_State *L) {
732   int i;
733   MD5_CTX ctx;
734   size_t inlen;
735   const char *in;
736   unsigned char md5[MD5_DIGEST_LENGTH];
737   char md5_hex[MD5_DIGEST_LENGTH * 2 + 1];
738
739   if(lua_gettop(L) != 1) luaL_error(L, "bad call to noit.md5_hex");
740   MD5_Init(&ctx);
741   in = lua_tolstring(L, 1, &inlen);
742   MD5_Update(&ctx, (const void *)in, (unsigned long)inlen);
743   MD5_Final(md5, &ctx);
744   for(i=0;i<MD5_DIGEST_LENGTH;i++) {
745     md5_hex[i*2] = _hexchars[(md5[i] >> 4) & 0xf];
746     md5_hex[i*2+1] = _hexchars[md5[i] & 0xf];
747   }
748   md5_hex[i*2] = '\0';
749   lua_pushstring(L, md5_hex);
750   return 1;
751 }
752 static int
753 nl_gettimeofday(lua_State *L) {
754   struct timeval now;
755   gettimeofday(&now, NULL);
756   lua_pushinteger(L, now.tv_sec);
757   lua_pushinteger(L, now.tv_usec);
758   return 2;
759 }
760 static int
761 nl_socket_tcp(lua_State *L, int family) {
762   struct nl_slcl *cl;
763   noit_lua_check_info_t *ci;
764   socklen_t optlen;
765   int fd;
766   eventer_t e;
767
768   fd = socket(family, SOCK_STREAM, 0);
769   if(fd < 0) {
770     lua_pushnil(L);
771     return 1;
772   }
773   if(eventer_set_fd_nonblocking(fd)) {
774     close(fd);
775     lua_pushnil(L);
776     return 1;
777   }
778
779   ci = get_ci(L);
780   assert(ci);
781
782   cl = calloc(1, sizeof(*cl));
783   cl->free = nl_extended_free;
784   cl->L = L;
785
786   optlen = sizeof(cl->send_size);
787   if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &cl->send_size, &optlen) != 0)
788     cl->send_size = 4096;
789
790   e = eventer_alloc();
791   e->fd = fd;
792   e->mask = EVENTER_EXCEPTION;
793   e->callback = NULL;
794   e->closure = cl;
795   cl->eptr = noit_lua_event(L, e);
796
797   noit_lua_check_register_event(ci, e);
798   return 1;
799 }
800 static int
801 nl_socket(lua_State *L) {
802   return nl_socket_tcp(L, AF_INET);
803 }
804 static int
805 nl_socket_ipv6(lua_State *L) {
806   return nl_socket_tcp(L, AF_INET6);
807 }
808
809 static int
810 nl_gunzip_deflate(lua_State *L) {
811   const char *input;
812   size_t inlen;
813   z_stream *stream;
814   Bytef *data = NULL;
815   uLong outlen = 0;
816   int limit = 1024*1024;
817   int err, n = lua_gettop(L);
818
819   if(n < 1 || n > 2) {
820     lua_pushnil(L);
821     return 1;
822   }
823
824   stream = lua_touserdata(L, lua_upvalueindex(1));
825
826   input = lua_tolstring(L, 1, &inlen);
827   if(!input) {
828     lua_pushnil(L);
829     return 1;
830   }
831   if(n == 2)
832     limit = lua_tointeger(L, 2);
833
834   stream->next_in = (Bytef *)input;
835   stream->avail_in = inlen;
836   while(1) {
837     err = inflate(stream, Z_FULL_FLUSH);
838     if(err == Z_OK || err == Z_STREAM_END) {
839       /* got some data */
840       int size_read = DEFLATE_CHUNK_SIZE - stream->avail_out;
841       uLong newoutlen = outlen + size_read;
842       if(newoutlen > limit) {
843         err = Z_MEM_ERROR;
844         break;
845       }
846       if(newoutlen > outlen) {
847         Bytef *newdata;
848         if(data) newdata = realloc(data, newoutlen);
849         else newdata = malloc(newoutlen);
850         if(!newdata) {
851           err = Z_MEM_ERROR;
852           break;
853         }
854         data = newdata;
855         memcpy(data + outlen, stream->next_out - size_read, size_read);
856         outlen += size_read;
857         stream->next_out -= size_read;
858         stream->avail_out += size_read;
859       }
860       if(err == Z_STREAM_END) {
861         /* Good to go */
862         break;
863       }
864     }
865     else break;
866     if(stream->avail_in == 0) break;
867   }
868   if(err == Z_OK || err == Z_STREAM_END) {
869     if(outlen > 0) lua_pushlstring(L, (char *)data, outlen);
870     else lua_pushstring(L, "");
871     if(data) free(data);
872     return 1;
873   }
874   lua_pushnil(L);
875   return 1;
876 }
877 static int
878 nl_gunzip(lua_State *L) {
879   z_stream *stream;
880  
881   stream = (z_stream *)lua_newuserdata(L, sizeof(*stream));
882   memset(stream, 0, sizeof(*stream));
883   luaL_getmetatable(L, "noit.gunzip");
884   lua_setmetatable(L, -2);
885
886   stream->next_in = NULL;
887   stream->avail_in = 0;
888   stream->next_out = malloc(DEFLATE_CHUNK_SIZE);
889   stream->avail_out = stream->next_out ? DEFLATE_CHUNK_SIZE : 0;
890   inflateInit2(stream, MAX_WBITS+32);
891
892   lua_pushcclosure(L, nl_gunzip_deflate, 1);
893   return 1;
894 }
895 static int
896 noit_lua_gunzip_gc(lua_State *L) {
897   z_stream *stream;
898   stream = (z_stream *)lua_touserdata(L,1);
899   if(stream->next_out) free(stream->next_out);
900   inflateEnd(stream);
901   return 0;
902 }
903
904 static int
905 noit_lua_pcre_match(lua_State *L) {
906   const char *subject;
907   pcre **re;
908   int i, cnt, ovector[30];
909   size_t inlen;
910
911   re = (pcre **)lua_touserdata(L, lua_upvalueindex(1));
912   subject = lua_tolstring(L,1,&inlen);
913   if(!subject) {
914     lua_pushboolean(L,0);
915     return 1;
916   }
917   cnt = pcre_exec(*re, NULL, subject, inlen, 0, 0,
918                   ovector, sizeof(ovector)/sizeof(*ovector));
919   if(cnt <= 0) {
920     lua_pushboolean(L,0);
921     return 1;
922   }
923   lua_pushboolean(L,1);
924   for(i = 0; i < cnt; i++) {
925     int start = ovector[i*2];
926     int end = ovector[i*2+1];
927     lua_pushlstring(L, subject+start, end-start);
928   }
929   return cnt+1;
930 }
931 static int
932 nl_pcre(lua_State *L) {
933   pcre *re, **holder;
934   const char *expr;
935   const char *errstr;
936   int erroff;
937
938   expr = lua_tostring(L,1);
939   re = pcre_compile(expr, 0, &errstr, &erroff, NULL);
940   if(!re) {
941     lua_pushnil(L);
942     lua_pushstring(L, errstr);
943     lua_pushinteger(L, erroff);
944     return 3;
945   }
946   holder = (pcre **)lua_newuserdata(L, sizeof(*holder));
947   *holder = re;
948   luaL_getmetatable(L, "noit.pcre");
949   lua_setmetatable(L, -2);
950   lua_pushcclosure(L, noit_lua_pcre_match, 1);
951   return 1;
952 }
953 static int
954 noit_lua_pcre_gc(lua_State *L) {
955   pcre **holder;
956   holder = (pcre **)lua_touserdata(L,1);
957   pcre_free(*holder);
958   return 0;
959 }
960
961 static int
962 nl_conf_get_string(lua_State *L) {
963   char *val;
964   const char *path = lua_tostring(L,1);
965   if(path &&
966      noit_conf_get_string(NULL, path, &val)) {
967     lua_pushstring(L,val);
968     free(val);
969   }
970   else lua_pushnil(L);
971   return 1;
972 }
973 static int
974 nl_conf_get_integer(lua_State *L) {
975   int val;
976   const char *path = lua_tostring(L,1);
977   if(path &&
978      noit_conf_get_int(NULL, path, &val)) {
979     lua_pushinteger(L,val);
980   }
981   else lua_pushnil(L);
982   return 1;
983 }
984 static int
985 nl_conf_get_boolean(lua_State *L) {
986   noit_boolean val;
987   const char *path = lua_tostring(L,1);
988   if(path &&
989      noit_conf_get_boolean(NULL, path, &val)) {
990     lua_pushboolean(L,val);
991   }
992   else lua_pushnil(L);
993   return 1;
994 }
995 static int
996 nl_conf_get_float(lua_State *L) {
997   float val;
998   const char *path = lua_tostring(L,1);
999   if(path &&
1000      noit_conf_get_float(NULL, path, &val)) {
1001     lua_pushnumber(L,val);
1002   }
1003   else lua_pushnil(L);
1004   return 1;
1005 }
1006 struct xpath_iter {
1007   xmlXPathContextPtr ctxt;
1008   xmlXPathObjectPtr pobj;
1009   int cnt;
1010   int idx;
1011 };
1012 static int
1013 noit_lua_xpath_iter(lua_State *L) {
1014   struct xpath_iter *xpi;
1015   xpi = lua_touserdata(L, lua_upvalueindex(1));
1016   if(xpi->pobj) {
1017     if(xpi->idx < xpi->cnt) {
1018       xmlNodePtr node, *nodeptr;
1019       node = xmlXPathNodeSetItem(xpi->pobj->nodesetval, xpi->idx);
1020       xpi->idx++;
1021       nodeptr = (xmlNodePtr *)lua_newuserdata(L, sizeof(node));
1022       *nodeptr = node;
1023       luaL_getmetatable(L, "noit.xmlnode");
1024       lua_setmetatable(L, -2);
1025       return 1;
1026     }
1027   }
1028   return 0;
1029 }
1030 static int
1031 noit_lua_xpath(lua_State *L) {
1032   int n;
1033   const char *xpathexpr;
1034   xmlDocPtr *docptr, doc;
1035   xmlNodePtr *nodeptr = NULL;
1036   xmlXPathContextPtr ctxt;
1037   struct xpath_iter *xpi;
1038
1039   n = lua_gettop(L);
1040   /* the first arg is implicitly self (it's a method) */
1041   docptr = lua_touserdata(L, lua_upvalueindex(1));
1042   if(docptr != lua_touserdata(L, 1))
1043     luaL_error(L, "must be called as method");
1044   if(n < 2 || n > 3) luaL_error(L, "expects 1 or 2 arguments, got %d", n);
1045   doc = *docptr;
1046   xpathexpr = lua_tostring(L, 2);
1047   if(!xpathexpr) luaL_error(L, "no xpath expression provided");
1048   ctxt = xmlXPathNewContext(doc);
1049   if(n == 3) {
1050     nodeptr = lua_touserdata(L, 3);
1051     if(nodeptr) ctxt->node = *nodeptr;
1052   }
1053   if(!ctxt) luaL_error(L, "invalid xpath");
1054
1055   xpi = (struct xpath_iter *)lua_newuserdata(L, sizeof(*xpi));
1056   xpi->ctxt = ctxt;
1057   xpi->pobj = xmlXPathEval((xmlChar *)xpathexpr, xpi->ctxt);
1058   if(!xpi->pobj || xpi->pobj->type != XPATH_NODESET)
1059     xpi->cnt = 0;
1060   else
1061     xpi->cnt = xmlXPathNodeSetGetLength(xpi->pobj->nodesetval);
1062   xpi->idx = 0;
1063   luaL_getmetatable(L, "noit.xpathiter");
1064   lua_setmetatable(L, -2);
1065   lua_pushcclosure(L, noit_lua_xpath_iter, 1);
1066   return 1;
1067 }
1068 static int
1069 noit_lua_xmlnode_name(lua_State *L) {
1070   xmlNodePtr *nodeptr;
1071   /* the first arg is implicitly self (it's a method) */
1072   nodeptr = lua_touserdata(L, lua_upvalueindex(1));
1073   if(nodeptr != lua_touserdata(L, 1))
1074     luaL_error(L, "must be called as method");
1075   if(lua_gettop(L) == 1) {
1076     xmlChar *v;
1077     v = (xmlChar *)(*nodeptr)->name;
1078     if(v) {
1079       lua_pushstring(L, (const char *)v);
1080     }
1081     else lua_pushnil(L);
1082     return 1;
1083   }
1084   luaL_error(L,"must be called with no arguments");
1085   return 0;
1086 }
1087 static int
1088 noit_lua_xmlnode_attr(lua_State *L) {
1089   xmlNodePtr *nodeptr;
1090   /* the first arg is implicitly self (it's a method) */
1091   nodeptr = lua_touserdata(L, lua_upvalueindex(1));
1092   if(nodeptr != lua_touserdata(L, 1))
1093     luaL_error(L, "must be called as method");
1094   if(lua_gettop(L) == 2 && lua_isstring(L,2)) {
1095     xmlChar *v;
1096     const char *attr = lua_tostring(L,2);
1097     v = xmlGetProp(*nodeptr, (xmlChar *)attr);
1098     if(v) {
1099       lua_pushstring(L, (const char *)v);
1100       xmlFree(v);
1101     }
1102     else lua_pushnil(L);
1103     return 1;
1104   }
1105   luaL_error(L,"must be called with one argument");
1106   return 0;
1107 }
1108 static int
1109 noit_lua_xmlnode_contents(lua_State *L) {
1110   xmlNodePtr *nodeptr;
1111   /* the first arg is implicitly self (it's a method) */
1112   nodeptr = lua_touserdata(L, lua_upvalueindex(1));
1113   if(nodeptr != lua_touserdata(L, 1))
1114     luaL_error(L, "must be called as method");
1115   if(lua_gettop(L) == 1) {
1116     xmlChar *v;
1117     v = xmlNodeGetContent(*nodeptr);
1118     if(v) {
1119       lua_pushstring(L, (const char *)v);
1120       xmlFree(v);
1121     }
1122     else lua_pushnil(L);
1123     return 1;
1124   }
1125   luaL_error(L,"must be called with no arguments");
1126   return 0;
1127 }
1128 static int
1129 noit_lua_xmlnode_next(lua_State *L) {
1130   xmlNodePtr *nodeptr;
1131   nodeptr = lua_touserdata(L, lua_upvalueindex(1));
1132   if(*nodeptr) {
1133     xmlNodePtr *newnodeptr;
1134     newnodeptr = (xmlNodePtr *)lua_newuserdata(L, sizeof(*nodeptr));
1135     *newnodeptr = *nodeptr;
1136     luaL_getmetatable(L, "noit.xmlnode");
1137     lua_setmetatable(L, -2);
1138     *nodeptr = (*nodeptr)->next;
1139     return 1;
1140   }
1141   return 0;
1142 }
1143 static int
1144 noit_lua_xmlnode_children(lua_State *L) {
1145   xmlNodePtr *nodeptr, node, cnode;
1146   /* the first arg is implicitly self (it's a method) */
1147   nodeptr = lua_touserdata(L, lua_upvalueindex(1));
1148   if(nodeptr != lua_touserdata(L, 1))
1149     luaL_error(L, "must be called as method");
1150   node = *nodeptr;
1151   cnode = node->children;
1152   nodeptr = lua_newuserdata(L, sizeof(cnode));
1153   *nodeptr = cnode;
1154   luaL_getmetatable(L, "noit.xmlnode");
1155   lua_setmetatable(L, -2);
1156   lua_pushcclosure(L, noit_lua_xmlnode_next, 1);
1157   return 1;
1158 }
1159 static int
1160 noit_lua_xml_docroot(lua_State *L) {
1161   int n;
1162   xmlDocPtr *docptr;
1163   xmlNodePtr *ptr;
1164   n = lua_gettop(L);
1165   /* the first arg is implicitly self (it's a method) */
1166   docptr = lua_touserdata(L, lua_upvalueindex(1));
1167   if(docptr != lua_touserdata(L, 1))
1168     luaL_error(L, "must be called as method");
1169   if(n != 1) luaL_error(L, "expects no arguments, got %d", n - 1);
1170   ptr = lua_newuserdata(L, sizeof(*ptr));
1171   *ptr = xmlDocGetRootElement(*docptr);
1172   luaL_getmetatable(L, "noit.xmlnode");
1173   lua_setmetatable(L, -2);
1174   return 1;
1175 }
1176 static int
1177 noit_lua_xpathiter_gc(lua_State *L) {
1178   struct xpath_iter *xpi;
1179   xpi = lua_touserdata(L, 1);
1180   xmlXPathFreeContext(xpi->ctxt);
1181   if(xpi->pobj) xmlXPathFreeObject(xpi->pobj);
1182   return 0;
1183 }
1184 static int
1185 noit_xmlnode_index_func(lua_State *L) {
1186   int n;
1187   const char *k;
1188   xmlNodePtr *udata, obj;
1189   n = lua_gettop(L); /* number of arguments */
1190   assert(n == 2);
1191   if(!luaL_checkudata(L, 1, "noit.xmlnode")) {
1192     luaL_error(L, "metatable error, arg1 not a noit.xmlnode!");
1193   }
1194   udata = lua_touserdata(L, 1);
1195   obj = *udata;
1196   if(!lua_isstring(L, 2)) {
1197     luaL_error(L, "metatable error, arg2 not a string!");
1198   }
1199   k = lua_tostring(L, 2);
1200   switch(*k) {
1201     case 'a':
1202       if(!strcmp(k,"attr") ||
1203          !strcmp(k,"attribute")) {
1204         lua_pushlightuserdata(L, udata);
1205         lua_pushcclosure(L, noit_lua_xmlnode_attr, 1);
1206         return 1;
1207       }
1208       break;
1209     case 'c':
1210       if(!strcmp(k,"children")) {
1211         lua_pushlightuserdata(L, udata);
1212         lua_pushcclosure(L, noit_lua_xmlnode_children, 1);
1213         return 1;
1214       }
1215       if(!strcmp(k,"contents")) {
1216         lua_pushlightuserdata(L, udata);
1217         lua_pushcclosure(L, noit_lua_xmlnode_contents, 1);
1218         return 1;
1219       }
1220       break;
1221     case 'n':
1222       if(!strcmp(k,"name")) {
1223         lua_pushlightuserdata(L, udata);
1224         lua_pushcclosure(L, noit_lua_xmlnode_name, 1);
1225         return 1;
1226       }
1227       break;
1228     default:
1229       break;
1230   }
1231   luaL_error(L, "noit.xmlnode no such element: %s", k);
1232   return 0;
1233 }
1234 static int
1235 nl_parsexml(lua_State *L) {
1236   xmlDocPtr *docptr, doc;
1237   const char *in;
1238   size_t inlen;
1239
1240   if(lua_gettop(L) != 1) luaL_error(L, "parsexml requires one argument");
1241
1242   in = lua_tolstring(L, 1, &inlen);
1243   doc = xmlParseMemory(in, inlen);
1244   if(!doc) {
1245     lua_pushnil(L);
1246     return 1;
1247   }
1248
1249   docptr = (xmlDocPtr *)lua_newuserdata(L, sizeof(doc));
1250   *docptr = doc;
1251   luaL_getmetatable(L, "noit.xmldoc");
1252   lua_setmetatable(L, -2);
1253   return 1;
1254 }
1255 static int
1256 noit_lua_xmldoc_gc(lua_State *L) {
1257   xmlDocPtr *holder;
1258   holder = (xmlDocPtr *)lua_touserdata(L,1);
1259   xmlFreeDoc(*holder);
1260   return 0;
1261 }
1262 static int
1263 noit_xmldoc_index_func(lua_State *L) {
1264   int n;
1265   const char *k;
1266   xmlDocPtr *udata, obj;
1267   n = lua_gettop(L); /* number of arguments */
1268   assert(n == 2);
1269   if(!luaL_checkudata(L, 1, "noit.xmldoc")) {
1270     luaL_error(L, "metatable error, arg1 not a noit.xmldoc!");
1271   }
1272   udata = lua_touserdata(L, 1);
1273   obj = *udata;
1274   if(!lua_isstring(L, 2)) {
1275     luaL_error(L, "metatable error, arg2 not a string!");
1276   }
1277   k = lua_tostring(L, 2);
1278   switch(*k) {
1279     case 'r':
1280      if(!strcmp(k, "root")) {
1281        lua_pushlightuserdata(L, udata);
1282        lua_pushcclosure(L, noit_lua_xml_docroot, 1);
1283        return 1;
1284      }
1285      break;
1286     case 'x':
1287      if(!strcmp(k, "xpath")) {
1288        lua_pushlightuserdata(L, udata);
1289        lua_pushcclosure(L, noit_lua_xpath, 1);
1290        return 1;
1291      }
1292      break;
1293     default:
1294      break;
1295   }
1296   luaL_error(L, "noit.xmldoc no such element: %s", k);
1297   return 0;
1298 }
1299 static const luaL_Reg noitlib[] = {
1300   { "sleep", nl_sleep },
1301   { "gettimeofday", nl_gettimeofday },
1302   { "socket", nl_socket },
1303   { "log", nl_log },
1304   { "base64_decode", nl_base64_decode },
1305   { "base64_encode", nl_base64_encode },
1306   { "md5_hex", nl_md5_hex },
1307   { "pcre", nl_pcre },
1308   { "socket_ipv6", nl_socket_ipv6 },
1309   { "gunzip", nl_gunzip },
1310   { "conf_get", nl_conf_get_string },
1311   { "conf_get_string", nl_conf_get_string },
1312   { "conf_get_integer", nl_conf_get_integer },
1313   { "conf_get_boolean", nl_conf_get_boolean },
1314   { "conf_get_number", nl_conf_get_float },
1315   { "parsexml", nl_parsexml },
1316   { NULL, NULL }
1317 };
1318
1319 int luaopen_noit(lua_State *L) {
1320   luaL_newmetatable(L, "noit.eventer");
1321   lua_pushcclosure(L, noit_eventer_index_func, 0);
1322   lua_setfield(L, -2, "__index");
1323
1324   luaL_newmetatable(L, "noit.eventer.ssl_ctx");
1325   lua_pushcclosure(L, noit_ssl_ctx_index_func, 0);
1326   lua_setfield(L, -2, "__index");
1327
1328   luaL_newmetatable(L, "noit.gunzip");
1329   lua_pushcfunction(L, noit_lua_gunzip_gc);
1330   lua_setfield(L, -2, "__gc");
1331
1332   luaL_newmetatable(L, "noit.pcre");
1333   lua_pushcfunction(L, noit_lua_pcre_gc);
1334   lua_setfield(L, -2, "__gc");
1335
1336   luaL_newmetatable(L, "noit.xmldoc");
1337   lua_pushcfunction(L, noit_lua_xmldoc_gc);
1338   lua_setfield(L, -2, "__gc");
1339   luaL_newmetatable(L, "noit.xmldoc");
1340   lua_pushcclosure(L, noit_xmldoc_index_func, 0);
1341   lua_setfield(L, -2, "__index");
1342
1343   luaL_newmetatable(L, "noit.xmlnode");
1344   lua_pushcclosure(L, noit_xmlnode_index_func, 0);
1345   lua_setfield(L, -2, "__index");
1346
1347   luaL_newmetatable(L, "noit.xpathiter");
1348   lua_pushcfunction(L, noit_lua_xpathiter_gc);
1349   lua_setfield(L, -2, "__gc");
1350
1351   luaL_register(L, "noit", noitlib);
1352   return 0;
1353 }
1354
1355 void noit_lua_init() {
1356   eventer_name_callback("lua/sleep", nl_sleep_complete);
1357   eventer_name_callback("lua/socket_read",
1358                         noit_lua_socket_read_complete);
1359   eventer_name_callback("lua/socket_write",
1360                         noit_lua_socket_write_complete);
1361   eventer_name_callback("lua/socket_connect",
1362                         noit_lua_socket_connect_complete);
1363   eventer_name_callback("lua/ssl_upgrade", noit_lua_ssl_upgrade);
1364 }
Note: See TracBrowser for help on using the browser.