root/src/modules/lua_noit.c

Revision acf04f0e1c96bcc37c1fac182d8738bd180c8e06, 17.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

make the lua eventer_t wrap stuff act as methods

  • 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 "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 "utils/noit_str.h"
41 #include "eventer/eventer.h"
42 #include "lua_noit.h"
43
44 #include <assert.h>
45 #include <math.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #ifdef HAVE_SYS_FILIO_H
51 #include <sys/filio.h>
52 #endif
53
54 static void
55 nl_extended_free(void *vcl) {
56   struct nl_slcl *cl = vcl;
57   if(cl->inbuff) free(cl->inbuff);
58   free(cl);
59 }
60 static void
61 inbuff_addlstring(struct nl_slcl *cl, const char *b, int l) {
62   int newsize = 0;
63   char *newbuf;
64   if(cl->inbuff_len + l > cl->inbuff_allocd)
65     newsize = cl->inbuff_len + l;
66   if(newsize) {
67     newbuf = cl->inbuff_allocd ? realloc(cl->inbuff, newsize) : malloc(newsize);
68     assert(newbuf);
69     cl->inbuff = newbuf;
70     cl->inbuff_allocd = newsize;
71   }
72   memcpy(cl->inbuff + cl->inbuff_len, b, l);
73   cl->inbuff_len += l;
74 }
75
76 static int
77 noit_lua_socket_connect_complete(eventer_t e, int mask, void *vcl,
78                                  struct timeval *now) {
79   noit_lua_check_info_t *ci;
80   struct nl_slcl *cl = vcl;
81   int args = 0, aerrno;
82   socklen_t aerrno_len = sizeof(aerrno);
83
84   ci = get_ci(cl->L);
85   assert(ci);
86   noit_lua_check_deregister_event(ci, e, 0);
87
88   *(cl->eptr) = eventer_alloc();
89   memcpy(*cl->eptr, e, sizeof(*e));
90   noit_lua_check_register_event(ci, *cl->eptr);
91
92   if(getsockopt(e->fd,SOL_SOCKET,SO_ERROR, &aerrno, &aerrno_len) == 0)
93     if(aerrno != 0) goto connerr;
94
95   if(!(mask & EVENTER_EXCEPTION) &&
96      mask & EVENTER_WRITE) {
97     /* Connect completed successfully */
98     lua_pushinteger(cl->L, 0);
99     args = 1;
100   }
101   else {
102     aerrno = errno;
103    connerr:
104     lua_pushinteger(cl->L, -1);
105     lua_pushstring(cl->L, strerror(aerrno));
106     args = 2;
107   }
108   noit_lua_resume(ci, args);
109   return 0;
110 }
111 static int
112 noit_lua_socket_connect(lua_State *L) {
113   noit_lua_check_info_t *ci;
114   eventer_t e, *eptr;
115   const char *target;
116   unsigned short port;
117   int8_t family;
118   int rv;
119   union {
120     struct sockaddr_in sin4;
121     struct sockaddr_in6 sin6;
122   } a;
123
124   ci = get_ci(L);
125   assert(ci);
126
127   eptr = lua_touserdata(L, lua_upvalueindex(1));
128   if(eptr != lua_touserdata(L, 1))
129     luaL_error(L, "must be called as method");
130   e = *eptr;
131   target = lua_tostring(L, 2);
132   port = lua_tointeger(L, 3);
133
134   family = AF_INET;
135   rv = inet_pton(family, target, &a.sin4.sin_addr);
136   if(rv != 1) {
137     family = AF_INET6;
138     rv = inet_pton(family, target, &a.sin6.sin6_addr);
139     if(rv != 1) {
140       noitL(noit_stderr, "Cannot translate '%s' to IP\n", target);
141       memset(&a, 0, sizeof(a));
142       lua_pushinteger(L, -1);
143       lua_pushfstring(L, "Cannot translate '%s' to IP\n", target);
144       return 2;
145     }
146     else {
147       /* We've IPv6 */
148       a.sin6.sin6_family = AF_INET6;
149       a.sin6.sin6_port = htons(port);
150     }
151   }
152   else {
153     a.sin4.sin_family = family;
154     a.sin4.sin_port = htons(port);
155   }
156
157   rv = connect(e->fd, (struct sockaddr *)&a,
158                family==AF_INET ? sizeof(a.sin4) : sizeof(a.sin6));
159   if(rv == 0) {
160     lua_pushinteger(L, 0);
161     return 1;
162   }
163   if(rv == -1 && errno == EINPROGRESS) {
164     /* Need completion */
165     e->callback = noit_lua_socket_connect_complete;
166     e->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
167     eventer_add(e);
168     return noit_lua_yield(ci, 0);
169   }
170   lua_pushinteger(L, -1);
171   lua_pushstring(L, strerror(errno));
172   return 2;
173 }
174 static int
175 noit_lua_ssl_upgrade(eventer_t e, int mask, void *vcl,
176                      struct timeval *now) {
177   noit_lua_check_info_t *ci;
178   struct nl_slcl *cl = vcl;
179   int rv;
180  
181   rv = eventer_SSL_connect(e, &mask);
182   if(rv <= 0 && errno == EAGAIN) return mask | EVENTER_EXCEPTION;
183
184   ci = get_ci(cl->L);
185   assert(ci);
186   noit_lua_check_deregister_event(ci, e, 0);
187  
188   *(cl->eptr) = eventer_alloc();
189   memcpy(*cl->eptr, e, sizeof(*e));
190   noit_lua_check_register_event(ci, *cl->eptr);
191
192   /* Upgrade completed successfully */
193   lua_pushinteger(cl->L, (rv > 0) ? 0 : -1);
194   noit_lua_resume(ci, 1);
195   return 0;
196 }
197 static int
198 noit_lua_socket_connect_ssl(lua_State *L) {
199   const char *ca, *ciphers, *cert, *key;
200   eventer_ssl_ctx_t *sslctx;
201   noit_lua_check_info_t *ci;
202   eventer_t e, *eptr;
203   struct timeval now;
204
205   ci = get_ci(L);
206   assert(ci);
207
208   eptr = lua_touserdata(L, lua_upvalueindex(1));
209   if(eptr != lua_touserdata(L, 1))
210     luaL_error(L, "must be called as method");
211   e = *eptr;
212   ca = lua_tostring(L, 2);
213   ciphers = lua_tostring(L, 3);
214   cert = lua_tostring(L, 4);
215   key = lua_tostring(L, 5);
216
217   sslctx = eventer_ssl_ctx_new(SSL_CLIENT, cert, key, ca, ciphers);
218   if(!sslctx) {
219     lua_pushinteger(L, -1);
220     return 1;
221   }
222
223   eventer_ssl_ctx_set_verify(sslctx, eventer_ssl_verify_cert, NULL);
224   EVENTER_ATTACH_SSL(e, sslctx);
225   e->callback = noit_lua_ssl_upgrade;
226   gettimeofday(&now, NULL);
227   e->mask = e->callback(e, EVENTER_READ|EVENTER_WRITE, e->closure, &now);
228   if(e->mask & (EVENTER_READ|EVENTER_WRITE)) {
229     /* Need completion */
230     eventer_add(e);
231     return noit_lua_yield(ci, 0);
232   }
233   lua_pushinteger(L, 0);
234   return 1;
235 }
236
237 static int
238 noit_lua_socket_read_complete(eventer_t e, int mask, void *vcl,
239                               struct timeval *now) {
240   char buff[4096];
241   noit_lua_check_info_t *ci;
242   struct nl_slcl *cl = vcl;
243   int len;
244   int args = 0;
245
246   ci = get_ci(cl->L);
247   assert(ci);
248
249   if(mask & EVENTER_EXCEPTION) {
250     lua_pushnil(cl->L);
251     args = 1;
252     goto alldone;
253   }
254
255   while((len = e->opset->read(e->fd, buff, sizeof(buff), &mask, e)) > 0) {
256     if(cl->read_goal) {
257       int remaining = cl->read_goal - cl->read_sofar;
258       /* copy up to the goal into the inbuff */
259       inbuff_addlstring(cl, buff, MIN(len, remaining));
260       cl->read_sofar += len;
261       if(cl->read_sofar >= cl->read_goal) { /* We're done */
262         lua_pushlstring(cl->L, cl->inbuff, cl->read_goal);
263         args = 1;
264         cl->read_sofar -= cl->read_goal;
265         if(cl->read_sofar > 0) {  /* We have to buffer this for next read */
266           cl->inbuff_len = 0;
267           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
268         }
269         break;
270       }
271     }
272     else if(cl->read_terminator) {
273       const char *cp;
274       int remaining = len;
275       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
276                     buff, len);
277       if(cp) remaining = cp - buff + strlen(cl->read_terminator);
278       inbuff_addlstring(cl, buff, MIN(len, remaining));
279       cl->read_sofar += len;
280       if(cp) {
281         lua_pushlstring(cl->L, cl->inbuff, cl->inbuff_len);
282         args = 1;
283        
284         cl->read_sofar = len - remaining;
285         cl->inbuff_len = 0;
286         if(cl->read_sofar > 0) { /* We have to buffer this for next read */
287           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
288         }
289         break;
290       }
291     }
292   }
293   if(len >= 0) {
294     /* We broke out, cause we read enough... */
295   }
296   else if(len == -1 && errno == EAGAIN) {
297     return mask | EVENTER_EXCEPTION;
298   }
299   else {
300     lua_pushnil(cl->L);
301     args = 1;
302   }
303  alldone:
304   eventer_remove_fd(e->fd);
305   noit_lua_check_deregister_event(ci, e, 0);
306   *(cl->eptr) = eventer_alloc();
307   memcpy(*cl->eptr, e, sizeof(*e));
308   noit_lua_check_register_event(ci, *cl->eptr);
309   noit_lua_resume(ci, args);
310   return 0;
311 }
312
313 static int
314 noit_lua_socket_read(lua_State *L) {
315   struct nl_slcl *cl;
316   noit_lua_check_info_t *ci;
317   eventer_t e, *eptr;
318
319   ci = get_ci(L);
320   assert(ci);
321
322   eptr = lua_touserdata(L, lua_upvalueindex(1));
323   if(eptr != lua_touserdata(L, 1))
324     luaL_error(L, "must be called as method");
325   e = *eptr;
326   cl = e->closure;
327   cl->read_goal = 0;
328   cl->read_terminator = NULL;
329
330   if(lua_isnumber(L, 2)) {
331     cl->read_goal = lua_tointeger(L, 2);
332     if(cl->read_goal <= cl->read_sofar) {
333       int base;
334      i_know_better:
335       base = lua_gettop(L);
336       /* We have enough, we can service this right here */
337       lua_pushlstring(L, cl->inbuff, cl->read_goal);
338       cl->read_sofar -= cl->read_goal;
339       if(cl->read_sofar) {
340         memmove(cl->inbuff, cl->inbuff + cl->read_goal, cl->read_sofar);
341       }
342       cl->inbuff_len = cl->read_sofar;
343       return 1;
344     }
345   }
346   else {
347     cl->read_terminator = lua_tostring(L, 2);
348     if(cl->read_sofar) {
349       const char *cp;
350       /* Ugh... inernalism */
351       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
352                     cl->inbuff, cl->read_sofar);
353       if(cp) {
354         /* Here we matched... and we _know_ that someone actually wants:
355          * strlen(cl->read_terminator) + cp - cl->inbuff.buffer bytes...
356          * give it to them.
357          */
358         cl->read_goal = strlen(cl->read_terminator) + cp - cl->inbuff;
359         cl->read_terminator = NULL;
360         assert(cl->read_goal <= cl->read_sofar);
361         goto i_know_better;
362       }
363     }
364   }
365
366   e->callback = noit_lua_socket_read_complete;
367   e->mask = EVENTER_READ | EVENTER_EXCEPTION;
368   eventer_add(e);
369   return noit_lua_yield(ci, 0);
370 }
371 static int
372 noit_lua_socket_write_complete(eventer_t e, int mask, void *vcl,
373                                struct timeval *now) {
374   noit_lua_check_info_t *ci;
375   struct nl_slcl *cl = vcl;
376   int rv;
377   int args = 0;
378
379   ci = get_ci(cl->L);
380   assert(ci);
381
382   if(mask & EVENTER_EXCEPTION) {
383     lua_pushinteger(cl->L, -1);
384     args = 1;
385     goto alldone;
386   }
387   while((rv = e->opset->write(e->fd,
388                               cl->outbuff + cl->write_sofar,
389                               MIN(cl->send_size, cl->write_goal),
390                               &mask, e)) > 0) {
391     cl->write_sofar += rv;
392     assert(cl->write_sofar <= cl->write_goal);
393     if(cl->write_sofar == cl->write_goal) break;
394   }
395   if(rv > 0) {
396     lua_pushinteger(cl->L, cl->write_goal);
397     args = 1;
398   }
399   else if(rv == -1 && errno == EAGAIN) {
400     return mask | EVENTER_EXCEPTION;
401   }
402   else {
403     lua_pushinteger(cl->L, -1);
404     args = 1;
405     if(rv == -1) {
406       lua_pushstring(cl->L, strerror(errno));
407       args++;
408     }
409   }
410
411  alldone:
412   eventer_remove_fd(e->fd);
413   noit_lua_check_deregister_event(ci, e, 0);
414   *(cl->eptr) = eventer_alloc();
415   memcpy(*cl->eptr, e, sizeof(*e));
416   noit_lua_check_register_event(ci, *cl->eptr);
417   noit_lua_resume(ci, args);
418   return 0;
419 }
420 static int
421 noit_lua_socket_write(lua_State *L) {
422   int rv, mask;
423   struct nl_slcl *cl;
424   noit_lua_check_info_t *ci;
425   eventer_t e, *eptr;
426
427   ci = get_ci(L);
428   assert(ci);
429
430   eptr = lua_touserdata(L, lua_upvalueindex(1));
431   if(eptr != lua_touserdata(L, 1))
432     luaL_error(L, "must be called as method");
433   e = *eptr;
434   cl = e->closure;
435   cl->write_sofar = 0;
436   cl->outbuff = lua_tolstring(L, 2, &cl->write_goal);
437
438   while((rv = e->opset->write(e->fd,
439                               cl->outbuff + cl->write_sofar,
440                               MIN(cl->send_size, cl->write_goal),
441                               &mask, e)) > 0) {
442     cl->write_sofar += rv;
443     assert(cl->write_sofar <= cl->write_goal);
444     if(cl->write_sofar == cl->write_goal) break;
445   }
446   if(rv > 0) {
447     lua_pushinteger(L, cl->write_goal);
448     return 1;
449   }
450   if(rv == -1 && errno == EAGAIN) {
451     e->callback = noit_lua_socket_write_complete;
452     e->mask = mask | EVENTER_EXCEPTION;
453     eventer_add(e);
454     return noit_lua_yield(ci, 0);
455   }
456   lua_pushinteger(L, -1);
457   return 1;
458 }
459 static int
460 noit_eventer_index_func(lua_State *L) {
461   int n;
462   const char *k;
463   eventer_t *udata, e;
464   n = lua_gettop(L);    /* number of arguments */
465   assert(n == 2);
466   if(!luaL_checkudata(L, 1, "eventer_t")) {
467     luaL_error(L, "metatable error, arg1 not a eventer_t!");
468   }
469   udata = lua_touserdata(L, 1);
470   e = *udata;
471   if(!lua_isstring(L, 2)) {
472     luaL_error(L, "metatable error, arg2 not a string!");
473   }
474   k = lua_tostring(L, 2);
475   switch(*k) {
476     case 'c':
477      if(!strcmp(k, "connect")) {
478        lua_pushlightuserdata(L, udata);
479        lua_pushcclosure(L, noit_lua_socket_connect, 1);
480        return 1;
481      }
482      break;
483     case 'r':
484      if(!strcmp(k, "read")) {
485        lua_pushlightuserdata(L, udata);
486        lua_pushcclosure(L, noit_lua_socket_read, 1);
487        return 1;
488      }
489      break;
490     case 's':
491      if(!strcmp(k, "ssl_upgrade_socket")) {
492        lua_pushlightuserdata(L, udata);
493        lua_pushcclosure(L, noit_lua_socket_connect_ssl, 1);
494        return 1;
495      }
496      break;
497     case 'w':
498      if(!strcmp(k, "write")) {
499        lua_pushlightuserdata(L, udata);
500        lua_pushcclosure(L, noit_lua_socket_write, 1);
501        return 1;
502      }
503      break;
504     default:
505       break;
506   }
507   luaL_error(L, "eventer_t no such element: %s", k);
508   return 0;
509 }
510
511 static eventer_t *
512 noit_lua_event(lua_State *L, eventer_t e) {
513   eventer_t *addr;
514   addr = (eventer_t *)lua_newuserdata(L, sizeof(e));
515   *addr = e;
516   if(luaL_newmetatable(L, "eventer_t") == 1) {
517     lua_pushcclosure(L, noit_eventer_index_func, 0);
518     lua_setfield(L, -2, "__index");
519   }
520   lua_setmetatable(L, -2);
521   return addr;
522 }
523
524 static int
525 nl_sleep_complete(eventer_t e, int mask, void *vcl, struct timeval *now) {
526   noit_lua_check_info_t *ci;
527   struct nl_slcl *cl = vcl;
528   struct timeval diff;
529   double p_int;
530
531   ci = get_ci(cl->L);
532   assert(ci);
533   noit_lua_check_deregister_event(ci, e, 0);
534
535   sub_timeval(*now, cl->start, &diff);
536   p_int = diff.tv_sec + diff.tv_usec / 1000000.0;
537   lua_pushnumber(cl->L, p_int);
538   free(cl);
539   noit_lua_resume(ci, 1);
540   return 0;
541 }
542
543 static int
544 nl_sleep(lua_State *L) {
545   noit_lua_check_info_t *ci;
546   struct nl_slcl *cl;
547   struct timeval diff;
548   eventer_t e;
549   double p_int;
550
551   ci = get_ci(L);
552   assert(ci);
553
554   p_int = lua_tonumber(L, 1);
555   cl = calloc(1, sizeof(*cl));
556   cl->free = nl_extended_free;
557   cl->L = L;
558   gettimeofday(&cl->start, NULL);
559
560   e = eventer_alloc();
561   e->mask = EVENTER_TIMER;
562   e->callback = nl_sleep_complete;
563   e->closure = cl;
564   memcpy(&e->whence, &cl->start, sizeof(cl->start));
565   diff.tv_sec = floor(p_int);
566   diff.tv_usec = (p_int - floor(p_int)) * 1000000;
567   add_timeval(e->whence, diff, &e->whence);
568   noit_lua_check_register_event(ci, e);
569   eventer_add(e);
570   return noit_lua_yield(ci, 0);
571 }
572
573 static int
574 nl_log(lua_State *L) {
575   int i, n;
576   const char *log_dest, *message;
577   noit_log_stream_t ls;
578
579   log_dest = lua_tostring(L, 1);
580   ls = noit_log_stream_find(log_dest);
581   if(!ls) {
582     noitL(noit_stderr, "Cannot find log stream: '%s'\n", log_dest);
583     return 0;
584   }
585
586   n = lua_gettop(L);
587   lua_pushstring(L, "string");
588   lua_gettable(L, LUA_GLOBALSINDEX);
589   lua_pushstring(L, "format");
590   lua_gettable(L, -1);
591   for(i=2;i<=n;i++)
592     lua_pushvalue(L, i);
593   lua_call(L, n-1, 1);
594   message = lua_tostring(L, -1);
595   noitL(ls, "%s", message);
596   lua_pop(L, 1); /* formatted string */
597   lua_pop(L, 1); /* "string" table */
598   return 0;
599 }
600 static int
601 nl_gettimeofday(lua_State *L) {
602   struct timeval now;
603   gettimeofday(&now, NULL);
604   lua_pushinteger(L, now.tv_sec);
605   lua_pushinteger(L, now.tv_usec);
606   return 2;
607 }
608 static int
609 nl_socket_tcp(lua_State *L, int family) {
610   struct nl_slcl *cl;
611   noit_lua_check_info_t *ci;
612   socklen_t optlen;
613   int fd;
614   eventer_t e;
615
616   fd = socket(family, SOCK_STREAM, 0);
617   if(fd < 0) {
618     lua_pushnil(L);
619     return 1;
620   }
621   if(eventer_set_fd_nonblocking(fd)) {
622     close(fd);
623     lua_pushnil(L);
624     return 1;
625   }
626
627   ci = get_ci(L);
628   assert(ci);
629
630   cl = calloc(1, sizeof(*cl));
631   cl->free = nl_extended_free;
632   cl->L = L;
633
634   optlen = sizeof(cl->send_size);
635   if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &cl->send_size, &optlen) != 0)
636     cl->send_size = 4096;
637
638   e = eventer_alloc();
639   e->fd = fd;
640   e->mask = EVENTER_EXCEPTION;
641   e->callback = NULL;
642   e->closure = cl;
643   cl->eptr = noit_lua_event(L, e);
644
645   noit_lua_check_register_event(ci, e);
646   return 1;
647 }
648 static int
649 nl_socket(lua_State *L) {
650   return nl_socket_tcp(L, AF_INET);
651 }
652 static int
653 nl_socket_ipv6(lua_State *L) {
654   return nl_socket_tcp(L, AF_INET6);
655 }
656
657 static const luaL_Reg noitlib[] = {
658   { "sleep", nl_sleep },
659   { "gettimeofday", nl_gettimeofday },
660   { "socket", nl_socket },
661   { "log", nl_log },
662   { "socket_ipv6", nl_socket_ipv6 },
663   { NULL, NULL }
664 };
665
666 int luaopen_noit(lua_State *L) {
667   luaL_register(L, "noit", noitlib);
668   return 0;
669 }
Note: See TracBrowser for help on using the browser.