root/src/modules/lua_noit.c

Revision 49a6c7b61d5cac352916722a03d88dc0a53bffee, 16.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 9 years ago)

added SSL upgrade support into lua, need to expose context metadata. refs #174

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