moonbridge

view moonbridge_io.c @ 239:90e6db450677

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

Impressum / About Us