root/src/modules/lua_noit.c

Revision c4546c715aee6db46888e7ab0bb87fd2ce5357c6, 12.8 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

I sure hope this doesn't break other platforms too badly. Solaris support sans the eventer... untested, of course. refs #32.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include "noit_conf.h"
9 #include "noit_module.h"
10 #include "noit_check.h"
11 #include "noit_check_tools.h"
12 #include "utils/noit_log.h"
13 #include "utils/noit_str.h"
14 #include "eventer/eventer.h"
15 #include "lua_noit.h"
16
17 #include <assert.h>
18 #include <math.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #ifdef HAVE_SYS_FILIO_H
24 #include <sys/filio.h>
25 #endif
26
27 struct nl_slcl {
28   int send_size;
29   struct timeval start;
30   char *inbuff;
31   int   inbuff_allocd;
32   int   inbuff_len;
33   size_t read_sofar;
34   size_t read_goal;
35   const char *read_terminator;
36   const char *outbuff;
37   size_t write_sofar;
38   size_t write_goal;
39   eventer_t *eptr;
40   lua_State *L;
41 };
42
43 static void
44 inbuff_addlstring(struct nl_slcl *cl, const char *b, int l) {
45   int newsize = 0;
46   char *newbuf;
47   if(cl->inbuff_len + l > cl->inbuff_allocd)
48     newsize = cl->inbuff_len + l;
49   if(newsize) {
50     newbuf = cl->inbuff_allocd ? realloc(cl->inbuff, newsize) : malloc(newsize);
51     assert(newbuf);
52     cl->inbuff = newbuf;
53     cl->inbuff_allocd = newsize;
54   }
55   memcpy(cl->inbuff + cl->inbuff_len, b, l);
56   cl->inbuff_len += l;
57 }
58
59 static int
60 noit_lua_socket_connect_complete(eventer_t e, int mask, void *vcl,
61                                  struct timeval *now) {
62   noit_lua_check_info_t *ci;
63   struct nl_slcl *cl = vcl;
64   int args = 0;
65
66   ci = get_ci(cl->L);
67   assert(ci);
68   noit_lua_check_deregister_event(ci, e, 0);
69
70   *(cl->eptr) = eventer_alloc();
71   memcpy(*cl->eptr, e, sizeof(*e));
72   noit_lua_check_register_event(ci, *cl->eptr);
73
74   if(!(mask & EVENTER_EXCEPTION) &&
75      mask & EVENTER_WRITE) {
76     /* Connect completed successfully */
77     lua_pushinteger(cl->L, 0);
78     args = 1;
79   }
80   else {
81     lua_pushinteger(cl->L, -1);
82     lua_pushstring(cl->L, strerror(errno));
83     args = 2;
84   }
85   noit_lua_resume(ci, args);
86   return 0;
87 }
88 static int
89 noit_lua_socket_connect(lua_State *L) {
90   noit_lua_check_info_t *ci;
91   eventer_t e, *eptr;
92   const char *target;
93   unsigned short port;
94   int8_t family;
95   int rv;
96   union {
97     struct sockaddr_in sin4;
98     struct sockaddr_in6 sin6;
99   } a;
100
101   ci = get_ci(L);
102   assert(ci);
103
104   eptr = lua_touserdata(L, lua_upvalueindex(1));
105   e = *eptr;
106   target = lua_tostring(L, 1);
107   port = lua_tointeger(L, 2);
108
109   family = AF_INET;
110   rv = inet_pton(family, target, &a.sin4.sin_addr);
111   if(rv != 1) {
112     family = AF_INET6;
113     rv = inet_pton(family, target, &a.sin6.sin6_addr);
114     if(rv != 1) {
115       noitL(noit_stderr, "Cannot translate '%s' to IP\n", target);
116       memset(&a, 0, sizeof(a));
117       lua_pushinteger(L, -1);
118       lua_pushfstring(L, "Cannot translate '%s' to IP\n", target);
119       return 2;
120     }
121     else {
122       /* We've IPv6 */
123       a.sin6.sin6_family = AF_INET6;
124       a.sin6.sin6_port = htons(port);
125     }
126   }
127   else {
128     a.sin4.sin_family = family;
129     a.sin4.sin_port = htons(port);
130   }
131
132   rv = connect(e->fd, (struct sockaddr *)&a,
133                family==AF_INET ? sizeof(a.sin4) : sizeof(a.sin6));
134   if(rv == 0) {
135     lua_pushinteger(L, 0);
136     return 1;
137   }
138   if(rv == -1 && errno == EINPROGRESS) {
139     /* Need completion */
140     e->callback = noit_lua_socket_connect_complete;
141     e->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
142     eventer_add(e);
143     return noit_lua_yield(ci, 0);
144   }
145   lua_pushinteger(L, -1);
146   lua_pushstring(L, strerror(errno));
147   return 2;
148 }
149
150 static int
151 noit_lua_socket_read_complete(eventer_t e, int mask, void *vcl,
152                               struct timeval *now) {
153   char buff[4096];
154   noit_lua_check_info_t *ci;
155   struct nl_slcl *cl = vcl;
156   int len;
157   int args = 0;
158
159   ci = get_ci(cl->L);
160   assert(ci);
161
162   if(mask & EVENTER_EXCEPTION) {
163     lua_pushnil(cl->L);
164     args = 1;
165     goto alldone;
166   }
167
168   while((len = e->opset->read(e->fd, buff, sizeof(buff), &mask, e)) > 0) {
169     if(cl->read_goal) {
170       int remaining = cl->read_goal - cl->read_sofar;
171       /* copy up to the goal into the inbuff */
172       inbuff_addlstring(cl, buff, MIN(len, remaining));
173       cl->read_sofar += len;
174       if(cl->read_sofar >= cl->read_goal) { /* We're done */
175         lua_pushlstring(cl->L, cl->inbuff, cl->read_goal);
176         args = 1;
177         cl->read_sofar -= cl->read_goal;
178         if(cl->read_sofar > 0) {  /* We have to buffer this for next read */
179           cl->inbuff_len = 0;
180           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
181         }
182         break;
183       }
184     }
185     else if(cl->read_terminator) {
186       const char *cp;
187       int remaining = len;
188       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
189                     buff, len);
190       if(cp) remaining = cp - buff + strlen(cl->read_terminator);
191       inbuff_addlstring(cl, buff, MIN(len, remaining));
192       cl->read_sofar += len;
193       if(cp) {
194         lua_pushlstring(cl->L, cl->inbuff, cl->inbuff_len);
195         args = 1;
196         cl->read_sofar = len - remaining;
197         if(cl->read_sofar > 0) { /* We have to buffer this for next read */
198           cl->inbuff_len = 0;
199           inbuff_addlstring(cl, buff + remaining, cl->read_sofar);
200         }
201         break;
202       }
203     }
204   }
205   if(len >= 0) {
206     /* We broke out, cause we read enough... */
207   }
208   else if(len == -1 && errno == EAGAIN) {
209     return mask | EVENTER_EXCEPTION;
210   }
211   else {
212     lua_pushnil(cl->L);
213     args = 1;
214   }
215  alldone:
216   eventer_remove_fd(e->fd);
217   noit_lua_check_deregister_event(ci, e, 0);
218   *(cl->eptr) = eventer_alloc();
219   memcpy(*cl->eptr, e, sizeof(*e));
220   noit_lua_check_register_event(ci, *cl->eptr);
221   noit_lua_resume(ci, args);
222   return 0;
223 }
224
225 static int
226 noit_lua_socket_read(lua_State *L) {
227   struct nl_slcl *cl;
228   noit_lua_check_info_t *ci;
229   eventer_t e, *eptr;
230
231   ci = get_ci(L);
232   assert(ci);
233
234   eptr = lua_touserdata(L, lua_upvalueindex(1));
235   e = *eptr;
236   cl = e->closure;
237   cl->read_goal = 0;
238   cl->read_terminator = NULL;
239
240   if(lua_isnumber(L, 1)) {
241     cl->read_goal = lua_tointeger(L, 1);
242     if(cl->read_goal <= cl->read_sofar) {
243       int base;
244      i_know_better:
245       base = lua_gettop(L);
246       /* We have enough, we can service this right here */
247       lua_pushlstring(L, cl->inbuff, cl->read_goal);
248       cl->read_sofar -= cl->read_goal;
249       if(cl->read_sofar) {
250         memmove(cl->inbuff, cl->inbuff + cl->read_goal, cl->read_sofar);
251         cl->inbuff_len = cl->read_sofar;
252       }
253       return 1;
254     }
255   }
256   else {
257     cl->read_terminator = lua_tostring(L, 1);
258     if(cl->read_sofar) {
259       const char *cp;
260       /* Ugh... inernalism */
261       cp = strnstrn(cl->read_terminator, strlen(cl->read_terminator),
262                     cl->inbuff, cl->read_sofar);
263       if(cp) {
264         /* Here we matched... and we _know_ that someone actually wants:
265          * strlen(cl->read_terminator) + cp - cl->inbuff.buffer bytes...
266          * give it to them.
267          */
268         cl->read_goal = strlen(cl->read_terminator) + cp - cl->inbuff;
269         cl->read_terminator = NULL;
270         assert(cl->read_goal <= cl->read_sofar);
271         goto i_know_better;
272       }
273     }
274   }
275
276   e->callback = noit_lua_socket_read_complete;
277   e->mask = EVENTER_READ | EVENTER_EXCEPTION;
278   eventer_add(e);
279   return noit_lua_yield(ci, 0);
280 }
281 static int
282 noit_lua_socket_write_complete(eventer_t e, int mask, void *vcl,
283                                struct timeval *now) {
284   noit_lua_check_info_t *ci;
285   struct nl_slcl *cl = vcl;
286   int rv;
287   int args = 0;
288
289   ci = get_ci(cl->L);
290   assert(ci);
291
292   if(mask & EVENTER_EXCEPTION) {
293     lua_pushinteger(cl->L, -1);
294     args = 1;
295     goto alldone;
296   }
297   while((rv = e->opset->write(e->fd,
298                               cl->outbuff + cl->write_sofar,
299                               MIN(cl->send_size, cl->write_goal),
300                               &mask, e)) > 0) {
301     cl->write_sofar += rv;
302     assert(cl->write_sofar <= cl->write_goal);
303     if(cl->write_sofar == cl->write_goal) break;
304   }
305   if(rv > 0) {
306     lua_pushinteger(cl->L, cl->write_goal);
307     args = 1;
308   }
309   else if(rv == -1 && errno == EAGAIN) {
310     return mask | EVENTER_EXCEPTION;
311   }
312   else {
313     lua_pushinteger(cl->L, -1);
314     args = 1;
315     if(rv == -1) {
316       lua_pushstring(cl->L, strerror(errno));
317       args++;
318     }
319   }
320
321  alldone:
322   eventer_remove_fd(e->fd);
323   noit_lua_check_deregister_event(ci, e, 0);
324   *(cl->eptr) = eventer_alloc();
325   memcpy(*cl->eptr, e, sizeof(*e));
326   noit_lua_check_register_event(ci, *cl->eptr);
327   noit_lua_resume(ci, args);
328   return 0;
329 }
330 static int
331 noit_lua_socket_write(lua_State *L) {
332   int rv, mask;
333   struct nl_slcl *cl;
334   noit_lua_check_info_t *ci;
335   eventer_t e, *eptr;
336
337   ci = get_ci(L);
338   assert(ci);
339
340   eptr = lua_touserdata(L, lua_upvalueindex(1));
341   e = *eptr;
342   cl = e->closure;
343   cl->write_sofar = 0;
344   cl->outbuff = lua_tolstring(L, 1, &cl->write_goal);
345
346   while((rv = e->opset->write(e->fd,
347                               cl->outbuff + cl->write_sofar,
348                               MIN(cl->send_size, cl->write_goal),
349                               &mask, e)) > 0) {
350     cl->write_sofar += rv;
351     assert(cl->write_sofar <= cl->write_goal);
352     if(cl->write_sofar == cl->write_goal) break;
353   }
354   if(rv > 0) {
355     lua_pushinteger(L, cl->write_goal);
356     return 1;
357   }
358   if(rv == -1 && errno == EAGAIN) {
359     e->callback = noit_lua_socket_write_complete;
360     e->mask = mask | EVENTER_EXCEPTION;
361     eventer_add(e);
362     return noit_lua_yield(ci, 0);
363   }
364   lua_pushinteger(L, -1);
365   return 1;
366 }
367 static int
368 noit_eventer_index_func(lua_State *L) {
369   int n;
370   const char *k;
371   eventer_t *udata, e;
372   n = lua_gettop(L);    /* number of arguments */
373   assert(n == 2);
374   if(!luaL_checkudata(L, 1, "eventer_t")) {
375     luaL_error(L, "metatable error, arg1 not a eventer_t!");
376   }
377   udata = lua_touserdata(L, 1);
378   e = *udata;
379   if(!lua_isstring(L, 2)) {
380     luaL_error(L, "metatable error, arg2 not a string!");
381   }
382   k = lua_tostring(L, 2);
383   switch(*k) {
384     case 'c':
385      if(!strcmp(k, "connect")) {
386        lua_pushlightuserdata(L, udata);
387        lua_pushcclosure(L, noit_lua_socket_connect, 1);
388        return 1;
389      }
390      break;
391     case 'r':
392      if(!strcmp(k, "read")) {
393        lua_pushlightuserdata(L, udata);
394        lua_pushcclosure(L, noit_lua_socket_read, 1);
395        return 1;
396      }
397      break;
398     case 'w':
399      if(!strcmp(k, "write")) {
400        lua_pushlightuserdata(L, udata);
401        lua_pushcclosure(L, noit_lua_socket_write, 1);
402        return 1;
403      }
404      break;
405     default:
406       break;
407   }
408   luaL_error(L, "eventer_t no such element: %s", k);
409   return 0;
410 }
411
412 static eventer_t *
413 noit_lua_event(lua_State *L, eventer_t e) {
414   eventer_t *addr;
415   addr = (eventer_t *)lua_newuserdata(L, sizeof(e));
416   *addr = e;
417   if(luaL_newmetatable(L, "eventer_t") == 1) {
418     lua_pushcclosure(L, noit_eventer_index_func, 0);
419     lua_setfield(L, -2, "__index");
420   }
421   lua_setmetatable(L, -2);
422   return addr;
423 }
424
425 static int
426 nl_sleep_complete(eventer_t e, int mask, void *vcl, struct timeval *now) {
427   noit_lua_check_info_t *ci;
428   struct nl_slcl *cl = vcl;
429   struct timeval diff;
430   double p_int;
431
432   ci = get_ci(cl->L);
433   assert(ci);
434   noit_lua_check_deregister_event(ci, e, 0);
435
436   sub_timeval(*now, cl->start, &diff);
437   p_int = diff.tv_sec + diff.tv_usec / 1000000.0;
438   lua_pushnumber(cl->L, p_int);
439   free(cl);
440   noit_lua_resume(ci, 1);
441   return 0;
442 }
443
444 static int
445 nl_sleep(lua_State *L) {
446   noit_lua_check_info_t *ci;
447   struct nl_slcl *cl;
448   struct timeval diff;
449   eventer_t e;
450   double p_int;
451
452   ci = get_ci(L);
453   assert(ci);
454
455   p_int = lua_tonumber(L, 1);
456   cl = calloc(1, sizeof(*cl));
457   cl->L = L;
458   gettimeofday(&cl->start, NULL);
459
460   e = eventer_alloc();
461   e->mask = EVENTER_TIMER;
462   e->callback = nl_sleep_complete;
463   e->closure = cl;
464   memcpy(&e->whence, &cl->start, sizeof(cl->start));
465   diff.tv_sec = floor(p_int);
466   diff.tv_usec = (p_int - floor(p_int)) * 1000000;
467   add_timeval(e->whence, diff, &e->whence);
468   noit_lua_check_register_event(ci, e);
469   eventer_add(e);
470   return noit_lua_yield(ci, 0);
471 }
472
473 static int
474 nl_socket_tcp(lua_State *L, int family) {
475   struct nl_slcl *cl;
476   noit_lua_check_info_t *ci;
477   socklen_t on, optlen;
478   int fd;
479   eventer_t e;
480
481   fd = socket(family, SOCK_STREAM, 0);
482   if(fd < 0) {
483     lua_pushnil(L);
484     return 1;
485   }
486   on = 1;
487   if(ioctl(fd, FIONBIO, &on)) {
488     close(fd);
489     lua_pushnil(L);
490     return 1;
491   }
492
493   ci = get_ci(L);
494   assert(ci);
495
496   cl = calloc(1, sizeof(*cl));
497   cl->L = L;
498
499   optlen = sizeof(cl->send_size);
500   if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &cl->send_size, &optlen) != 0)
501     cl->send_size = 4096;
502
503   e = eventer_alloc();
504   e->fd = fd;
505   e->mask = EVENTER_EXCEPTION;
506   e->callback = NULL;
507   e->closure = cl;
508   cl->eptr = noit_lua_event(L, e);
509
510   noit_lua_check_register_event(ci, e);
511   return 1;
512 }
513 static int
514 nl_socket(lua_State *L) {
515   return nl_socket_tcp(L, AF_INET);
516 }
517 static int
518 nl_socket_ipv6(lua_State *L) {
519   return nl_socket_tcp(L, AF_INET6);
520 }
521
522 static const luaL_Reg noitlib[] = {
523   { "sleep", nl_sleep },
524   { "socket", nl_socket },
525   { "socket_ipv6", nl_socket_ipv6 },
526   { NULL, NULL }
527 };
528
529 int luaopen_noit(lua_State *L) {
530   luaL_register(L, "noit", noitlib);
531   return 0;
532 }
Note: See TracBrowser for help on using the browser.