root/src/modules/lua_noit.c

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

It just shouldn't be this hard to write this correctly, refs #57

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