moonbridge

view moonbridge_io.c @ 205:5601a486e68a

Support asynchronous I/O with stdin/stdout/stderr of executed child processes
author jbe
date Sun Jun 21 20:10:21 2015 +0200 (2015-06-21)
parents d338068fad0d
children 56efa825bfc7
line source
2 #if defined(__linux__)
3 #define _GNU_SOURCE
4 #endif
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <netinet/in.h>
16 #include <netinet/tcp.h>
17 #include <sys/select.h>
18 #include <time.h>
19 #include <netdb.h>
20 #include <arpa/inet.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
24 #include <lua.h>
25 #include <lauxlib.h>
26 #include <lualib.h>
28 #include <assert.h>
30 #define MOONBR_IO_MAXSTRERRORLEN 80
31 #define MOONBR_IO_READBUFLEN 4096
32 #define MOONBR_IO_WRITEBUFLEN 4096
34 #define MOONBR_IO_LISTEN_BACKLOG 1024
36 #define moonbr_io_errmsg() \
37 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
38 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
40 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
41 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
42 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
43 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
44 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
46 typedef struct {
47 int fd;
48 int issock;
49 sa_family_t addrfam;
50 int finished;
51 int closed;
52 int nonblocking;
53 int nopush;
54 int readerr;
55 int readbufin;
56 int readbufout;
57 int writeerr;
58 size_t writeleft;
59 size_t flushedleft;
60 #if LUA_VERSION_NUM >= 503
61 lua_Integer writeqin;
62 lua_Integer writeqout;
63 #else
64 int writeqin;
65 int writeqout;
66 #endif
67 size_t writeqoff;
68 int writebufin;
69 int writebufout;
70 char readbuf[MOONBR_IO_READBUFLEN];
71 char writebuf[MOONBR_IO_WRITEBUFLEN];
72 } moonbr_io_handle_t;
74 typedef struct {
75 int fd;
76 sa_family_t addrfam;
77 int nonblocking;
78 } moonbr_io_listener_t;
80 typedef struct {
81 pid_t pid;
82 int uninitialized_in;
83 int uninitialized_out;
84 int uninitialized_err;
85 } moonbr_io_child_t;
87 static int moonbr_io_yield(lua_State *L) {
88 return lua_yield(L, lua_gettop(L));
89 }
91 #if LUA_VERSION_NUM >= 503
92 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
93 #else
94 static int moonbr_io_cont_returnall(lua_State *L) {
95 #endif
96 return lua_gettop(L);
97 }
99 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
100 static int yieldfunc(lua_State *L) { \
101 int args; \
102 lua_pushcfunction(L, callfunc); \
103 lua_insert(L, 1); \
104 args = lua_gettop(L); \
105 lua_pushcfunction(L, moonbr_io_yield); \
106 lua_insert(L, 3); \
107 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
108 return lua_gettop(L); \
109 }
111 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
112 int flags;
113 if (handle->nonblocking == nonblocking) return;
114 flags = fcntl(handle->fd, F_GETFL, 0);
115 if (flags == -1) {
116 moonbr_io_errmsg();
117 close(handle->fd);
118 handle->fd = -1;
119 handle->closed = 1;
120 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
121 }
122 if (nonblocking) flags |= O_NONBLOCK;
123 else flags &= ~O_NONBLOCK;
124 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
125 moonbr_io_errmsg();
126 close(handle->fd);
127 handle->fd = -1;
128 handle->closed = 1;
129 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
130 }
131 handle->nonblocking = nonblocking;
132 }
134 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
135 struct linger lingerval = { 0, };
136 if (!handle->issock) return;
137 if (timeout >= 0) {
138 lingerval.l_onoff = 1;
139 lingerval.l_linger = timeout;
140 }
141 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
142 moonbr_io_errmsg();
143 close(handle->fd);
144 handle->fd = -1;
145 handle->closed = 1;
146 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
147 }
148 }
150 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
151 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
152 if (
153 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
154 handle->nopush == nopush
155 ) return;
156 #if defined(TCP_NOPUSH)
157 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
158 #elif defined(TCP_CORK)
159 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
160 #endif
161 moonbr_io_errmsg();
162 close(handle->fd);
163 handle->fd = -1;
164 handle->closed = 1;
165 #if defined(TCP_NOPUSH)
166 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
167 #elif defined(TCP_CORK)
168 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
169 #endif
170 }
171 handle->nopush = nopush;
172 #else
173 #warning Neither TCP_NOPUSH nor TCP_CORK is available
174 #endif
175 }
177 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
178 moonbr_io_handle_t *handle;
179 lua_Integer maxread;
180 const char *terminatorstr;
181 size_t terminatorlen;
182 char terminator;
183 luaL_Buffer luabuf;
184 size_t luabufcnt = 0;
185 int remaining;
186 char *terminatorpos;
187 ssize_t bytesread;
188 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
189 maxread = luaL_optinteger(L, 2, -1);
190 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
191 if (terminatorlen) {
192 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
193 terminator = terminatorstr[0];
194 }
195 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
196 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
197 if (handle->readerr) {
198 lua_pushnil(L);
199 lua_pushliteral(L, "Previous read error");
200 return 2;
201 }
202 if (handle->fd < 0) {
203 /* fake EOF to simulate shutdown */
204 if (!drain) lua_pushliteral(L, "");
205 else lua_pushinteger(L, 0);
206 lua_pushliteral(L, "eof");
207 return 2;
208 }
209 handle->readerr = 1;
210 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
211 if (!drain) luaL_buffinit(L, &luabuf);
212 while (1) {
213 remaining = -1;
214 terminatorpos = NULL;
215 if (
216 maxread >= 0 &&
217 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
218 ) {
219 remaining = (size_t)maxread - luabufcnt;
220 if (terminatorlen) {
221 terminatorpos = memchr(
222 handle->readbuf + handle->readbufout,
223 terminator,
224 remaining
225 );
226 }
227 } else if (terminatorlen) {
228 terminatorpos = memchr(
229 handle->readbuf + handle->readbufout,
230 terminator,
231 handle->readbufin - handle->readbufout
232 );
233 }
234 if (terminatorpos) remaining = 1 + (
235 terminatorpos - (handle->readbuf + handle->readbufout)
236 );
237 if (remaining >= 0) {
238 if (!drain) {
239 luaL_addlstring(
240 &luabuf,
241 handle->readbuf + handle->readbufout,
242 remaining
243 );
244 luaL_pushresult(&luabuf);
245 } else {
246 lua_pushinteger(L, luabufcnt + remaining);
247 }
248 if (terminatorpos) lua_pushliteral(L, "term");
249 else lua_pushliteral(L, "maxlen");
250 handle->readbufout += remaining;
251 if (handle->readbufout == handle->readbufin) {
252 handle->readbufin = 0;
253 handle->readbufout = 0;
254 }
255 handle->readerr = 0;
256 return 2;
257 }
258 if (!drain) luaL_addlstring(
259 &luabuf,
260 handle->readbuf + handle->readbufout,
261 handle->readbufin - handle->readbufout
262 );
263 luabufcnt += handle->readbufin - handle->readbufout;
264 handle->readbufout = 0;
265 do {
266 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
267 } while (bytesread < 0 && (errno == EINTR));
268 if (
269 bytesread == 0 || (
270 nonblocking &&
271 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
272 )
273 ) {
274 handle->readbufin = 0;
275 if (!drain) luaL_pushresult(&luabuf);
276 else lua_pushinteger(L, luabufcnt);
277 if (bytesread == 0) lua_pushliteral(L, "eof");
278 else lua_pushliteral(L, "block");
279 handle->readerr = 0;
280 return 2;
281 }
282 if (bytesread < 0) {
283 moonbr_io_errmsg();
284 lua_pushnil(L);
285 lua_pushstring(L, errmsg);
286 return 2;
287 }
288 handle->readbufin = bytesread;
289 }
290 }
292 static int moonbr_io_read(lua_State *L) {
293 return moonbr_io_read_impl(L, 0, 0);
294 }
296 static int moonbr_io_read_nb(lua_State *L) {
297 return moonbr_io_read_impl(L, 1, 0);
298 }
300 static int moonbr_io_drain(lua_State *L) {
301 return moonbr_io_read_impl(L, 0, 1);
302 }
304 static int moonbr_io_drain_nb(lua_State *L) {
305 return moonbr_io_read_impl(L, 1, 1);
306 }
308 #if LUA_VERSION_NUM >= 503
309 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
310 #else
311 static int moonbr_io_read_cont(lua_State *L) {
312 #endif
313 lua_Integer remaining;
314 size_t len;
315 #if !(LUA_VERSION_NUM >= 503)
316 int ctx = 0;
317 lua_getctx(L, &ctx);
318 #endif
319 remaining = lua_tointeger(L, 3);
320 while (1) {
321 lua_pushcfunction(L, moonbr_io_read_nb);
322 lua_pushvalue(L, 1);
323 lua_pushvalue(L, 3);
324 lua_pushvalue(L, 4);
325 lua_call(L, 3, 2);
326 if (lua_isnil(L, -2)) return 2;
327 lua_insert(L, -2);
328 len = lua_rawlen(L, -1);
329 if (ctx == 0) {
330 lua_replace(L, 5);
331 ctx = 1;
332 } else if (ctx == 1) {
333 lua_pushvalue(L, 5);
334 lua_newtable(L);
335 lua_replace(L, 5);
336 lua_rawseti(L, 5, 2);
337 lua_rawseti(L, 5, 1);
338 ctx = 2;
339 } else {
340 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
341 }
342 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
343 lua_pop(L, 1);
344 if (remaining >= 0 && len) {
345 remaining -= len;
346 lua_pushinteger(L, remaining);
347 lua_replace(L, 3);
348 }
349 lua_pushvalue(L, 2);
350 lua_callk(L, 0, 0, ctx, moonbr_io_read_cont);
351 }
352 if (ctx == 1) {
353 lua_pushvalue(L, 5);
354 } else {
355 luaL_Buffer buf;
356 lua_Integer i, chunkcount;
357 chunkcount = lua_rawlen(L, 5);
358 luaL_buffinit(L, &buf);
359 for (i=1; i<=chunkcount && i>0; i++) {
360 lua_rawgeti(L, 5, i);
361 luaL_addvalue(&buf);
362 }
363 luaL_pushresult(&buf);
364 }
365 lua_pushvalue(L, -2);
366 return 2;
367 }
369 static int moonbr_io_read_call(lua_State *L) {
370 lua_settop(L, 4);
371 lua_pushnil(L);
372 #if LUA_VERSION_NUM >= 503
373 return moonbr_io_read_cont(L, 0, 0);
374 #else
375 return moonbr_io_read_cont(L);
376 #endif
377 }
379 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
381 #if LUA_VERSION_NUM >= 503
382 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
383 #else
384 static int moonbr_io_drain_cont(lua_State *L) {
385 #endif
386 lua_Integer remaining, len;
387 size_t totallen = 0;
388 #if !(LUA_VERSION_NUM >= 503)
389 int ctx = 0;
390 lua_getctx(L, &ctx);
391 #endif
392 remaining = lua_tointeger(L, 3);
393 while (1) {
394 lua_pushcfunction(L, moonbr_io_drain_nb);
395 lua_pushvalue(L, 1);
396 lua_pushvalue(L, 3);
397 lua_pushvalue(L, 4);
398 lua_call(L, 3, 2);
399 if (lua_isnil(L, -2)) return 2;
400 lua_insert(L, -2);
401 len = lua_tointeger(L, -1);
402 lua_pop(L, 1);
403 totallen += len;
404 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
405 lua_pop(L, 1);
406 if (remaining >= 0 && len) {
407 remaining -= len;
408 lua_pushinteger(L, remaining);
409 lua_replace(L, 3);
410 }
411 lua_pushvalue(L, 2);
412 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
413 }
414 lua_pushinteger(L, totallen);
415 lua_pushvalue(L, -2);
416 return 2;
417 }
419 static int moonbr_io_drain_call(lua_State *L) {
420 #if LUA_VERSION_NUM >= 503
421 return moonbr_io_drain_cont(L, 0, 0);
422 #else
423 return moonbr_io_drain_cont(L);
424 #endif
425 }
427 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
429 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
430 moonbr_io_handle_t *handle;
431 int i, top;
432 const char *str;
433 size_t strlen;
434 ssize_t written;
435 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
436 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
437 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
438 if (handle->writeerr) {
439 lua_pushnil(L);
440 lua_pushliteral(L, "Previous write error");
441 return 2;
442 }
443 handle->writeerr = 1;
444 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
445 top = lua_gettop(L);
446 lua_getuservalue(L, 1);
447 lua_getfield(L, -1, "writequeue");
448 for (i=2; i<=top; i++) {
449 luaL_checklstring(L, i, &strlen);
450 lua_pushvalue(L, i);
451 lua_rawseti(L, -2, handle->writeqin++);
452 handle->writeleft += strlen;
453 }
454 if (flush) handle->flushedleft = handle->writeleft;
455 while (handle->writeqout != handle->writeqin) {
456 lua_rawgeti(L, -1, handle->writeqout);
457 str = lua_tolstring(L, -1, &strlen);
458 while (handle->writeqoff < strlen) {
459 if (
460 strlen - handle->writeqoff <
461 MOONBR_IO_WRITEBUFLEN - handle->writebufin
462 ) {
463 memcpy(
464 handle->writebuf + handle->writebufin,
465 str + handle->writeqoff,
466 strlen - handle->writeqoff
467 );
468 handle->writebufin += strlen - handle->writeqoff;
469 break;
470 } else {
471 memcpy(
472 handle->writebuf + handle->writebufin,
473 str + handle->writeqoff,
474 MOONBR_IO_WRITEBUFLEN - handle->writebufin
475 );
476 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
477 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
478 moonbr_io_handle_set_nopush(L, handle, 1);
479 written = write(
480 handle->fd,
481 handle->writebuf + handle->writebufout,
482 MOONBR_IO_WRITEBUFLEN - handle->writebufout
483 );
484 if (written < 0) {
485 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
486 goto moonbr_io_write_impl_block;
487 } else if (errno != EINTR) {
488 moonbr_io_errmsg();
489 lua_pushnil(L);
490 lua_pushstring(L, errmsg);
491 return 2;
492 }
493 } else {
494 handle->writebufout += written;
495 handle->writeleft -= written;
496 if (handle->flushedleft) {
497 if (written >= handle->flushedleft) {
498 handle->flushedleft = 0;
499 moonbr_io_handle_set_nopush(L, handle, 0);
500 } else {
501 handle->flushedleft -= written;
502 }
503 }
504 }
505 }
506 handle->writebufin = 0;
507 handle->writebufout = 0;
508 }
509 }
510 handle->writeqoff = 0;
511 lua_pop(L, 1);
512 lua_pushnil(L);
513 lua_rawseti(L, -2, handle->writeqout++);
514 }
515 while (handle->flushedleft) {
516 moonbr_io_handle_set_nopush(L, handle, 1);
517 written = write(
518 handle->fd,
519 handle->writebuf + handle->writebufout,
520 handle->writebufin - handle->writebufout
521 );
522 if (written < 0) {
523 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
524 goto moonbr_io_write_impl_block;
525 } else if (errno != EINTR) {
526 moonbr_io_errmsg();
527 lua_pushnil(L);
528 lua_pushstring(L, errmsg);
529 return 2;
530 }
531 } else {
532 handle->writebufout += written;
533 handle->writeleft -= written;
534 if (handle->flushedleft) {
535 if (written >= handle->flushedleft) {
536 handle->flushedleft = 0;
537 moonbr_io_handle_set_nopush(L, handle, 0);
538 } else {
539 handle->flushedleft -= written;
540 }
541 }
542 }
543 }
544 if (handle->writebufout == handle->writebufin) {
545 handle->writebufin = 0;
546 handle->writebufout = 0;
547 }
548 if (nonblocking) lua_pushinteger(L, 0);
549 else lua_pushvalue(L, 1);
550 handle->writeerr = 0;
551 return 1;
552 moonbr_io_write_impl_block:
553 lua_pushinteger(L, handle->writeleft);
554 handle->writeerr = 0;
555 return 1;
556 }
558 static int moonbr_io_write(lua_State *L) {
559 return moonbr_io_write_impl(L, 0, 0);
560 }
562 static int moonbr_io_write_nb(lua_State *L) {
563 return moonbr_io_write_impl(L, 1, 0);
564 }
566 static int moonbr_io_flush(lua_State *L) {
567 return moonbr_io_write_impl(L, 0, 1);
568 }
570 static int moonbr_io_flush_nb(lua_State *L) {
571 return moonbr_io_write_impl(L, 1, 1);
572 }
574 #if LUA_VERSION_NUM >= 503
575 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
576 #else
577 static int moonbr_io_write_cont(lua_State *L) {
578 #endif
579 while (1) {
580 lua_pushcfunction(L, moonbr_io_write_nb);
581 lua_pushvalue(L, 1);
582 lua_call(L, 1, 2);
583 if (lua_isnil(L, -2)) return 2;
584 if (!lua_tointeger(L, -2)) {
585 lua_pushvalue(L, 1);
586 return 1;
587 }
588 lua_pop(L, 2);
589 lua_pushvalue(L, 2);
590 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
591 }
592 }
594 static int moonbr_io_write_call(lua_State *L) {
595 lua_pushcfunction(L, moonbr_io_write_nb);
596 lua_insert(L, 3);
597 lua_pushvalue(L, 1);
598 lua_insert(L, 4);
599 lua_call(L, lua_gettop(L) - 3, 2);
600 if (lua_isnil(L, -2)) return 2;
601 if (!lua_tointeger(L, -2)) {
602 lua_pushvalue(L, 1);
603 return 1;
604 }
605 #if LUA_VERSION_NUM >= 503
606 return moonbr_io_write_cont(L, 0, 0);
607 #else
608 return moonbr_io_write_cont(L);
609 #endif
610 }
612 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
614 static int moonbr_io_flush_call(lua_State *L) {
615 lua_pushcfunction(L, moonbr_io_flush_nb);
616 lua_insert(L, 3);
617 lua_pushvalue(L, 1);
618 lua_insert(L, 4);
619 lua_call(L, lua_gettop(L) - 3, 2);
620 if (lua_isnil(L, -2)) return 2;
621 if (!lua_tointeger(L, -2)) {
622 lua_pushvalue(L, 1);
623 return 1;
624 }
625 #if LUA_VERSION_NUM >= 503
626 return moonbr_io_write_cont(L, 0, 0);
627 #else
628 return moonbr_io_write_cont(L);
629 #endif
630 }
632 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
634 static int moonbr_io_finish(lua_State *L) {
635 moonbr_io_handle_t *handle;
636 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
637 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
638 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
639 if (handle->writeleft) {
640 lua_pushcfunction(L, moonbr_io_flush);
641 lua_pushvalue(L, 1);
642 if (lua_pcall(L, 1, 2, 0)) {
643 handle->finished = 1;
644 lua_error(L);
645 }
646 if (!lua_toboolean(L, -2)) {
647 handle->finished = 1;
648 return 2;
649 }
650 }
651 handle->finished = 1;
652 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
653 if (shutdown(handle->fd, SHUT_WR)) {
654 moonbr_io_errmsg();
655 lua_pushnil(L);
656 lua_pushstring(L, errmsg);
657 return 2;
658 }
659 } else {
660 if (close(handle->fd)) {
661 moonbr_io_errmsg();
662 handle->fd = -1;
663 lua_pushnil(L);
664 lua_pushstring(L, errmsg);
665 return 2;
666 }
667 handle->fd = -1; /* fake EOF on read */
668 }
669 lua_pushboolean(L, 1);
670 return 1;
671 }
673 static int moonbr_io_close_impl(lua_State *L, int reset) {
674 moonbr_io_handle_t *handle;
675 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
676 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
677 if (!reset) {
678 if (handle->writeleft) {
679 lua_pushcfunction(L, moonbr_io_flush);
680 lua_pushvalue(L, 1);
681 if (lua_pcall(L, 1, 2, 0)) {
682 handle->closed = 1;
683 close(handle->fd);
684 handle->fd = -1;
685 lua_error(L);
686 }
687 handle->closed = 1;
688 if (!lua_toboolean(L, -2)) {
689 close(handle->fd);
690 handle->fd = -1;
691 return 2;
692 }
693 } else {
694 handle->closed = 1;
695 moonbr_io_handle_set_linger(L, handle, -1);
696 }
697 } else {
698 handle->closed = 1;
699 }
700 if (handle->fd >= 0) {
701 if (close(handle->fd)) {
702 moonbr_io_errmsg();
703 handle->fd = -1;
704 lua_pushnil(L);
705 lua_pushstring(L, errmsg);
706 return 2;
707 }
708 handle->fd = -1;
709 }
710 lua_pushboolean(L, 1);
711 return 1;
713 }
715 static int moonbr_io_close(lua_State *L) {
716 return moonbr_io_close_impl(L, 0);
717 }
719 static int moonbr_io_reset(lua_State *L) {
720 return moonbr_io_close_impl(L, 1);
721 }
723 static int moonbr_io_handlegc(lua_State *L) {
724 moonbr_io_handle_t *handle;
725 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
726 if (handle->fd >= 0) {
727 lua_pushcfunction(L, moonbr_io_close);
728 lua_pushvalue(L, 1);
729 lua_pushinteger(L, 0);
730 lua_call(L, 2, 0);
731 }
732 return 0;
733 }
735 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
736 moonbr_io_handle_t *handle;
737 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
738 if (!handle->closed) {
739 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
740 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
741 lua_call(L, 1, 0);
742 }
743 }
745 void moonbr_io_pushhandle(lua_State *L, int fd) {
746 moonbr_io_handle_t *handle;
747 struct sockaddr addr;
748 socklen_t addrlen;
749 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
750 handle->fd = fd;
751 addrlen = sizeof(addr);
752 if (getsockname(fd, &addr, &addrlen)) {
753 if (errno != ENOTSOCK) {
754 moonbr_io_errmsg();
755 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
756 }
757 handle->issock = 0;
758 } else {
759 handle->issock = 1;
760 handle->addrfam = addr.sa_family;
761 }
762 handle->finished = 0;
763 handle->closed = 0;
764 handle->nonblocking = -1;
765 handle->nopush = -1;
766 handle->readerr = 0;
767 handle->readbufin = 0;
768 handle->readbufout = 0;
769 handle->writeerr = 0;
770 handle->writeleft = 0;
771 handle->flushedleft = 0;
772 handle->writeqin = 0;
773 handle->writeqout = 0;
774 handle->writeqoff = 0;
775 handle->writebufin = 0;
776 handle->writebufout = 0;
777 moonbr_io_handle_set_linger(L, handle, 0);
778 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
779 lua_setmetatable(L, -2);
780 lua_newtable(L); // uservalue
781 lua_newtable(L);
782 lua_setfield(L, -2, "writequeue");
783 lua_newtable(L); // public
784 if (handle->addrfam == AF_INET6) {
785 struct sockaddr_in6 addr_in6;
786 char addrstrbuf[INET6_ADDRSTRLEN];
787 const char *addrstr;
788 addrlen = sizeof(addr_in6);
789 if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
790 moonbr_io_errmsg();
791 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
792 }
793 if (addrlen > sizeof(addr_in6)) {
794 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
795 }
796 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
797 if (!addrstr) {
798 moonbr_io_errmsg();
799 luaL_error(L, "Could not format local IP address: %s", errmsg);
800 } else {
801 lua_pushstring(L, addrstr);
802 lua_setfield(L, -2, "local_ip6");
803 }
804 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
805 lua_setfield(L, -2, "local_tcpport");
806 if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
807 moonbr_io_errmsg();
808 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
809 }
810 if (addrlen > sizeof(addr_in6)) {
811 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
812 }
813 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
814 if (!addrstr) {
815 moonbr_io_errmsg();
816 luaL_error(L, "Could not format remote IP address: %s", errmsg);
817 } else {
818 lua_pushstring(L, addrstr);
819 lua_setfield(L, -2, "remote_ip6");
820 }
821 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
822 lua_setfield(L, -2, "remote_tcpport");
823 } else if (handle->addrfam == AF_INET) {
824 struct sockaddr_in addr_in;
825 char addrstrbuf[INET_ADDRSTRLEN];
826 const char *addrstr;
827 addrlen = sizeof(addr_in);
828 if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) {
829 moonbr_io_errmsg();
830 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
831 }
832 if (addrlen > sizeof(addr_in)) {
833 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
834 }
835 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
836 if (!addrstr) {
837 moonbr_io_errmsg();
838 luaL_error(L, "Could not format local IP address: %s", errmsg);
839 } else {
840 lua_pushstring(L, addrstr);
841 lua_setfield(L, -2, "local_ip4");
842 }
843 lua_pushinteger(L, ntohs(addr_in.sin_port));
844 lua_setfield(L, -2, "local_tcpport");
845 if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) {
846 moonbr_io_errmsg();
847 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
848 }
849 if (addrlen > sizeof(addr_in)) {
850 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
851 }
852 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
853 if (!addrstr) {
854 moonbr_io_errmsg();
855 luaL_error(L, "Could not format remote IP address: %s", errmsg);
856 } else {
857 lua_pushstring(L, addrstr);
858 lua_setfield(L, -2, "remote_ip4");
859 }
860 lua_pushinteger(L, ntohs(addr_in.sin_port));
861 lua_setfield(L, -2, "remote_tcpport");
862 }
863 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
864 lua_setmetatable(L, -2);
865 lua_setfield(L, -2, "public");
866 lua_setuservalue(L, -2);
867 }
869 static int moonbr_io_handleindex(lua_State *L) {
870 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
871 luaL_checkany(L, 2);
872 lua_getuservalue(L, 1);
873 lua_getfield(L, -1, "public");
874 lua_pushvalue(L, 2);
875 lua_gettable(L, -2);
876 return 1;
877 }
879 static int moonbr_io_handlenewindex(lua_State *L) {
880 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
881 luaL_checkany(L, 2);
882 luaL_checkany(L, 3);
883 lua_getuservalue(L, 1);
884 lua_getfield(L, -1, "public");
885 lua_pushvalue(L, 2);
886 lua_pushvalue(L, 3);
887 lua_settable(L, -3);
888 return 0;
889 }
891 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
892 const char *path;
893 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
894 const int path_maxlen = sizeof(struct sockaddr_un) - (
895 (void *)sockaddr.sun_path - (void *)&sockaddr
896 ) - 1; /* one byte for termination */
897 int sock;
898 path = luaL_checkstring(L, 1);
899 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
900 strcpy(sockaddr.sun_path, path);
901 sock = socket(
902 PF_LOCAL,
903 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
904 0
905 );
906 if (sock < 0) {
907 moonbr_io_errmsg();
908 lua_pushnil(L);
909 lua_pushstring(L, errmsg);
910 return 2;
911 }
912 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
913 if (!nonblocking && errno == EINTR) {
914 moonbr_io_errmsg();
915 close(sock);
916 lua_pushnil(L);
917 lua_pushstring(L, errmsg);
918 return 2;
919 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
920 moonbr_io_errmsg();
921 lua_pushnil(L);
922 lua_pushstring(L, errmsg);
923 return 2;
924 }
925 }
926 moonbr_io_pushhandle(L, sock);
927 return 1;
928 }
930 static int moonbr_io_localconnect(lua_State *L) {
931 return moonbr_io_localconnect_impl(L, 0);
932 }
934 static int moonbr_io_localconnect_nb(lua_State *L) {
935 return moonbr_io_localconnect_impl(L, 1);
936 }
938 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
939 const char *host, *port;
940 struct addrinfo hints = { 0, };
941 struct addrinfo *res, *addrinfo;
942 int errcode;
943 int sock;
944 host = luaL_checkstring(L, 1);
945 port = luaL_checkstring(L, 2);
946 hints.ai_family = AF_UNSPEC;
947 hints.ai_socktype = SOCK_STREAM;
948 hints.ai_protocol = IPPROTO_TCP;
949 hints.ai_flags = AI_ADDRCONFIG;
950 errcode = getaddrinfo(host, port, &hints, &res);
951 if (errcode) {
952 freeaddrinfo(res);
953 if (errcode == EAI_SYSTEM) {
954 moonbr_io_errmsg();
955 lua_pushnil(L);
956 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
957 } else {
958 lua_pushnil(L);
959 lua_pushstring(L, gai_strerror(errcode));
960 }
961 return 2;
962 }
963 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
964 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
965 }
966 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
967 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
968 }
969 addrinfo = res;
970 moonbr_io_tcpconnect_found:
971 sock = socket(
972 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
973 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
974 addrinfo->ai_protocol
975 );
976 if (sock < 0) {
977 moonbr_io_errmsg();
978 freeaddrinfo(res);
979 lua_pushnil(L);
980 lua_pushstring(L, errmsg);
981 return 2;
982 }
983 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
984 freeaddrinfo(res);
985 if (!nonblocking && errno == EINTR) {
986 moonbr_io_errmsg();
987 close(sock);
988 lua_pushnil(L);
989 lua_pushstring(L, errmsg);
990 return 2;
991 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
992 moonbr_io_errmsg();
993 lua_pushnil(L);
994 lua_pushstring(L, errmsg);
995 return 2;
996 }
997 } else {
998 freeaddrinfo(res);
999 }
1000 moonbr_io_pushhandle(L, sock);
1001 return 1;
1004 static int moonbr_io_tcpconnect(lua_State *L) {
1005 return moonbr_io_tcpconnect_impl(L, 0);
1008 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1009 return moonbr_io_tcpconnect_impl(L, 1);
1012 static int moonbr_io_locallisten(lua_State *L) {
1013 moonbr_io_listener_t *listener;
1014 const char *path;
1015 struct stat sb;
1016 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1017 const int path_maxlen = sizeof(struct sockaddr_un) - (
1018 (void *)sockaddr.sun_path - (void *)&sockaddr
1019 ) - 1; /* one byte for termination */
1020 int sock;
1021 path = luaL_checkstring(L, 1);
1022 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1023 strcpy(sockaddr.sun_path, path);
1024 if (stat(path, &sb) == 0) {
1025 if (S_ISSOCK(sb.st_mode)) unlink(path);
1027 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1028 listener->fd = -1;
1029 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1030 sock = socket(
1031 PF_LOCAL,
1032 SOCK_STREAM | SOCK_CLOEXEC,
1034 );
1035 if (sock < 0) {
1036 moonbr_io_errmsg();
1037 lua_pushnil(L);
1038 lua_pushstring(L, errmsg);
1039 return 2;
1041 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1042 moonbr_io_errmsg();
1043 close(sock);
1044 lua_pushnil(L);
1045 lua_pushstring(L, errmsg);
1046 return 2;
1048 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1049 moonbr_io_errmsg();
1050 close(sock);
1051 lua_pushnil(L);
1052 lua_pushstring(L, errmsg);
1053 return 2;
1055 listener->fd = sock;
1056 listener->addrfam = AF_LOCAL;
1057 listener->nonblocking = -1;
1058 return 1;
1061 static int moonbr_io_tcplisten(lua_State *L) {
1062 moonbr_io_listener_t *listener;
1063 const char *host, *port;
1064 struct addrinfo hints = { 0, };
1065 struct addrinfo *res, *addrinfo;
1066 int errcode;
1067 int sock;
1068 host = luaL_optstring(L, 1, NULL);
1069 port = luaL_checkstring(L, 2);
1070 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1071 listener->fd = -1;
1072 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1073 hints.ai_family = AF_UNSPEC;
1074 hints.ai_socktype = SOCK_STREAM;
1075 hints.ai_protocol = IPPROTO_TCP;
1076 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1077 errcode = getaddrinfo(host, port, &hints, &res);
1078 if (errcode) {
1079 freeaddrinfo(res);
1080 if (errcode == EAI_SYSTEM) {
1081 moonbr_io_errmsg();
1082 lua_pushnil(L);
1083 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1084 } else {
1085 lua_pushnil(L);
1086 lua_pushstring(L, gai_strerror(errcode));
1088 return 2;
1090 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1091 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1093 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1094 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1096 addrinfo = res;
1097 moonbr_io_tcpconnect_found:
1098 listener->addrfam = addrinfo->ai_family;
1099 sock = socket(
1100 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1101 addrinfo->ai_socktype | SOCK_CLOEXEC,
1102 addrinfo->ai_protocol
1103 );
1104 if (sock < 0) {
1105 moonbr_io_errmsg();
1106 freeaddrinfo(res);
1107 lua_pushnil(L);
1108 lua_pushstring(L, errmsg);
1109 return 2;
1112 static const int reuseval = 1;
1113 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1114 moonbr_io_errmsg();
1115 freeaddrinfo(res);
1116 close(sock);
1117 lua_pushnil(L);
1118 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1119 return 2;
1122 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1123 moonbr_io_errmsg();
1124 freeaddrinfo(res);
1125 close(sock);
1126 lua_pushnil(L);
1127 lua_pushstring(L, errmsg);
1128 return 2;
1130 freeaddrinfo(res);
1131 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1132 moonbr_io_errmsg();
1133 close(sock);
1134 lua_pushnil(L);
1135 lua_pushstring(L, errmsg);
1136 return 2;
1138 listener->fd = sock;
1139 listener->nonblocking = -1;
1140 return 1;
1143 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1144 moonbr_io_listener_t *listener;
1145 int fd;
1146 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1147 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1148 if (listener->nonblocking != nonblocking) {
1149 int flags;
1150 flags = fcntl(listener->fd, F_GETFL, 0);
1151 if (flags == -1) {
1152 moonbr_io_errmsg();
1153 close(listener->fd);
1154 listener->fd = -1;
1155 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1157 if (nonblocking) flags |= O_NONBLOCK;
1158 else flags &= ~O_NONBLOCK;
1159 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1160 moonbr_io_errmsg();
1161 close(listener->fd);
1162 listener->fd = -1;
1163 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1165 listener->nonblocking = nonblocking;
1167 while (1) {
1168 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1169 if (fd < 0) {
1170 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1171 lua_pushboolean(L, 0);
1172 lua_pushliteral(L, "No incoming connection pending");
1173 return 2;
1174 } else if (errno != EINTR) {
1175 moonbr_io_errmsg();
1176 lua_pushnil(L);
1177 lua_pushstring(L, errmsg);
1178 return 2;
1180 } else {
1181 moonbr_io_pushhandle(L, fd);
1182 return 1;
1187 static int moonbr_io_accept(lua_State *L) {
1188 return moonbr_io_accept_impl(L, 0);
1191 static int moonbr_io_accept_nb(lua_State *L) {
1192 return moonbr_io_accept_impl(L, 1);
1195 static int moonbr_io_unlisten(lua_State *L) {
1196 moonbr_io_listener_t *listener;
1197 struct sockaddr_un addr;
1198 socklen_t addrlen;
1199 struct stat sb;
1200 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1201 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1202 addrlen = sizeof(addr);
1203 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1204 if (close(listener->fd)) {
1205 moonbr_io_errmsg();
1206 listener->fd = -1;
1207 if (addrlen && addrlen <= sizeof(addr)) {
1208 if (stat(addr.sun_path, &sb) == 0) {
1209 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1212 lua_pushnil(L);
1213 lua_pushstring(L, errmsg);
1214 return 2;
1216 listener->fd = -1;
1217 if (addrlen && addrlen <= sizeof(addr)) {
1218 if (stat(addr.sun_path, &sb) == 0) {
1219 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1222 lua_pushboolean(L, 1);
1223 return 1;
1226 static int moonbr_io_listenergc(lua_State *L) {
1227 moonbr_io_listener_t *listener;
1228 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1229 if (listener->fd >= 0) close(listener->fd);
1230 listener->fd = -1;
1231 return 0;
1234 static int moonbr_io_exec(lua_State *L) {
1235 char **argv;
1236 int i, argc;
1237 int sockin[2], sockout[2], sockerr[2];
1238 volatile int errorcond = 0;
1239 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN];
1240 moonbr_io_child_t *child;
1241 argc = lua_gettop(L);
1242 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1243 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1244 argv[argc] = NULL;
1245 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sockin)) {
1246 moonbr_io_errmsg();
1247 lua_pushnil(L);
1248 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1249 return 2;
1251 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sockout)) {
1252 moonbr_io_errmsg();
1253 close(sockin[0]);
1254 close(sockin[1]);
1255 lua_pushnil(L);
1256 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1257 return 2;
1259 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sockerr)) {
1260 moonbr_io_errmsg();
1261 close(sockin[0]);
1262 close(sockin[1]);
1263 close(sockout[0]);
1264 close(sockout[1]);
1265 lua_pushnil(L);
1266 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1267 return 2;
1269 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1270 child->pid = vfork();
1271 if (child->pid == -1) {
1272 moonbr_io_errmsg();
1273 close(sockin[0]);
1274 close(sockin[1]);
1275 close(sockout[0]);
1276 close(sockout[1]);
1277 close(sockerr[0]);
1278 close(sockerr[1]);
1279 lua_pushnil(L);
1280 lua_pushfstring(L, "Could not fork: %s", errmsg);
1281 return 2;
1283 if (!child->pid) {
1284 if (dup2(sockin[1], 0) == -1) {
1285 errorcond = 1;
1286 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1287 _exit(0);
1289 if (dup2(sockout[1], 1) == -1) {
1290 errorcond = 1;
1291 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1292 _exit(0);
1294 if (dup2(sockerr[1], 2) == -1) {
1295 errorcond = 1;
1296 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1297 _exit(0);
1299 closefrom(4);
1300 if (execvp(argv[0], argv)) {
1301 errorcond = 2;
1302 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1303 _exit(0);
1306 close(sockin[1]);
1307 close(sockout[1]);
1308 close(sockerr[1]);
1309 if (errorcond) {
1310 int status;
1311 close(sockin[0]);
1312 close(sockout[0]);
1313 close(sockerr[0]);
1314 while (waitpid(child->pid, &status, 0) == -1) {
1315 if (errno != EINTR) {
1316 moonbr_io_errmsg();
1317 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1320 lua_pushnil(L);
1321 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1322 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1323 return 2;
1325 if (fcntl(sockin[0], F_SETFD, FD_CLOEXEC) == -1) {
1326 moonbr_io_errmsg();
1327 close(sockin[0]);
1328 close(sockout[0]);
1329 close(sockerr[0]);
1330 luaL_error(L, "Error in fcntl call: %s", errmsg);
1332 if (fcntl(sockout[0], F_SETFD, FD_CLOEXEC) == -1) {
1333 moonbr_io_errmsg();
1334 close(sockin[0]);
1335 close(sockout[0]);
1336 close(sockerr[0]);
1337 luaL_error(L, "Error in fcntl call: %s", errmsg);
1339 if (fcntl(sockerr[0], F_SETFD, FD_CLOEXEC) == -1) {
1340 moonbr_io_errmsg();
1341 close(sockin[0]);
1342 close(sockout[0]);
1343 close(sockerr[0]);
1344 luaL_error(L, "Error in fcntl call: %s", errmsg);
1346 /* close sockets during garbage collection in case a Lua error is raised */
1347 child->uninitialized_in = sockin[0];
1348 child->uninitialized_out = sockout[0];
1349 child->uninitialized_err = sockerr[0];
1350 lua_newtable(L);
1351 lua_setuservalue(L, -2);
1352 luaL_getmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1353 lua_setmetatable(L, -2);
1354 moonbr_io_pushhandle(L, sockin[0]);
1355 lua_setfield(L, -2, "stdin");
1356 child->uninitialized_in = -1;
1357 moonbr_io_pushhandle(L, sockout[0]);
1358 lua_setfield(L, -2, "stdout");
1359 child->uninitialized_out = -1;
1360 moonbr_io_pushhandle(L, sockerr[0]);
1361 lua_setfield(L, -2, "stderr");
1362 child->uninitialized_err = -1;
1363 return 1;
1366 static int moonbr_io_childindex(lua_State *L) {
1367 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1368 luaL_checkany(L, 2);
1369 lua_getuservalue(L, 1);
1370 lua_pushvalue(L, 2);
1371 lua_gettable(L, -2);
1372 if (lua_isnil(L, -1)) {
1373 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1374 lua_pushvalue(L, 2);
1375 lua_gettable(L, -2);
1377 return 1;
1380 static int moonbr_io_childnewindex(lua_State *L) {
1381 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1382 luaL_checkany(L, 2);
1383 luaL_checkany(L, 3);
1384 lua_getuservalue(L, 1);
1385 lua_pushvalue(L, 2);
1386 lua_pushvalue(L, 3);
1387 lua_settable(L, -3);
1388 return 0;
1391 static int moonbr_io_childgc(lua_State *L) {
1392 moonbr_io_child_t *child;
1393 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1394 if (child->pid) {
1395 int status;
1396 if (kill(child->pid, SIGKILL)) {
1397 moonbr_io_errmsg();
1398 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1400 while (waitpid(child->pid, &status, 0) == -1) {
1401 if (errno != EINTR) {
1402 moonbr_io_errmsg();
1403 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1407 if (child->uninitialized_in != -1) close(child->uninitialized_in);
1408 if (child->uninitialized_out != -1) close(child->uninitialized_out);
1409 if (child->uninitialized_err != -1) close(child->uninitialized_err);
1410 return 0;
1413 static int moonbr_io_kill(lua_State *L) {
1414 moonbr_io_child_t *child;
1415 int sig;
1416 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1417 sig = luaL_optinteger(L, 2, SIGTERM);
1418 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
1419 if (kill(child->pid, sig)) {
1420 moonbr_io_errmsg();
1421 luaL_error(L, "Error in kill call: %s", errmsg);
1423 lua_settop(L, 1);
1424 return 1;
1427 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1428 moonbr_io_child_t *child;
1429 pid_t waitedpid;
1430 int status;
1431 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1432 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
1433 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1434 if (errno != EINTR) {
1435 moonbr_io_errmsg();
1436 luaL_error(L, "Error in waitpid call: %s", errmsg);
1439 if (!waitedpid) {
1440 lua_pushnil(L);
1441 } else {
1442 child->pid = 0;
1443 if (WIFEXITED(status)) {
1444 lua_pushinteger(L, WEXITSTATUS(status));
1445 } else if (WIFSIGNALED(status)) {
1446 lua_pushinteger(L, -WTERMSIG(status));
1447 } else {
1448 luaL_error(L, "Unexpected status value returned by waitpid call");
1451 return 1;
1454 static int moonbr_io_wait(lua_State *L) {
1455 return moonbr_io_wait_impl(L, 0);
1458 static int moonbr_io_wait_nb(lua_State *L) {
1459 return moonbr_io_wait_impl(L, 1);
1462 #if LUA_VERSION_NUM >= 503
1463 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1464 #else
1465 static int moonbr_io_wait_cont(lua_State *L) {
1466 #endif
1467 #if !(LUA_VERSION_NUM >= 503)
1468 int ctx = 0;
1469 lua_getctx(L, &ctx);
1470 #endif
1471 while (1) {
1472 lua_pushcfunction(L, moonbr_io_wait_nb);
1473 lua_pushvalue(L, 1);
1474 lua_call(L, 1, 1);
1475 if (!lua_isnil(L, -1)) break;
1476 lua_pushvalue(L, 2);
1477 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1479 return 1;
1482 static int moonbr_io_wait_call(lua_State *L) {
1483 lua_settop(L, 2);
1484 #if LUA_VERSION_NUM >= 503
1485 return moonbr_io_wait_cont(L, 0, 0);
1486 #else
1487 return moonbr_io_wait_cont(L);
1488 #endif
1491 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1493 static int moonbr_io_poll(lua_State *L) {
1494 moonbr_io_handle_t *handle;
1495 moonbr_io_listener_t *listener;
1496 int fd, isnum;
1497 int nfds = 0;
1498 fd_set readfds, writefds, exceptfds;
1499 struct timeval timeout = {0, };
1500 int status;
1501 FD_ZERO(&readfds);
1502 FD_ZERO(&writefds);
1503 FD_ZERO(&exceptfds);
1504 if (!lua_isnoneornil(L, 1)) {
1505 luaL_checktype(L, 1, LUA_TTABLE);
1506 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1507 if (lua_toboolean(L, -1)) {
1508 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1509 if (handle) {
1510 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1511 fd = handle->fd;
1512 if (
1513 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1514 handle->readbufin != handle->readbufout /* data pending in buffer */
1515 ) {
1516 lua_pushboolean(L, 1);
1517 return 1;
1519 } else {
1520 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1521 if (listener) {
1522 fd = listener->fd;
1523 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1524 } else {
1525 fd = lua_tointegerx(L, -2, &isnum);
1526 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1529 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1530 FD_SET(fd, &readfds);
1531 if (fd+1 > nfds) nfds = fd+1;
1535 if (!lua_isnoneornil(L, 2)) {
1536 luaL_checktype(L, 2, LUA_TTABLE);
1537 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1538 if (lua_toboolean(L, -1)) {
1539 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1540 if (handle) {
1541 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1542 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1543 fd = handle->fd;
1544 } else {
1545 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1546 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1547 fd = lua_tointegerx(L, -2, &isnum);
1548 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1550 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1551 FD_SET(fd, &writefds);
1552 if (fd+1 > nfds) nfds = fd+1;
1556 if (!lua_isnoneornil(L, 3)) {
1557 lua_Number n;
1558 n = lua_tonumberx(L, 3, &isnum);
1559 if (isnum && n<0) {
1560 lua_pushboolean(L, 0);
1561 lua_pushliteral(L, "Negative timeout");
1562 return 2;
1563 } else if (isnum && n>=0 && n<100000000) {
1564 timeout.tv_sec = n;
1565 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1566 } else {
1567 luaL_argcheck(L, 0, 3, "not a valid timeout");
1569 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1570 } else {
1571 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1573 if (status == -1) {
1574 if (errno == EINTR) {
1575 lua_pushnil(L);
1576 lua_pushliteral(L, "Signal received while polling file descriptors");
1577 return 2;
1578 } else {
1579 moonbr_io_errmsg();
1580 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1582 } else if (status == 0) {
1583 lua_pushboolean(L, 0);
1584 lua_pushliteral(L, "Timeout while polling file descriptors");
1585 return 2;
1586 } else {
1587 lua_pushboolean(L, 1);
1588 return 1;
1592 static int moonbr_io_timeref(lua_State *L) {
1593 lua_Number sub;
1594 struct timespec tp;
1595 sub = luaL_optnumber(L, 1, 0);
1596 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1597 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1599 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1600 return 1;
1603 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1604 {"read", moonbr_io_read},
1605 {"read_nb", moonbr_io_read_nb},
1606 {"read_call", moonbr_io_read_call},
1607 {"read_yield", moonbr_io_read_yield},
1608 {"drain", moonbr_io_drain},
1609 {"drain_nb", moonbr_io_drain_nb},
1610 {"drain_call", moonbr_io_drain_call},
1611 {"drain_yield", moonbr_io_drain_yield},
1612 {"write", moonbr_io_write},
1613 {"write_nb", moonbr_io_write_nb},
1614 {"write_call", moonbr_io_write_call},
1615 {"write_yield", moonbr_io_write_yield},
1616 {"flush", moonbr_io_flush},
1617 {"flush_nb", moonbr_io_flush_nb},
1618 {"flush_call", moonbr_io_flush_call},
1619 {"flush_yield", moonbr_io_flush_yield},
1620 {"finish", moonbr_io_finish},
1621 {"close", moonbr_io_close},
1622 {"reset", moonbr_io_reset},
1623 {NULL, NULL}
1624 };
1626 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1627 {"__index", moonbr_io_handleindex},
1628 {"__newindex", moonbr_io_handlenewindex},
1629 {"__gc", moonbr_io_handlegc},
1630 {NULL, NULL}
1631 };
1633 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1634 {"accept", moonbr_io_accept},
1635 {"accept_nb", moonbr_io_accept_nb},
1636 {"close", moonbr_io_unlisten},
1637 {NULL, NULL}
1638 };
1640 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1641 {"__gc", moonbr_io_listenergc},
1642 {NULL, NULL}
1643 };
1645 static const struct luaL_Reg moonbr_io_child_methods[] = {
1646 {"kill", moonbr_io_kill},
1647 {"wait", moonbr_io_wait},
1648 {"wait_nb", moonbr_io_wait_nb},
1649 {"wait_call", moonbr_io_wait_call},
1650 {"wait_yield", moonbr_io_wait_yield},
1651 {NULL, NULL}
1652 };
1654 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
1655 {"__index", moonbr_io_childindex},
1656 {"__newindex", moonbr_io_childnewindex},
1657 {"__gc", moonbr_io_childgc},
1658 {NULL, NULL}
1659 };
1661 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1662 {"localconnect", moonbr_io_localconnect},
1663 {"localconnect_nb", moonbr_io_localconnect_nb},
1664 {"tcpconnect", moonbr_io_tcpconnect},
1665 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1666 {"locallisten", moonbr_io_locallisten},
1667 {"tcplisten", moonbr_io_tcplisten},
1668 {"exec", moonbr_io_exec},
1669 {"poll", moonbr_io_poll},
1670 {"timeref", moonbr_io_timeref},
1671 {NULL, NULL}
1672 };
1674 int luaopen_moonbridge_io(lua_State *L) {
1676 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1678 lua_newtable(L); // module
1680 lua_newtable(L); // public metatable
1681 lua_newtable(L); // handle methods
1682 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1683 lua_pushvalue(L, -1);
1684 lua_setfield(L, -4, "handle_pt");
1685 lua_setfield(L, -2, "__index");
1686 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1688 lua_newtable(L); // handle metatable
1689 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1690 lua_pushvalue(L, -1);
1691 lua_setfield(L, -3, "handle_mt");
1692 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1694 lua_newtable(L); // listener metatable
1695 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1696 lua_newtable(L); // listener methods
1697 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1698 lua_pushvalue(L, -1);
1699 lua_setfield(L, -4, "listener_pt");
1700 lua_setfield(L, -2, "__index");
1701 lua_pushvalue(L, -1);
1702 lua_setfield(L, -3, "listener_mt");
1703 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1705 lua_newtable(L); // child methods
1706 luaL_setfuncs(L, moonbr_io_child_methods, 0);
1707 lua_pushvalue(L, -1);
1708 lua_setfield(L, -3, "child_pt");
1709 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
1710 lua_newtable(L); // child metatable
1711 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
1712 lua_pushvalue(L, -1);
1713 lua_setfield(L, -3, "child_mt");
1714 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
1716 moonbr_io_pushhandle(L, 0);
1717 lua_setfield(L, -2, "stdin");
1718 moonbr_io_pushhandle(L, 1);
1719 lua_setfield(L, -2, "stdout");
1720 moonbr_io_pushhandle(L, 2);
1721 lua_setfield(L, -2, "stderr");
1723 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1724 return 1;

Impressum / About Us