root/src/modules/lua_noit.c

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

implement write and fix up read... luaL_Buffer is crap -- avoid it. show our accomplishment with a short, simple Varnish stat query check, refs #28

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