root/src/modules/lua_noit.c

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

remove from the eventer, use strnstrn and always correlate a mask with the event (so we know it is fd-based), refs #28, refs #29

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