moonbridge

view moonbridge_io.c @ 313:334ea1f13b0b

Modified non-blocking I/O _call functions to pass certain arguments (socket, mode, module) to wait function
author jbe
date Thu Feb 01 19:13:25 2018 +0100 (2018-02-01)
parents 930a43a0099a
children 1b459e9c12c9
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_prepare_errmsg() \
46 char errmsg[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG; \
47 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
48 #define moonbr_io_return_prepared_errmsg() \
49 lua_pushnil(L); \
50 lua_pushstring(L, errmsg); \
51 return 2
52 #define moonbr_io_return_errmsg() \
53 do { \
54 moonbr_io_prepare_errmsg(); \
55 moonbr_io_return_prepared_errmsg(); \
56 } while (0)
58 #define MOONBR_IO_MODULE_REGKEY "moonbridge_io_module"
59 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
60 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
61 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
62 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
63 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
65 #ifdef MOONBR_IO_USE_TLS
67 #define MOONBR_IO_TLSCONF_MT_REGKEY "moonbridge_io_tlsconf"
69 typedef struct {
70 struct tls_config *config;
71 int server;
72 } moonbr_io_tlsconf_t;
74 #endif /* MOONBR_IO_USE_TLS */
76 typedef struct {
77 int fd;
78 int issock;
79 sa_family_t addrfam;
80 int finished;
81 int closed;
82 int nonblocking;
83 int nopush;
84 int readerr;
85 int readbufin;
86 int readbufout;
87 int writeerr;
88 size_t writeleft;
89 size_t flushedleft;
90 #if LUA_VERSION_NUM >= 503
91 lua_Integer writeqin;
92 lua_Integer writeqout;
93 #else
94 int writeqin;
95 int writeqout;
96 #endif
97 size_t writeqoff;
98 int writebufin;
99 int writebufout;
100 char readbuf[MOONBR_IO_READBUFLEN];
101 char writebuf[MOONBR_IO_WRITEBUFLEN];
102 #ifdef MOONBR_IO_USE_TLS
103 struct tls *tls;
104 struct tls *servertls;
105 int tlshandshake;
106 int tlsclosing;
107 #endif
108 } moonbr_io_handle_t;
110 typedef struct {
111 int fd;
112 sa_family_t addrfam;
113 int nonblocking;
114 } moonbr_io_listener_t;
116 typedef struct {
117 pid_t pid;
118 int status;
119 int status_valid;
120 } moonbr_io_child_t;
122 volatile sig_atomic_t moonbr_io_sigterm_flag = 0;
123 volatile sig_atomic_t moonbr_io_sigchld_flag = 0;
125 static int moonbr_io_yield(lua_State *L) {
126 return lua_yield(L, lua_gettop(L));
127 }
129 #if LUA_VERSION_NUM >= 503
130 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
131 #else
132 static int moonbr_io_cont_returnall(lua_State *L) {
133 #endif
134 return lua_gettop(L);
135 }
137 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
138 static int yieldfunc(lua_State *L) { \
139 int args; \
140 lua_pushcfunction(L, callfunc); \
141 lua_insert(L, 1); \
142 args = lua_gettop(L); \
143 lua_pushcfunction(L, moonbr_io_yield); \
144 lua_insert(L, 3); \
145 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
146 return lua_gettop(L); \
147 }
149 static int moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
150 int flags;
151 if (handle->nonblocking == nonblocking) return 0;
152 flags = fcntl(handle->fd, F_GETFL, 0);
153 if (flags == -1) return -1;
154 if (nonblocking) flags |= O_NONBLOCK;
155 else flags &= ~O_NONBLOCK;
156 if (fcntl(handle->fd, F_SETFL, flags) == -1) return -1;
157 handle->nonblocking = nonblocking;
158 return 0;
159 }
161 static int moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
162 struct linger lingerval = { 0, };
163 if (!handle->issock) return 0;
164 if (timeout >= 0) {
165 lingerval.l_onoff = 1;
166 lingerval.l_linger = timeout;
167 }
168 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) return -1;
169 return 0;
170 }
172 static inline int moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
173 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
174 if (
175 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
176 handle->nopush == nopush
177 ) return 0;
178 #if defined(TCP_NOPUSH)
179 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) return -1;
180 #elif defined(TCP_CORK)
181 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) return -1;
182 #endif
183 handle->nopush = nopush;
184 #else
185 #warning Neither TCP_NOPUSH nor TCP_CORK is available
186 #endif
187 return 0;
188 }
190 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
191 moonbr_io_handle_t *handle;
192 lua_Integer maxread;
193 const char *terminatorstr;
194 size_t terminatorlen;
195 char terminator = 0; /* initialize to avoid compiler warning */
196 luaL_Buffer luabuf;
197 size_t luabufcnt = 0;
198 int remaining;
199 char *terminatorpos;
200 ssize_t bytesread;
201 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
202 maxread = luaL_optinteger(L, 2, -1);
203 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
204 if (terminatorlen) {
205 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
206 terminator = terminatorstr[0];
207 }
208 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
209 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
210 if (handle->readerr) {
211 lua_pushnil(L);
212 lua_pushliteral(L, "Previous read error");
213 return 2;
214 }
215 if (handle->fd < 0) {
216 /* fake EOF to simulate shutdown */
217 if (!drain) lua_pushliteral(L, "");
218 else lua_pushinteger(L, 0);
219 lua_pushliteral(L, "eof");
220 return 2;
221 }
222 handle->readerr = 1;
223 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
224 if (!drain) luaL_buffinit(L, &luabuf);
225 while (1) {
226 remaining = -1;
227 terminatorpos = NULL;
228 if (
229 maxread >= 0 &&
230 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
231 ) {
232 remaining = (size_t)maxread - luabufcnt;
233 if (terminatorlen) {
234 terminatorpos = memchr(
235 handle->readbuf + handle->readbufout,
236 terminator,
237 remaining
238 );
239 }
240 } else if (terminatorlen) {
241 terminatorpos = memchr(
242 handle->readbuf + handle->readbufout,
243 terminator,
244 handle->readbufin - handle->readbufout
245 );
246 }
247 if (terminatorpos) remaining = 1 + (
248 terminatorpos - (handle->readbuf + handle->readbufout)
249 );
250 if (remaining >= 0) {
251 if (!drain) {
252 luaL_addlstring(
253 &luabuf,
254 handle->readbuf + handle->readbufout,
255 remaining
256 );
257 luaL_pushresult(&luabuf);
258 } else {
259 lua_pushinteger(L, luabufcnt + remaining);
260 }
261 if (terminatorpos) lua_pushliteral(L, "term");
262 else lua_pushliteral(L, "maxlen");
263 handle->readbufout += remaining;
264 if (handle->readbufout == handle->readbufin) {
265 handle->readbufin = 0;
266 handle->readbufout = 0;
267 }
268 handle->readerr = 0;
269 return 2;
270 }
271 if (!drain) luaL_addlstring(
272 &luabuf,
273 handle->readbuf + handle->readbufout,
274 handle->readbufin - handle->readbufout
275 );
276 luabufcnt += handle->readbufin - handle->readbufout;
277 handle->readbufout = 0;
278 #ifdef MOONBR_IO_USE_TLS
279 if (handle->tls) {
280 do {
281 if (!handle->tlshandshake) {
282 do bytesread = tls_handshake(handle->tls);
283 while (!nonblocking && (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT));
284 if (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT) {
285 handle->tlshandshake = bytesread;
286 errno = EAGAIN;
287 break;
288 }
289 if (bytesread < 0) {
290 lua_pushnil(L);
291 lua_pushstring(L, tls_error(handle->tls));
292 return 2;
293 }
294 handle->tlshandshake = 1;
295 }
296 do bytesread = tls_read(handle->tls, handle->readbuf, MOONBR_IO_READBUFLEN);
297 while (!nonblocking && (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT));
298 if (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT) {
299 errno = EAGAIN;
300 break;
301 }
302 if (bytesread < 0) {
303 lua_pushnil(L);
304 lua_pushstring(L, tls_error(handle->tls));
305 return 2;
306 }
307 } while (0);
308 }
309 else
310 #endif
311 do bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
312 while (bytesread < 0 && (errno == EINTR));
313 if (
314 bytesread == 0 || (
315 nonblocking &&
316 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
317 )
318 ) {
319 handle->readbufin = 0;
320 if (!drain) luaL_pushresult(&luabuf);
321 else lua_pushinteger(L, luabufcnt);
322 if (bytesread == 0) lua_pushliteral(L, "eof");
323 else lua_pushliteral(L, "block");
324 handle->readerr = 0;
325 return 2;
326 }
327 if (bytesread < 0) moonbr_io_return_errmsg();
328 handle->readbufin = bytesread;
329 }
330 }
332 static int moonbr_io_read(lua_State *L) {
333 return moonbr_io_read_impl(L, 0, 0);
334 }
336 static int moonbr_io_read_nb(lua_State *L) {
337 return moonbr_io_read_impl(L, 1, 0);
338 }
340 static int moonbr_io_drain(lua_State *L) {
341 return moonbr_io_read_impl(L, 0, 1);
342 }
344 static int moonbr_io_drain_nb(lua_State *L) {
345 return moonbr_io_read_impl(L, 1, 1);
346 }
348 #if LUA_VERSION_NUM >= 503
349 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
350 #else
351 static int moonbr_io_read_cont(lua_State *L) {
352 #endif
353 lua_Integer remaining;
354 size_t len;
355 #if !(LUA_VERSION_NUM >= 503)
356 int ctx = 0;
357 lua_getctx(L, &ctx);
358 #endif
359 remaining = lua_tointeger(L, 3);
360 while (1) {
361 lua_pushcfunction(L, moonbr_io_read_nb);
362 lua_pushvalue(L, 1);
363 lua_pushvalue(L, 3);
364 lua_pushvalue(L, 4);
365 lua_call(L, 3, 2);
366 if (lua_isnil(L, -2)) return 2;
367 lua_insert(L, -2);
368 len = lua_rawlen(L, -1);
369 if (ctx == 0) {
370 lua_replace(L, 5);
371 ctx = 1;
372 } else if (ctx == 1) {
373 lua_pushvalue(L, 5);
374 lua_newtable(L);
375 lua_replace(L, 5);
376 lua_rawseti(L, 5, 1);
377 lua_rawseti(L, 5, 2);
378 ctx = 2;
379 } else {
380 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
381 }
382 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
383 lua_pop(L, 1);
384 if (remaining >= 0 && len) {
385 remaining -= len;
386 lua_pushinteger(L, remaining);
387 lua_replace(L, 3);
388 }
389 lua_pushvalue(L, 2);
390 lua_pushvalue(L, 1);
391 lua_pushliteral(L, "r");
392 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
393 lua_callk(L, 3, 0, ctx, moonbr_io_read_cont);
394 }
395 if (ctx != 1) {
396 luaL_Buffer buf;
397 lua_Integer i, chunkcount;
398 chunkcount = lua_rawlen(L, 5);
399 luaL_buffinit(L, &buf);
400 for (i=1; i<=chunkcount && i>0; i++) {
401 lua_rawgeti(L, 5, i);
402 luaL_addvalue(&buf);
403 }
404 luaL_pushresult(&buf);
405 lua_pushvalue(L, -2);
406 }
407 return 2;
408 }
410 static int moonbr_io_read_call(lua_State *L) {
411 lua_settop(L, 4);
412 lua_pushnil(L);
413 #if LUA_VERSION_NUM >= 503
414 return moonbr_io_read_cont(L, 0, 0);
415 #else
416 return moonbr_io_read_cont(L);
417 #endif
418 }
420 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
422 #if LUA_VERSION_NUM >= 503
423 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
424 #else
425 static int moonbr_io_drain_cont(lua_State *L) {
426 #endif
427 lua_Integer remaining, len;
428 size_t totallen = 0;
429 #if !(LUA_VERSION_NUM >= 503)
430 int ctx = 0;
431 lua_getctx(L, &ctx);
432 #endif
433 remaining = lua_tointeger(L, 3);
434 while (1) {
435 lua_pushcfunction(L, moonbr_io_drain_nb);
436 lua_pushvalue(L, 1);
437 lua_pushvalue(L, 3);
438 lua_pushvalue(L, 4);
439 lua_call(L, 3, 2);
440 if (lua_isnil(L, -2)) return 2;
441 lua_insert(L, -2);
442 len = lua_tointeger(L, -1);
443 lua_pop(L, 1);
444 totallen += len;
445 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
446 lua_pop(L, 1);
447 if (remaining >= 0 && len) {
448 remaining -= len;
449 lua_pushinteger(L, remaining);
450 lua_replace(L, 3);
451 }
452 lua_pushvalue(L, 2);
453 lua_pushvalue(L, 1);
454 lua_pushliteral(L, "r");
455 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
456 lua_callk(L, 3, 0, ctx, moonbr_io_drain_cont);
457 }
458 lua_pushinteger(L, totallen);
459 lua_pushvalue(L, -2);
460 return 2;
461 }
463 static int moonbr_io_drain_call(lua_State *L) {
464 #if LUA_VERSION_NUM >= 503
465 return moonbr_io_drain_cont(L, 0, 0);
466 #else
467 return moonbr_io_drain_cont(L);
468 #endif
469 }
471 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
473 #ifdef MOONBR_IO_USE_TLS
475 #define moonbr_io_write_tls(buf, buflen) \
476 if (handle->tls) { \
477 do { \
478 if (!handle->tlshandshake) { \
479 do written = tls_handshake(handle->tls); \
480 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
481 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
482 handle->tlshandshake = written; \
483 errno = EAGAIN; \
484 break; \
485 } \
486 if (written < 0) { \
487 lua_pushnil(L); \
488 lua_pushstring(L, tls_error(handle->tls)); \
489 return 2; \
490 } \
491 handle->tlshandshake = 1; \
492 } \
493 do written = tls_write(handle->tls, (buf), (buflen)); \
494 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
495 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
496 errno = EAGAIN; \
497 break; \
498 } \
499 if (written < 0) { \
500 lua_pushnil(L); \
501 lua_pushstring(L, tls_error(handle->tls)); \
502 return 2; \
503 } \
504 } while (0); \
505 } \
506 else
508 #endif /* MOONBR_IO_USE_TLS */
510 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
511 moonbr_io_handle_t *handle;
512 int i, top;
513 const char *str;
514 size_t strlen;
515 ssize_t written;
516 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
517 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
518 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
519 if (handle->writeerr) {
520 lua_pushnil(L);
521 lua_pushliteral(L, "Previous write error");
522 return 2;
523 }
524 handle->writeerr = 1;
525 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
526 top = lua_gettop(L);
527 lua_getuservalue(L, 1);
528 lua_getfield(L, -1, "writequeue");
529 for (i=2; i<=top; i++) {
530 luaL_checklstring(L, i, &strlen);
531 lua_pushvalue(L, i);
532 lua_rawseti(L, -2, handle->writeqin++);
533 handle->writeleft += strlen;
534 }
535 if (flush) handle->flushedleft = handle->writeleft;
536 while (handle->writeqout != handle->writeqin) {
537 lua_rawgeti(L, -1, handle->writeqout);
538 str = lua_tolstring(L, -1, &strlen);
539 while (handle->writeqoff < strlen) {
540 if (
541 strlen - handle->writeqoff <
542 MOONBR_IO_WRITEBUFLEN - handle->writebufin
543 ) {
544 memcpy(
545 handle->writebuf + handle->writebufin,
546 str + handle->writeqoff,
547 strlen - handle->writeqoff
548 );
549 handle->writebufin += strlen - handle->writeqoff;
550 break;
551 } else {
552 memcpy(
553 handle->writebuf + handle->writebufin,
554 str + handle->writeqoff,
555 MOONBR_IO_WRITEBUFLEN - handle->writebufin
556 );
557 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
558 handle->writebufin = MOONBR_IO_WRITEBUFLEN;
559 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
560 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
561 #ifdef MOONBR_IO_USE_TLS
562 moonbr_io_write_tls(
563 handle->writebuf + handle->writebufout,
564 MOONBR_IO_WRITEBUFLEN - handle->writebufout
565 )
566 #endif
567 written = write(
568 handle->fd,
569 handle->writebuf + handle->writebufout,
570 MOONBR_IO_WRITEBUFLEN - handle->writebufout
571 );
572 if (written < 0) {
573 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
574 goto moonbr_io_write_impl_block;
575 } else if (errno != EINTR) moonbr_io_return_errmsg();
576 } else {
577 handle->writebufout += written;
578 handle->writeleft -= written;
579 if (handle->flushedleft) {
580 if (written >= handle->flushedleft) {
581 handle->flushedleft = 0;
582 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
583 } else {
584 handle->flushedleft -= written;
585 }
586 }
587 }
588 }
589 handle->writebufin = 0;
590 handle->writebufout = 0;
591 }
592 }
593 handle->writeqoff = 0;
594 lua_pop(L, 1);
595 lua_pushnil(L);
596 lua_rawseti(L, -2, handle->writeqout++);
597 }
598 while (handle->flushedleft) {
599 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
600 #ifdef MOONBR_IO_USE_TLS
601 moonbr_io_write_tls(
602 handle->writebuf + handle->writebufout,
603 handle->writebufin - handle->writebufout
604 )
605 #endif
606 written = write(
607 handle->fd,
608 handle->writebuf + handle->writebufout,
609 handle->writebufin - handle->writebufout
610 );
611 if (written < 0) {
612 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
613 goto moonbr_io_write_impl_block;
614 } else if (errno != EINTR) moonbr_io_return_errmsg();
615 } else {
616 handle->writebufout += written;
617 handle->writeleft -= written;
618 if (handle->flushedleft) {
619 if (written >= handle->flushedleft) {
620 handle->flushedleft = 0;
621 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
622 } else {
623 handle->flushedleft -= written;
624 }
625 }
626 }
627 }
628 if (handle->writebufout == handle->writebufin) {
629 handle->writebufin = 0;
630 handle->writebufout = 0;
631 }
632 if (nonblocking) lua_pushinteger(L, 0);
633 else lua_pushvalue(L, 1);
634 handle->writeerr = 0;
635 return 1;
636 moonbr_io_write_impl_block:
637 lua_pushinteger(L, handle->writeleft);
638 handle->writeerr = 0;
639 return 1;
640 }
642 static int moonbr_io_write(lua_State *L) {
643 return moonbr_io_write_impl(L, 0, 0);
644 }
646 static int moonbr_io_write_nb(lua_State *L) {
647 return moonbr_io_write_impl(L, 1, 0);
648 }
650 static int moonbr_io_flush(lua_State *L) {
651 return moonbr_io_write_impl(L, 0, 1);
652 }
654 static int moonbr_io_flush_nb(lua_State *L) {
655 return moonbr_io_write_impl(L, 1, 1);
656 }
658 #if LUA_VERSION_NUM >= 503
659 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
660 #else
661 static int moonbr_io_write_cont(lua_State *L) {
662 #endif
663 while (1) {
664 lua_pushcfunction(L, moonbr_io_write_nb);
665 lua_pushvalue(L, 1);
666 lua_call(L, 1, 2);
667 if (lua_isnil(L, -2)) return 2;
668 if (!lua_tointeger(L, -2)) {
669 lua_pushvalue(L, 1);
670 return 1;
671 }
672 lua_pop(L, 2);
673 lua_pushvalue(L, 2);
674 lua_pushvalue(L, 1);
675 lua_pushliteral(L, "w");
676 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
677 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
678 }
679 }
681 static int moonbr_io_write_call(lua_State *L) {
682 lua_pushcfunction(L, moonbr_io_write_nb);
683 lua_insert(L, 3);
684 lua_pushvalue(L, 1);
685 lua_insert(L, 4);
686 lua_call(L, lua_gettop(L) - 3, 2);
687 if (lua_isnil(L, -2)) return 2;
688 if (!lua_tointeger(L, -2)) {
689 lua_pushvalue(L, 1);
690 return 1;
691 }
692 #if LUA_VERSION_NUM >= 503
693 return moonbr_io_write_cont(L, 0, 0);
694 #else
695 return moonbr_io_write_cont(L);
696 #endif
697 }
699 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
701 static int moonbr_io_flush_call(lua_State *L) {
702 lua_pushcfunction(L, moonbr_io_flush_nb);
703 lua_insert(L, 3);
704 lua_pushvalue(L, 1);
705 lua_insert(L, 4);
706 lua_call(L, lua_gettop(L) - 3, 2);
707 if (lua_isnil(L, -2)) return 2;
708 if (!lua_tointeger(L, -2)) {
709 lua_pushvalue(L, 1);
710 return 1;
711 }
712 #if LUA_VERSION_NUM >= 503
713 return moonbr_io_write_cont(L, 0, 0);
714 #else
715 return moonbr_io_write_cont(L);
716 #endif
717 }
719 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
721 static int moonbr_io_finish(lua_State *L) {
722 moonbr_io_handle_t *handle;
723 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
724 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
725 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
726 if (handle->writeleft) {
727 lua_pushcfunction(L, moonbr_io_flush);
728 lua_pushvalue(L, 1);
729 if (lua_pcall(L, 1, 2, 0)) {
730 handle->finished = 1;
731 lua_error(L);
732 }
733 if (!lua_toboolean(L, -2)) {
734 handle->finished = 1;
735 return 2;
736 }
737 }
738 handle->finished = 1;
739 #ifdef MOONBR_IO_USE_TLS
740 if ((handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) && !handle->tls) {
741 #else
742 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
743 #endif
744 if (shutdown(handle->fd, SHUT_WR)) moonbr_io_return_errmsg();
745 } else {
746 #ifdef MOONBR_IO_USE_TLS
747 if (handle->tls) {
748 int status;
749 if (moonbr_io_handle_set_nonblocking(L, handle, 1)) moonbr_io_return_errmsg();
750 do status = tls_close(handle->tls);
751 while (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT);
752 if (status) {
753 close(handle->fd);
754 handle->fd = -1;
755 lua_pushnil(L);
756 lua_pushstring(L, tls_error(handle->tls));
757 return 2;
758 }
759 }
760 #endif
761 if (close(handle->fd)) {
762 handle->fd = -1;
763 moonbr_io_return_errmsg();
764 }
765 handle->fd = -1; /* fake EOF on read */
766 }
767 lua_pushboolean(L, 1);
768 return 1;
769 }
771 static int moonbr_io_close_impl(lua_State *L, int nonblocking, int reset) {
772 moonbr_io_handle_t *handle;
773 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
774 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
775 if (!reset && handle->fd >= 0) {
776 if (handle->writeleft) {
777 lua_pushcfunction(L, nonblocking ? moonbr_io_flush_nb : moonbr_io_flush);
778 lua_pushvalue(L, 1);
779 if (lua_pcall(L, 1, 2, 0)) {
780 handle->closed = 1;
781 close(handle->fd);
782 handle->fd = -1;
783 lua_error(L);
784 }
785 if (!nonblocking) handle->closed = 1; /* TODO: handle nonblocking case */
786 if (!lua_toboolean(L, -2)) {
787 close(handle->fd);
788 handle->fd = -1;
789 return 2;
790 }
791 #if LUA_VERSION_NUM >= 503
792 if (nonblocking && lua_tointeger(L, -2)) {
793 #else
794 if (nonblocking && lua_tonumber(L, -2)) {
795 #endif
796 lua_pushliteral(L, "flush");
797 lua_pushvalue(L, -3);
798 return 2;
799 }
800 } else {
801 handle->closed = 1;
802 }
803 #ifdef MOONBR_IO_USE_TLS
804 if (handle->tls) {
805 int status;
806 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
807 do status = tls_close(handle->tls);
808 while (!nonblocking && (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT));
809 if (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT) {
810 handle->tlsclosing = status; /* TODO: handle polling */
811 lua_pushliteral(L, "close");
812 return 1;
813 }
814 if (status) {
815 close(handle->fd);
816 handle->fd = -1;
817 lua_pushnil(L);
818 lua_pushstring(L, tls_error(handle->tls));
819 return 2;
820 }
821 }
822 #endif
823 if (moonbr_io_handle_set_linger(L, handle, -1)) {
824 moonbr_io_prepare_errmsg();
825 close(handle->fd);
826 handle->fd = -1;
827 moonbr_io_return_prepared_errmsg();
828 }
829 } else {
830 handle->closed = 1;
831 }
832 if (handle->fd >= 0) {
833 if (close(handle->fd)) {
834 handle->fd = -1;
835 moonbr_io_return_errmsg();
836 }
837 handle->fd = -1;
838 }
839 lua_pushboolean(L, 1);
840 return 1;
842 }
844 static int moonbr_io_close(lua_State *L) {
845 return moonbr_io_close_impl(L, 0, 0);
846 }
848 static int moonbr_io_reset(lua_State *L) {
849 return moonbr_io_close_impl(L, 0, 1);
850 }
852 static int moonbr_io_handlegc(lua_State *L) {
853 moonbr_io_handle_t *handle;
854 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
855 if (handle->fd >= 0) {
856 lua_pushcfunction(L, moonbr_io_reset);
857 lua_pushvalue(L, 1);
858 lua_pushinteger(L, 0);
859 lua_call(L, 2, 0);
860 }
861 #ifdef MOONBR_IO_USE_TLS
862 if (handle->tls) {
863 tls_free(handle->tls);
864 handle->tls = NULL;
865 }
866 if (handle->servertls) {
867 tls_free(handle->servertls);
868 handle->servertls = NULL;
869 }
870 #endif
871 return 0;
872 }
874 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
875 moonbr_io_handle_t *handle;
876 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
877 if (!handle->closed) {
878 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
879 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
880 lua_call(L, 1, 0);
881 }
882 }
884 static int moonbr_io_pushhandle_impl(lua_State *L) {
885 int *fd;
886 int skip_peeraddr;
887 moonbr_io_handle_t *handle;
888 struct sockaddr addr;
889 socklen_t addrlen;
890 fd = lua_touserdata(L, 1);
891 skip_peeraddr = lua_toboolean(L, 2);
892 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
893 handle->fd = -1; /* avoid closing incomplete handle */
894 addrlen = sizeof(addr);
895 if (getsockname(*fd, &addr, &addrlen)) {
896 if (errno != ENOTSOCK) {
897 moonbr_io_prepare_errmsg();
898 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
899 }
900 handle->issock = 0;
901 } else {
902 handle->issock = 1;
903 handle->addrfam = addr.sa_family;
904 }
905 handle->finished = 0;
906 handle->closed = 0;
907 handle->nonblocking = -1;
908 handle->nopush = -1;
909 handle->readerr = 0;
910 handle->readbufin = 0;
911 handle->readbufout = 0;
912 handle->writeerr = 0;
913 handle->writeleft = 0;
914 handle->flushedleft = 0;
915 handle->writeqin = 0;
916 handle->writeqout = 0;
917 handle->writeqoff = 0;
918 handle->writebufin = 0;
919 handle->writebufout = 0;
920 #ifdef MOONBR_IO_USE_TLS
921 handle->tls = NULL;
922 handle->servertls = NULL;
923 handle->tlshandshake = 0;
924 handle->tlsclosing = 0;
925 #endif
926 handle->fd = *fd; /* required for set_linger call */
927 if (moonbr_io_handle_set_linger(L, handle, 0)) {
928 moonbr_io_prepare_errmsg();
929 handle->fd = -1;
930 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
931 }
932 handle->fd = -1; /* avoid closing incomplete handle */
933 luaL_setmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
934 lua_newtable(L); // uservalue
935 lua_newtable(L);
936 lua_setfield(L, -2, "writequeue");
937 lua_newtable(L); // public
938 if (handle->addrfam == AF_INET6) {
939 struct sockaddr_in6 addr_in6;
940 char addrstrbuf[INET6_ADDRSTRLEN];
941 const char *addrstr;
942 addrlen = sizeof(addr_in6);
943 /* NOTE: According to documentation, getsockname() may fail if connection
944 * was reset. There seems to be no problem in practice though. */
945 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
946 moonbr_io_prepare_errmsg();
947 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
948 }
949 if (addrlen > sizeof(addr_in6)) {
950 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
951 }
952 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
953 if (!addrstr) {
954 moonbr_io_prepare_errmsg();
955 luaL_error(L, "Could not format local IP address: %s", errmsg);
956 } else {
957 lua_pushstring(L, addrstr);
958 lua_setfield(L, -2, "local_ip6");
959 }
960 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
961 lua_setfield(L, -2, "local_tcpport");
962 if (!skip_peeraddr) {
963 /* NOTE: According to documentation, getpeername() may fail if connection
964 * was reset. There seems to be no problem in practice though. */
965 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
966 moonbr_io_prepare_errmsg();
967 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
968 }
969 if (addrlen > sizeof(addr_in6)) {
970 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
971 }
972 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
973 if (!addrstr) {
974 moonbr_io_prepare_errmsg();
975 luaL_error(L, "Could not format remote IP address: %s", errmsg);
976 } else {
977 lua_pushstring(L, addrstr);
978 lua_setfield(L, -2, "remote_ip6");
979 }
980 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
981 lua_setfield(L, -2, "remote_tcpport");
982 }
983 } else if (handle->addrfam == AF_INET) {
984 struct sockaddr_in addr_in;
985 char addrstrbuf[INET_ADDRSTRLEN];
986 const char *addrstr;
987 addrlen = sizeof(addr_in);
988 /* NOTE: According to documentation, getsockname() may fail if connection
989 * was reset. There seems to be no problem in practice though. */
990 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
991 moonbr_io_prepare_errmsg();
992 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
993 }
994 if (addrlen > sizeof(addr_in)) {
995 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
996 }
997 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
998 if (!addrstr) {
999 moonbr_io_prepare_errmsg();
1000 luaL_error(L, "Could not format local IP address: %s", errmsg);
1001 } else {
1002 lua_pushstring(L, addrstr);
1003 lua_setfield(L, -2, "local_ip4");
1005 lua_pushinteger(L, ntohs(addr_in.sin_port));
1006 lua_setfield(L, -2, "local_tcpport");
1007 if (!skip_peeraddr) {
1008 /* NOTE: According to documentation, getpeername() may fail if connection
1009 * was reset. There seems to be no problem in practice though. */
1010 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
1011 moonbr_io_prepare_errmsg();
1012 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
1014 if (addrlen > sizeof(addr_in)) {
1015 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
1017 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
1018 if (!addrstr) {
1019 moonbr_io_prepare_errmsg();
1020 luaL_error(L, "Could not format remote IP address: %s", errmsg);
1021 } else {
1022 lua_pushstring(L, addrstr);
1023 lua_setfield(L, -2, "remote_ip4");
1025 lua_pushinteger(L, ntohs(addr_in.sin_port));
1026 lua_setfield(L, -2, "remote_tcpport");
1029 luaL_setmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1030 lua_setfield(L, -2, "public");
1031 lua_setuservalue(L, -2);
1032 handle->fd = *fd;
1033 *fd = -1; /* closing is now handled by garbage collection */
1034 return 1;
1037 void moonbr_io_pushhandle(lua_State *L, int fd) {
1038 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1039 lua_pushlightuserdata(L, &fd);
1040 if (lua_pcall(L, 1, 1, 0)) {
1041 if (fd != -1) close(fd); // TODO: correct to close file descriptor here?
1042 lua_error(L);
1046 void moonbr_io_pushhandle_skip_peeraddr(lua_State *L, int fd) {
1047 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1048 lua_pushlightuserdata(L, &fd);
1049 lua_pushboolean(L, 1);
1050 if (lua_pcall(L, 2, 1, 0)) {
1051 if (fd != -1) close(fd); // TODO: correct to close file descriptor here?
1052 lua_error(L);
1056 static int moonbr_io_handleindex(lua_State *L) {
1057 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1058 luaL_checkany(L, 2);
1059 lua_getuservalue(L, 1);
1060 lua_getfield(L, -1, "public");
1061 lua_pushvalue(L, 2);
1062 lua_gettable(L, -2);
1063 return 1;
1066 static int moonbr_io_handlenewindex(lua_State *L) {
1067 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1068 luaL_checkany(L, 2);
1069 luaL_checkany(L, 3);
1070 lua_getuservalue(L, 1);
1071 lua_getfield(L, -1, "public");
1072 lua_pushvalue(L, 2);
1073 lua_pushvalue(L, 3);
1074 lua_settable(L, -3);
1075 return 0;
1078 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
1079 const char *path;
1080 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1081 const int path_maxlen = sizeof(struct sockaddr_un) - (
1082 (void *)sockaddr.sun_path - (void *)&sockaddr
1083 ) - 1; /* one byte for termination */
1084 int sock;
1085 path = luaL_checkstring(L, 1);
1086 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1087 strcpy(sockaddr.sun_path, path);
1088 sock = socket(
1089 PF_LOCAL,
1090 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1092 );
1093 if (sock < 0) moonbr_io_return_errmsg();
1094 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1095 if (!nonblocking && errno == EINTR) {
1096 moonbr_io_prepare_errmsg();
1097 close(sock);
1098 moonbr_io_return_prepared_errmsg();
1099 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1101 moonbr_io_pushhandle(L, sock);
1102 return 1;
1105 static int moonbr_io_localconnect(lua_State *L) {
1106 return moonbr_io_localconnect_impl(L, 0);
1109 static int moonbr_io_localconnect_nb(lua_State *L) {
1110 return moonbr_io_localconnect_impl(L, 1);
1113 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
1114 const char *host, *port;
1115 struct addrinfo hints = { 0, };
1116 struct addrinfo *res, *addrinfo;
1117 int errcode;
1118 int sock;
1119 host = luaL_checkstring(L, 1);
1120 port = luaL_checkstring(L, 2);
1121 hints.ai_family = AF_UNSPEC;
1122 hints.ai_socktype = SOCK_STREAM;
1123 hints.ai_protocol = IPPROTO_TCP;
1124 hints.ai_flags = AI_ADDRCONFIG;
1125 errcode = getaddrinfo(host, port, &hints, &res);
1126 if (errcode) {
1127 freeaddrinfo(res);
1128 if (errcode == EAI_SYSTEM) {
1129 moonbr_io_prepare_errmsg();
1130 lua_pushnil(L);
1131 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1132 } else {
1133 lua_pushnil(L);
1134 lua_pushstring(L, gai_strerror(errcode));
1136 return 2;
1138 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1139 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1141 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1142 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1144 addrinfo = res;
1145 moonbr_io_tcpconnect_found:
1146 sock = socket(
1147 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1148 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1149 addrinfo->ai_protocol
1150 );
1151 if (sock < 0) {
1152 moonbr_io_prepare_errmsg();
1153 freeaddrinfo(res);
1154 moonbr_io_return_prepared_errmsg();
1156 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1157 freeaddrinfo(res);
1158 if (!nonblocking && errno == EINTR) {
1159 moonbr_io_prepare_errmsg();
1160 close(sock);
1161 moonbr_io_return_prepared_errmsg();
1162 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1163 } else {
1164 freeaddrinfo(res);
1166 if (nonblocking) {
1167 moonbr_io_pushhandle_skip_peeraddr(L, sock);
1168 if (addrinfo->ai_family == AF_INET6) {
1169 // TODO: fill remote_ip6 and remote_tcpport
1170 } else if (addrinfo->ai_family == AF_INET) {
1171 // TODO: fill remote_ip4 and remote_tcpport
1173 } else {
1174 moonbr_io_pushhandle(L, sock);
1176 return 1;
1179 static int moonbr_io_tcpconnect(lua_State *L) {
1180 return moonbr_io_tcpconnect_impl(L, 0);
1183 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1184 return moonbr_io_tcpconnect_impl(L, 1);
1187 static int moonbr_io_locallisten(lua_State *L) {
1188 moonbr_io_listener_t *listener;
1189 const char *path;
1190 struct stat sb;
1191 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1192 const int path_maxlen = sizeof(struct sockaddr_un) - (
1193 (void *)sockaddr.sun_path - (void *)&sockaddr
1194 ) - 1; /* one byte for termination */
1195 int sock;
1196 path = luaL_checkstring(L, 1);
1197 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1198 strcpy(sockaddr.sun_path, path);
1199 if (stat(path, &sb) == 0) {
1200 if (S_ISSOCK(sb.st_mode)) unlink(path);
1202 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1203 listener->fd = -1;
1204 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1205 sock = socket(
1206 PF_LOCAL,
1207 SOCK_STREAM | SOCK_CLOEXEC,
1209 );
1210 if (sock < 0) moonbr_io_return_errmsg();
1211 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1212 moonbr_io_prepare_errmsg();
1213 close(sock);
1214 moonbr_io_return_prepared_errmsg();
1216 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1217 moonbr_io_prepare_errmsg();
1218 close(sock);
1219 moonbr_io_return_prepared_errmsg();
1221 listener->fd = sock;
1222 listener->addrfam = AF_LOCAL;
1223 listener->nonblocking = -1;
1224 return 1;
1227 static int moonbr_io_tcplisten(lua_State *L) {
1228 moonbr_io_listener_t *listener;
1229 const char *host, *port;
1230 struct addrinfo hints = { 0, };
1231 struct addrinfo *res, *addrinfo;
1232 int errcode;
1233 int sock;
1234 host = luaL_optstring(L, 1, NULL);
1235 port = luaL_checkstring(L, 2);
1236 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1237 listener->fd = -1;
1238 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1239 hints.ai_family = AF_UNSPEC;
1240 hints.ai_socktype = SOCK_STREAM;
1241 hints.ai_protocol = IPPROTO_TCP;
1242 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1243 errcode = getaddrinfo(host, port, &hints, &res);
1244 if (errcode) {
1245 freeaddrinfo(res);
1246 if (errcode == EAI_SYSTEM) {
1247 moonbr_io_prepare_errmsg();
1248 lua_pushnil(L);
1249 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1250 } else {
1251 lua_pushnil(L);
1252 lua_pushstring(L, gai_strerror(errcode));
1254 return 2;
1256 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1257 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1259 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1260 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1262 addrinfo = res;
1263 moonbr_io_tcpconnect_found:
1264 listener->addrfam = addrinfo->ai_family;
1265 sock = socket(
1266 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1267 addrinfo->ai_socktype | SOCK_CLOEXEC,
1268 addrinfo->ai_protocol
1269 );
1270 if (sock < 0) {
1271 moonbr_io_prepare_errmsg();
1272 freeaddrinfo(res);
1273 moonbr_io_return_prepared_errmsg();
1276 static const int reuseval = 1;
1277 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1278 moonbr_io_prepare_errmsg();
1279 freeaddrinfo(res);
1280 close(sock);
1281 lua_pushnil(L);
1282 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1283 return 2;
1286 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1287 moonbr_io_prepare_errmsg();
1288 freeaddrinfo(res);
1289 close(sock);
1290 moonbr_io_return_prepared_errmsg();
1292 freeaddrinfo(res);
1293 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1294 moonbr_io_prepare_errmsg();
1295 close(sock);
1296 moonbr_io_return_prepared_errmsg();
1298 listener->fd = sock;
1299 listener->nonblocking = -1;
1300 return 1;
1303 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1304 moonbr_io_listener_t *listener;
1305 int fd;
1306 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1307 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1308 if (listener->nonblocking != nonblocking) {
1309 int flags;
1310 flags = fcntl(listener->fd, F_GETFL, 0);
1311 if (flags == -1) {
1312 moonbr_io_prepare_errmsg();
1313 close(listener->fd);
1314 listener->fd = -1;
1315 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1317 if (nonblocking) flags |= O_NONBLOCK;
1318 else flags &= ~O_NONBLOCK;
1319 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1320 moonbr_io_prepare_errmsg();
1321 close(listener->fd);
1322 listener->fd = -1;
1323 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1325 listener->nonblocking = nonblocking;
1327 while (1) {
1328 #if defined(__linux__) && !defined(_GNU_SOURCE)
1329 fd = accept(listener->fd, NULL, NULL);
1330 if (fd != -1) {
1331 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1332 moonbr_io_prepare_errmsg();
1333 close(listener->fd);
1334 listener->fd = -1;
1335 close(fd);
1336 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1339 #else
1340 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1341 #endif
1342 if (fd < 0) {
1343 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1344 lua_pushboolean(L, 0);
1345 lua_pushliteral(L, "No incoming connection pending");
1346 return 2;
1347 } else if (errno != EINTR) moonbr_io_return_errmsg();
1348 } else {
1349 moonbr_io_pushhandle(L, fd);
1350 return 1;
1355 static int moonbr_io_accept(lua_State *L) {
1356 return moonbr_io_accept_impl(L, 0);
1359 static int moonbr_io_accept_nb(lua_State *L) {
1360 return moonbr_io_accept_impl(L, 1);
1363 static int moonbr_io_unlisten(lua_State *L) {
1364 moonbr_io_listener_t *listener;
1365 struct sockaddr_un addr;
1366 socklen_t addrlen;
1367 struct stat sb;
1368 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1369 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1370 addrlen = sizeof(addr);
1371 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1372 if (close(listener->fd)) {
1373 moonbr_io_prepare_errmsg();
1374 listener->fd = -1;
1375 if (addrlen && addrlen <= sizeof(addr)) {
1376 if (stat(addr.sun_path, &sb) == 0) {
1377 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1380 moonbr_io_return_prepared_errmsg();
1382 listener->fd = -1;
1383 if (addrlen && addrlen <= sizeof(addr)) {
1384 if (stat(addr.sun_path, &sb) == 0) {
1385 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1388 lua_pushboolean(L, 1);
1389 return 1;
1392 static int moonbr_io_listenergc(lua_State *L) {
1393 moonbr_io_listener_t *listener;
1394 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1395 if (listener->fd >= 0) close(listener->fd);
1396 listener->fd = -1;
1397 return 0;
1400 static int moonbr_io_exec(lua_State *L) {
1401 char **argv;
1402 int i, argc;
1403 int sockin[2], sockout[2], sockerr[2];
1404 volatile int errorcond = 0;
1405 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
1406 moonbr_io_child_t *child;
1407 argc = lua_gettop(L);
1408 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1409 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1410 argv[argc] = NULL;
1411 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1412 child->pid = 0;
1413 child->status_valid = 0;
1414 lua_newtable(L);
1415 lua_setuservalue(L, -2);
1416 luaL_setmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1417 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
1418 moonbr_io_prepare_errmsg();
1419 lua_pushnil(L);
1420 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1421 return 2;
1423 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
1424 moonbr_io_prepare_errmsg();
1425 close(sockin[0]);
1426 close(sockin[1]);
1427 lua_pushnil(L);
1428 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1429 return 2;
1431 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
1432 moonbr_io_prepare_errmsg();
1433 close(sockin[0]);
1434 close(sockin[1]);
1435 close(sockout[0]);
1436 close(sockout[1]);
1437 lua_pushnil(L);
1438 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1439 return 2;
1441 child->pid = vfork();
1442 if (child->pid == -1) {
1443 moonbr_io_prepare_errmsg();
1444 close(sockin[0]);
1445 close(sockin[1]);
1446 close(sockout[0]);
1447 close(sockout[1]);
1448 close(sockerr[0]);
1449 close(sockerr[1]);
1450 lua_pushnil(L);
1451 lua_pushfstring(L, "Could not fork: %s", errmsg);
1452 return 2;
1454 if (!child->pid) {
1455 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
1456 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
1457 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
1458 closefrom(3);
1459 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1460 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1461 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1462 if (execvp(argv[0], argv)) {
1463 errorcond = 2;
1464 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1465 _exit(0);
1467 moonbr_io_exec_error1:
1468 errorcond = 1;
1469 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1470 _exit(0);
1472 close(sockin[1]);
1473 close(sockout[1]);
1474 close(sockerr[1]);
1475 if (errorcond) {
1476 int status;
1477 close(sockin[0]);
1478 close(sockout[0]);
1479 close(sockerr[0]);
1480 while (waitpid(child->pid, &status, 0) == -1) {
1481 if (errno != EINTR) {
1482 moonbr_io_prepare_errmsg();
1483 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1486 child->pid = 0;
1487 lua_pushnil(L);
1488 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1489 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1490 return 2;
1492 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1493 lua_pushlightuserdata(L, &sockin[0]);
1494 if (lua_pcall(L, 1, 1, 0)) {
1495 if (sockin[0] != -1) close(sockin[0]);
1496 close(sockout[0]);
1497 close(sockerr[0]);
1498 goto moonbr_io_exec_error2;
1500 lua_setfield(L, -2, "stdin");
1501 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1502 lua_pushlightuserdata(L, &sockout[0]);
1503 if (lua_pcall(L, 1, 1, 0)) {
1504 if (sockout[0] != -1) close(sockout[0]);
1505 close(sockerr[0]);
1506 goto moonbr_io_exec_error2;
1508 lua_setfield(L, -2, "stdout");
1509 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1510 lua_pushlightuserdata(L, &sockerr[0]);
1511 if (lua_pcall(L, 1, 1, 0)) {
1512 if (sockerr[0] != -1) close(sockerr[0]);
1513 goto moonbr_io_exec_error2;
1515 lua_setfield(L, -2, "stderr");
1516 return 1;
1517 moonbr_io_exec_error2:
1519 int status;
1520 while (waitpid(child->pid, &status, 0) == -1) {
1521 if (errno != EINTR) {
1522 moonbr_io_prepare_errmsg();
1523 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
1527 child->pid = 0;
1528 return lua_error(L);
1531 static int moonbr_io_childindex(lua_State *L) {
1532 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1533 luaL_checkany(L, 2);
1534 lua_getuservalue(L, 1);
1535 lua_pushvalue(L, 2);
1536 lua_gettable(L, -2);
1537 if (lua_isnil(L, -1)) {
1538 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1539 lua_pushvalue(L, 2);
1540 lua_gettable(L, -2);
1542 return 1;
1545 static int moonbr_io_childnewindex(lua_State *L) {
1546 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1547 luaL_checkany(L, 2);
1548 luaL_checkany(L, 3);
1549 lua_getuservalue(L, 1);
1550 lua_pushvalue(L, 2);
1551 lua_pushvalue(L, 3);
1552 lua_settable(L, -3);
1553 return 0;
1556 static int moonbr_io_childgc(lua_State *L) {
1557 moonbr_io_child_t *child;
1558 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1559 if (child->pid) {
1560 int status;
1561 int pid = child->pid;
1562 child->pid = 0;
1563 if (kill(pid, SIGKILL)) {
1564 moonbr_io_prepare_errmsg();
1565 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1567 while (waitpid(pid, &status, 0) == -1) {
1568 if (errno != EINTR) {
1569 moonbr_io_prepare_errmsg();
1570 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1574 return 0;
1577 static int moonbr_io_kill(lua_State *L) {
1578 moonbr_io_child_t *child;
1579 int sig;
1580 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1581 sig = luaL_optinteger(L, 2, SIGKILL);
1582 if (!child->pid) {
1583 if (!child->status_valid) luaL_error(L, "Attempt to kill an already collected child process");
1584 } else {
1585 if (kill(child->pid, sig)) {
1586 moonbr_io_prepare_errmsg();
1587 luaL_error(L, "Error in kill call: %s", errmsg);
1590 lua_settop(L, 1);
1591 return 1;
1594 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1595 moonbr_io_child_t *child;
1596 int status;
1597 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1598 if (!child->pid) {
1599 if (!child->status_valid) luaL_error(L, "Attempt to wait for an already collected child process");
1600 status = child->status;
1601 child->status_valid = 0;
1602 } else {
1603 pid_t waitedpid;
1604 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1605 if (errno != EINTR) {
1606 moonbr_io_prepare_errmsg();
1607 luaL_error(L, "Error in waitpid call: %s", errmsg);
1610 if (!waitedpid) {
1611 lua_pushboolean(L, 0);
1612 lua_pushliteral(L, "Process is still running");
1613 return 2;
1615 child->pid = 0;
1617 if (WIFEXITED(status)) {
1618 lua_pushinteger(L, WEXITSTATUS(status));
1619 } else if (WIFSIGNALED(status)) {
1620 lua_pushinteger(L, -WTERMSIG(status));
1621 } else {
1622 luaL_error(L, "Unexpected status value returned by waitpid call");
1624 return 1;
1627 static int moonbr_io_wait(lua_State *L) {
1628 return moonbr_io_wait_impl(L, 0);
1631 static int moonbr_io_wait_nb(lua_State *L) {
1632 return moonbr_io_wait_impl(L, 1);
1635 #if LUA_VERSION_NUM >= 503
1636 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1637 #else
1638 static int moonbr_io_wait_cont(lua_State *L) {
1639 #endif
1640 #if !(LUA_VERSION_NUM >= 503)
1641 int ctx = 0;
1642 lua_getctx(L, &ctx);
1643 #endif
1644 while (1) {
1645 lua_pushcfunction(L, moonbr_io_wait_nb);
1646 lua_pushvalue(L, 1);
1647 lua_call(L, 1, 1);
1648 if (!lua_isnil(L, -1)) break;
1649 lua_pushvalue(L, 2);
1650 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1652 return 1;
1655 static int moonbr_io_wait_call(lua_State *L) {
1656 lua_settop(L, 2);
1657 #if LUA_VERSION_NUM >= 503
1658 return moonbr_io_wait_cont(L, 0, 0);
1659 #else
1660 return moonbr_io_wait_cont(L);
1661 #endif
1664 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1666 static void moonbr_io_sigterm_handler(int sig) {
1667 moonbr_io_sigterm_flag = 1;
1670 static void moonbr_io_sigchld_handler(int sig) {
1671 moonbr_io_sigchld_flag = 1;
1674 int moonbr_io_catch_sigterm(lua_State *L) {
1675 signal(SIGTERM, moonbr_io_sigterm_handler);
1676 return 0;
1679 static int moonbr_io_getpid(lua_State *L) {
1680 lua_pushinteger(L, getpid());
1681 return 1;
1684 #ifdef MOONBR_IO_USE_TLS
1686 #define moonbr_io_poll_tls() \
1687 if (!handle->tlshandshake) { \
1688 force_wakeup = 1; \
1689 continue; \
1690 } \
1691 if (handle->tlshandshake == TLS_WANT_POLLIN) { \
1692 if (fd < 0) { \
1693 force_wakeup = 1; \
1694 continue; \
1695 } \
1696 FD_SET(fd, &readfds); \
1697 if (fd+1 > nfds) nfds = fd+1; \
1698 continue; \
1699 } \
1700 if (handle->tlshandshake == TLS_WANT_POLLOUT) { \
1701 if (fd < 0) { \
1702 force_wakeup = 1; \
1703 continue; \
1704 } \
1705 FD_SET(fd, &writefds); \
1706 if (fd+1 > nfds) nfds = fd+1; \
1707 continue; \
1708 } \
1709 while (0)
1711 #endif /* MOONBR_IO_USE_TLS */
1713 static int moonbr_io_poll(lua_State *L) {
1714 moonbr_io_handle_t *handle;
1715 moonbr_io_listener_t *listener;
1716 moonbr_io_child_t *child;
1717 int fd, isnum;
1718 int nfds = 0;
1719 fd_set readfds, writefds, exceptfds;
1720 struct timespec timeout = {0, };
1721 int force_wakeup = 0;
1722 int use_timeout = 0; // negative for negative timeout
1723 int check_sigterm = 0;
1724 int check_sigchld = 0;
1725 pid_t waitedpid;
1726 sigset_t mask, orig_mask;
1727 int status;
1728 FD_ZERO(&readfds);
1729 FD_ZERO(&writefds);
1730 FD_ZERO(&exceptfds);
1731 if (!lua_isnoneornil(L, 1)) {
1732 luaL_checktype(L, 1, LUA_TTABLE);
1733 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1734 if (lua_toboolean(L, -1)) {
1735 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1736 if (handle) {
1737 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1738 fd = handle->fd;
1739 #if MOONBR_IO_USE_TLS
1740 moonbr_io_poll_tls();
1741 #endif
1742 if (
1743 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1744 handle->readbufin != handle->readbufout /* data pending in buffer */
1745 ) {
1746 force_wakeup = 1;
1747 continue;
1749 } else {
1750 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1751 if (listener) {
1752 fd = listener->fd;
1753 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1754 } else {
1755 child = luaL_testudata(L, -2, MOONBR_IO_CHILD_MT_REGKEY);
1756 if (child) {
1757 if (!child->pid) luaL_error(L, "Attemt to poll an already collected child process");
1758 if (!check_sigchld) {
1759 check_sigchld = 1;
1760 moonbr_io_sigchld_flag = 0;
1761 signal(SIGCHLD, moonbr_io_sigchld_handler);
1763 if (child->status_valid) {
1764 force_wakeup = 1;
1765 } else {
1766 while ((waitedpid = waitpid(child->pid, &status, WNOHANG)) == -1) {
1767 if (errno != EINTR) {
1768 moonbr_io_prepare_errmsg();
1769 luaL_error(L, "Error in waitpid call: %s", errmsg);
1772 if (waitedpid) {
1773 child->pid = 0;
1774 child->status = status;
1775 child->status_valid = 1;
1776 force_wakeup = 1;
1779 continue;
1780 } else {
1781 fd = lua_tointegerx(L, -2, &isnum);
1782 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1786 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1787 FD_SET(fd, &readfds);
1788 if (fd+1 > nfds) nfds = fd+1;
1792 if (!lua_isnoneornil(L, 2)) {
1793 luaL_checktype(L, 2, LUA_TTABLE);
1794 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1795 if (lua_toboolean(L, -1)) {
1796 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1797 if (handle) {
1798 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1799 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1800 fd = handle->fd;
1801 #if MOONBR_IO_USE_TLS
1802 moonbr_io_poll_tls();
1803 #endif
1804 } else {
1805 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1806 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1807 fd = lua_tointegerx(L, -2, &isnum);
1808 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1810 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1811 FD_SET(fd, &writefds);
1812 if (fd+1 > nfds) nfds = fd+1;
1816 if (!lua_isnoneornil(L, 3)) {
1817 lua_Number n;
1818 n = lua_tonumberx(L, 3, &isnum);
1819 if (isnum && n<0) {
1820 use_timeout = -1;
1821 } else if (isnum && n>=0 && n<100000000) {
1822 use_timeout = 1;
1823 timeout.tv_sec = n;
1824 timeout.tv_nsec = 1e9 * (n - timeout.tv_sec);
1825 } else {
1826 luaL_argcheck(L, 0, 3, "not a valid timeout");
1829 if (use_timeout < 0) force_wakeup = 1;
1830 if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN);
1831 check_sigterm = lua_toboolean(L, 4);
1832 if ((check_sigterm || check_sigchld) && !force_wakeup) {
1833 sigemptyset(&mask);
1834 if (check_sigterm) sigaddset(&mask, SIGTERM);
1835 if (check_sigchld) sigaddset(&mask, SIGCHLD);
1836 if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort();
1838 if (check_sigterm && moonbr_io_sigterm_flag) {
1839 if (!force_wakeup) {
1840 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
1842 lua_pushboolean(L, 0);
1843 lua_pushliteral(L, "SIGTERM received");
1844 lua_pushboolean(L, 1);
1845 return 3;
1847 if (check_sigchld && !force_wakeup && moonbr_io_sigchld_flag) {
1848 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
1849 force_wakeup = 1;
1851 if (use_timeout < 0) {
1852 lua_pushboolean(L, 0);
1853 lua_pushliteral(L, "Timeout");
1854 if (check_sigterm) {
1855 lua_pushboolean(L, 0);
1856 return 3;
1857 } else {
1858 return 2;
1861 if (!force_wakeup) {
1862 status = pselect(
1863 nfds, &readfds, &writefds, &exceptfds,
1864 use_timeout ? &timeout : NULL,
1865 (check_sigterm || check_sigchld) ? &orig_mask : NULL
1866 );
1867 if (check_sigterm || check_sigchld) {
1868 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
1869 if (check_sigterm && moonbr_io_sigterm_flag) {
1870 lua_pushboolean(L, 0);
1871 lua_pushliteral(L, "SIGTERM received");
1872 lua_pushboolean(L, 1);
1873 return 3;
1876 if (status == -1) {
1877 if (errno == EINTR) {
1878 lua_pushboolean(L, 1);
1879 return 1;
1880 } else {
1881 moonbr_io_prepare_errmsg();
1882 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1884 } else if (status == 0) {
1885 lua_pushboolean(L, 0);
1886 lua_pushliteral(L, "Timeout");
1887 if (check_sigterm) {
1888 lua_pushboolean(L, 0);
1889 return 3;
1890 } else {
1891 return 2;
1895 lua_pushboolean(L, 1);
1896 return 1;
1899 static int moonbr_io_timeref(lua_State *L) {
1900 lua_Number sub;
1901 struct timespec tp;
1902 sub = luaL_optnumber(L, 1, 0);
1903 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1904 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1906 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1907 return 1;
1910 #ifdef MOONBR_IO_USE_TLS
1912 #define moonbr_io_tlsconf_string(name, field, func) \
1913 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1914 lua_getfield(L, 1, (field)); \
1915 valuetype = lua_type(L, -1); \
1916 if (valuetype != LUA_TNIL) { \
1917 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1918 value = lua_tostring(L, -1); \
1919 if (func(tlsconf->config, value)) { \
1920 lua_pushnil(L); \
1921 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
1922 return 2; \
1923 } \
1924 } \
1925 lua_pop(L, 1);
1927 #define moonbr_io_tlsconf_binary(name, field, func) \
1928 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1929 lua_getfield(L, 1, (field)); \
1930 valuetype = lua_type(L, -1); \
1931 if (valuetype != LUA_TNIL) { \
1932 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1933 value = lua_tolstring(L, -1, &valuelen); \
1934 if (func(tlsconf->config, (void *)value, valuelen)) { \
1935 lua_pushnil(L); \
1936 lua_pushliteral(L, "Could not set " name); \
1937 return 2; \
1938 } \
1939 } \
1940 lua_pop(L, 1);
1942 static int moonbr_io_tlsconf(lua_State *L) {
1943 moonbr_io_tlsconf_t *tlsconf;
1944 int valuetype;
1945 const char *value;
1946 size_t valuelen;
1947 luaL_checktype(L, 1, LUA_TTABLE);
1948 tlsconf = lua_newuserdata(L, sizeof(moonbr_io_tlsconf_t));
1949 tlsconf->config = tls_config_new();
1950 if (!tlsconf->config) {
1951 return luaL_error(L, "Could not allocate memory for TLS configuration");
1953 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
1954 lua_getfield(L, 1, "mode");
1955 value = lua_tostring(L, -1);
1956 if (value && !strcmp(value, "server")) tlsconf->server = 1;
1957 else if (value && !strcmp(value, "client")) tlsconf->server = 0;
1958 else luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
1959 lua_pop(L, 1);
1960 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
1961 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
1962 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
1963 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
1964 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
1965 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
1966 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
1967 #if LUA_VERSION_NUM >= 503
1968 valuetype = lua_getfield(L, 1, "verify_client");
1969 #else
1970 lua_getfield(L, 1, "verify_client");
1971 #endif
1972 if (lua_toboolean(L, -1)) {
1973 value = lua_tostring(L, -1);
1974 if (value && !strcmp(value, "required")) {
1975 tls_config_verify_client(tlsconf->config);
1976 } else if (value && !strcmp(value, "optional")) {
1977 tls_config_verify_client_optional(tlsconf->config);
1978 } else {
1979 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
1982 lua_pop(L, 1);
1983 // TODO: configurable legacy support
1984 // tls_config_set_protocols(tlsconf->config, TLS_PROTOCOLS_ALL);
1985 // tls_config_set_ciphers(tlsconf->config, "legacy");
1986 return 1;
1989 static int moonbr_io_tlsconfgc(lua_State *L) {
1990 moonbr_io_tlsconf_t *tlsconf;
1991 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1992 if (tlsconf->config) tls_config_free(tlsconf->config);
1993 tlsconf->config = NULL;
1994 return 0;
1997 static int moonbr_io_starttls(lua_State *L) {
1998 moonbr_io_handle_t *handle;
1999 moonbr_io_tlsconf_t *tlsconf;
2000 const char *servername;
2001 struct tls *tls, *tls2;
2002 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
2003 if (lua_type(L, 2) == LUA_TTABLE) {
2004 lua_pushcfunction(L, moonbr_io_tlsconf);
2005 lua_pushvalue(L, 2);
2006 lua_call(L, 1, 2);
2007 if (lua_isnil(L, -2)) return 2;
2008 lua_pop(L, 1);
2009 lua_replace(L, 2);
2011 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
2012 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
2013 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
2014 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
2015 if (handle->readbufin || handle->writebufin) {
2016 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
2018 if (tlsconf->server) tls = tls_server();
2019 else {
2020 servername = luaL_checkstring(L, 3);
2021 tls = tls_client();
2023 if (!tls) {
2024 return luaL_error(L, "Could not allocate memory for TLS context");
2026 if (tls_configure(tls, tlsconf->config)) goto moonbr_io_starttls_error;
2027 if (tlsconf->server) {
2028 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
2029 handle->servertls = tls;
2030 handle->tls = tls2;
2031 } else {
2032 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
2033 handle->tls = tls;
2035 lua_settop(L, 1);
2036 return 1;
2037 moonbr_io_starttls_error:
2038 lua_pushnil(L);
2039 lua_pushstring(L, tls_error(tls));
2040 tls_free(tls);
2041 return 2;
2044 #endif /* MOONBR_IO_USE_TLS */
2046 static const struct luaL_Reg moonbr_io_handle_methods[] = {
2047 {"read", moonbr_io_read},
2048 {"read_nb", moonbr_io_read_nb},
2049 {"read_call", moonbr_io_read_call},
2050 {"read_yield", moonbr_io_read_yield},
2051 {"drain", moonbr_io_drain},
2052 {"drain_nb", moonbr_io_drain_nb},
2053 {"drain_call", moonbr_io_drain_call},
2054 {"drain_yield", moonbr_io_drain_yield},
2055 {"write", moonbr_io_write},
2056 {"write_nb", moonbr_io_write_nb},
2057 {"write_call", moonbr_io_write_call},
2058 {"write_yield", moonbr_io_write_yield},
2059 {"flush", moonbr_io_flush},
2060 {"flush_nb", moonbr_io_flush_nb},
2061 {"flush_call", moonbr_io_flush_call},
2062 {"flush_yield", moonbr_io_flush_yield},
2063 {"finish", moonbr_io_finish},
2064 {"close", moonbr_io_close},
2065 {"reset", moonbr_io_reset},
2066 #ifdef MOONBR_IO_USE_TLS
2067 {"starttls", moonbr_io_starttls},
2068 #endif
2069 {NULL, NULL}
2070 };
2072 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
2073 {"__index", moonbr_io_handleindex},
2074 {"__newindex", moonbr_io_handlenewindex},
2075 {"__gc", moonbr_io_handlegc},
2076 {NULL, NULL}
2077 };
2079 static const struct luaL_Reg moonbr_io_listener_methods[] = {
2080 {"accept", moonbr_io_accept},
2081 {"accept_nb", moonbr_io_accept_nb},
2082 {"close", moonbr_io_unlisten},
2083 {NULL, NULL}
2084 };
2086 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
2087 {"__gc", moonbr_io_listenergc},
2088 {NULL, NULL}
2089 };
2091 static const struct luaL_Reg moonbr_io_child_methods[] = {
2092 {"kill", moonbr_io_kill},
2093 {"wait", moonbr_io_wait},
2094 {"wait_nb", moonbr_io_wait_nb},
2095 {"wait_call", moonbr_io_wait_call},
2096 {"wait_yield", moonbr_io_wait_yield},
2097 {NULL, NULL}
2098 };
2100 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
2101 {"__index", moonbr_io_childindex},
2102 {"__newindex", moonbr_io_childnewindex},
2103 {"__gc", moonbr_io_childgc},
2104 {NULL, NULL}
2105 };
2107 static const struct luaL_Reg moonbr_io_module_funcs[] = {
2108 {"localconnect", moonbr_io_localconnect},
2109 {"localconnect_nb", moonbr_io_localconnect_nb},
2110 {"tcpconnect", moonbr_io_tcpconnect},
2111 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
2112 {"locallisten", moonbr_io_locallisten},
2113 {"tcplisten", moonbr_io_tcplisten},
2114 {"exec", moonbr_io_exec},
2115 {"catch_sigterm", moonbr_io_catch_sigterm},
2116 {"getpid", moonbr_io_getpid},
2117 {"poll", moonbr_io_poll},
2118 {"timeref", moonbr_io_timeref},
2119 #ifdef MOONBR_IO_USE_TLS
2120 {"tlsconf", moonbr_io_tlsconf},
2121 #endif
2122 {NULL, NULL}
2123 };
2125 #ifdef MOONBR_IO_USE_TLS
2127 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
2128 {"__gc", moonbr_io_tlsconfgc},
2129 {NULL, NULL}
2130 };
2132 #endif /* MOONBR_IO_USE_TLS */
2134 int luaopen_moonbridge_io(lua_State *L) {
2136 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
2138 lua_newtable(L); // module
2139 lua_pushvalue(L, -1);
2140 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
2142 lua_newtable(L); // public metatable
2143 lua_newtable(L); // handle methods
2144 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
2145 lua_pushvalue(L, -1);
2146 lua_setfield(L, -4, "handle_pt");
2147 lua_setfield(L, -2, "__index");
2148 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
2150 lua_newtable(L); // handle metatable
2151 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
2152 lua_pushvalue(L, -1);
2153 lua_setfield(L, -3, "handle_mt");
2154 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
2156 lua_newtable(L); // listener metatable
2157 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
2158 lua_newtable(L); // listener methods
2159 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
2160 lua_pushvalue(L, -1);
2161 lua_setfield(L, -4, "listener_pt");
2162 lua_setfield(L, -2, "__index");
2163 lua_pushvalue(L, -1);
2164 lua_setfield(L, -3, "listener_mt");
2165 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
2167 lua_newtable(L); // child methods
2168 luaL_setfuncs(L, moonbr_io_child_methods, 0);
2169 lua_pushvalue(L, -1);
2170 lua_setfield(L, -3, "child_pt");
2171 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
2172 lua_newtable(L); // child metatable
2173 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
2174 lua_pushvalue(L, -1);
2175 lua_setfield(L, -3, "child_mt");
2176 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
2178 #ifdef MOONBR_IO_USE_TLS
2179 if(tls_init()) {
2180 return luaL_error(L, "Could not initialize TLS library");
2182 lua_newtable(L); // tlsconf metatable
2183 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
2184 lua_pushvalue(L, -1);
2185 lua_setfield(L, -3, "tlsconf_mt");
2186 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
2187 #endif
2189 moonbr_io_pushhandle(L, 0);
2190 lua_setfield(L, -2, "stdin");
2191 moonbr_io_pushhandle(L, 1);
2192 lua_setfield(L, -2, "stdout");
2193 moonbr_io_pushhandle(L, 2);
2194 lua_setfield(L, -2, "stderr");
2196 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
2197 return 1;

Impressum / About Us