moonbridge

view moonbridge_io.c @ 274:42b85f65327c

Allow "main threads" to be named; main threads also use MOONBR_PROTO_INTERVAL as listener type now
author jbe
date Tue Jun 06 11:25:07 2017 +0200 (2017-06-06)
parents 8b8be1a66a98
children d4c82c90d244
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 static int moonbr_io_signalfds[2];
59 #define moonbr_io_signalfd_read moonbr_io_signalfds[0]
60 #define moonbr_io_signalfd_write moonbr_io_signalfds[1]
62 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
63 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
64 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
65 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
66 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
67 #define MOONBR_IO_SIGNALSOCKET_REGKEY "moonbridge_io_signalsocket"
68 #define MOONBR_IO_SIGNALS_REGKEY "moonbridge_io_signals"
70 #ifdef MOONBR_IO_USE_TLS
72 #define MOONBR_IO_TLSCONF_MT_REGKEY "moonbridge_io_tlsconf"
74 typedef struct {
75 struct tls_config *config;
76 int server;
77 } moonbr_io_tlsconf_t;
79 #endif /* MOONBR_IO_USE_TLS */
81 typedef struct {
82 int fd;
83 int issock;
84 sa_family_t addrfam;
85 int finished;
86 int closed;
87 int nonblocking;
88 int nopush;
89 int readerr;
90 int readbufin;
91 int readbufout;
92 int writeerr;
93 size_t writeleft;
94 size_t flushedleft;
95 #if LUA_VERSION_NUM >= 503
96 lua_Integer writeqin;
97 lua_Integer writeqout;
98 #else
99 int writeqin;
100 int writeqout;
101 #endif
102 size_t writeqoff;
103 int writebufin;
104 int writebufout;
105 char readbuf[MOONBR_IO_READBUFLEN];
106 char writebuf[MOONBR_IO_WRITEBUFLEN];
107 #ifdef MOONBR_IO_USE_TLS
108 struct tls *tls;
109 struct tls *servertls;
110 int tlshandshake;
111 int tlsclosing;
112 #endif
113 } moonbr_io_handle_t;
115 typedef struct {
116 int fd;
117 sa_family_t addrfam;
118 int nonblocking;
119 } moonbr_io_listener_t;
121 typedef struct {
122 pid_t pid;
123 } moonbr_io_child_t;
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, 2);
377 lua_rawseti(L, 5, 1);
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_callk(L, 0, 0, ctx, moonbr_io_read_cont);
391 }
392 if (ctx == 1) {
393 lua_pushvalue(L, 5);
394 } else {
395 luaL_Buffer buf;
396 lua_Integer i, chunkcount;
397 chunkcount = lua_rawlen(L, 5);
398 luaL_buffinit(L, &buf);
399 for (i=1; i<=chunkcount && i>0; i++) {
400 lua_rawgeti(L, 5, i);
401 luaL_addvalue(&buf);
402 }
403 luaL_pushresult(&buf);
404 }
405 lua_pushvalue(L, -2);
406 return 2;
407 }
409 static int moonbr_io_read_call(lua_State *L) {
410 lua_settop(L, 4);
411 lua_pushnil(L);
412 #if LUA_VERSION_NUM >= 503
413 return moonbr_io_read_cont(L, 0, 0);
414 #else
415 return moonbr_io_read_cont(L);
416 #endif
417 }
419 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
421 #if LUA_VERSION_NUM >= 503
422 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
423 #else
424 static int moonbr_io_drain_cont(lua_State *L) {
425 #endif
426 lua_Integer remaining, len;
427 size_t totallen = 0;
428 #if !(LUA_VERSION_NUM >= 503)
429 int ctx = 0;
430 lua_getctx(L, &ctx);
431 #endif
432 remaining = lua_tointeger(L, 3);
433 while (1) {
434 lua_pushcfunction(L, moonbr_io_drain_nb);
435 lua_pushvalue(L, 1);
436 lua_pushvalue(L, 3);
437 lua_pushvalue(L, 4);
438 lua_call(L, 3, 2);
439 if (lua_isnil(L, -2)) return 2;
440 lua_insert(L, -2);
441 len = lua_tointeger(L, -1);
442 lua_pop(L, 1);
443 totallen += len;
444 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
445 lua_pop(L, 1);
446 if (remaining >= 0 && len) {
447 remaining -= len;
448 lua_pushinteger(L, remaining);
449 lua_replace(L, 3);
450 }
451 lua_pushvalue(L, 2);
452 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
453 }
454 lua_pushinteger(L, totallen);
455 lua_pushvalue(L, -2);
456 return 2;
457 }
459 static int moonbr_io_drain_call(lua_State *L) {
460 #if LUA_VERSION_NUM >= 503
461 return moonbr_io_drain_cont(L, 0, 0);
462 #else
463 return moonbr_io_drain_cont(L);
464 #endif
465 }
467 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
469 #ifdef MOONBR_IO_USE_TLS
471 #define moonbr_io_write_tls(buf, buflen) \
472 if (handle->tls) { \
473 do { \
474 if (!handle->tlshandshake) { \
475 do written = tls_handshake(handle->tls); \
476 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
477 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
478 handle->tlshandshake = written; \
479 errno = EAGAIN; \
480 break; \
481 } \
482 if (written < 0) { \
483 lua_pushnil(L); \
484 lua_pushstring(L, tls_error(handle->tls)); \
485 return 2; \
486 } \
487 handle->tlshandshake = 1; \
488 } \
489 do written = tls_write(handle->tls, (buf), (buflen)); \
490 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
491 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
492 errno = EAGAIN; \
493 break; \
494 } \
495 if (written < 0) { \
496 lua_pushnil(L); \
497 lua_pushstring(L, tls_error(handle->tls)); \
498 return 2; \
499 } \
500 } while (0); \
501 } \
502 else
504 #endif /* MOONBR_IO_USE_TLS */
506 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
507 moonbr_io_handle_t *handle;
508 int i, top;
509 const char *str;
510 size_t strlen;
511 ssize_t written;
512 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
513 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
514 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
515 if (handle->writeerr) {
516 lua_pushnil(L);
517 lua_pushliteral(L, "Previous write error");
518 return 2;
519 }
520 handle->writeerr = 1;
521 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
522 top = lua_gettop(L);
523 lua_getuservalue(L, 1);
524 lua_getfield(L, -1, "writequeue");
525 for (i=2; i<=top; i++) {
526 luaL_checklstring(L, i, &strlen);
527 lua_pushvalue(L, i);
528 lua_rawseti(L, -2, handle->writeqin++);
529 handle->writeleft += strlen;
530 }
531 if (flush) handle->flushedleft = handle->writeleft;
532 while (handle->writeqout != handle->writeqin) {
533 lua_rawgeti(L, -1, handle->writeqout);
534 str = lua_tolstring(L, -1, &strlen);
535 while (handle->writeqoff < strlen) {
536 if (
537 strlen - handle->writeqoff <
538 MOONBR_IO_WRITEBUFLEN - handle->writebufin
539 ) {
540 memcpy(
541 handle->writebuf + handle->writebufin,
542 str + handle->writeqoff,
543 strlen - handle->writeqoff
544 );
545 handle->writebufin += strlen - handle->writeqoff;
546 break;
547 } else {
548 memcpy(
549 handle->writebuf + handle->writebufin,
550 str + handle->writeqoff,
551 MOONBR_IO_WRITEBUFLEN - handle->writebufin
552 );
553 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
554 handle->writebufin = MOONBR_IO_WRITEBUFLEN;
555 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
556 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
557 #ifdef MOONBR_IO_USE_TLS
558 moonbr_io_write_tls(
559 handle->writebuf + handle->writebufout,
560 MOONBR_IO_WRITEBUFLEN - handle->writebufout
561 )
562 #endif
563 written = write(
564 handle->fd,
565 handle->writebuf + handle->writebufout,
566 MOONBR_IO_WRITEBUFLEN - handle->writebufout
567 );
568 if (written < 0) {
569 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
570 goto moonbr_io_write_impl_block;
571 } else if (errno != EINTR) moonbr_io_return_errmsg();
572 } else {
573 handle->writebufout += written;
574 handle->writeleft -= written;
575 if (handle->flushedleft) {
576 if (written >= handle->flushedleft) {
577 handle->flushedleft = 0;
578 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
579 } else {
580 handle->flushedleft -= written;
581 }
582 }
583 }
584 }
585 handle->writebufin = 0;
586 handle->writebufout = 0;
587 }
588 }
589 handle->writeqoff = 0;
590 lua_pop(L, 1);
591 lua_pushnil(L);
592 lua_rawseti(L, -2, handle->writeqout++);
593 }
594 while (handle->flushedleft) {
595 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
596 #ifdef MOONBR_IO_USE_TLS
597 moonbr_io_write_tls(
598 handle->writebuf + handle->writebufout,
599 handle->writebufin - handle->writebufout
600 )
601 #endif
602 written = write(
603 handle->fd,
604 handle->writebuf + handle->writebufout,
605 handle->writebufin - handle->writebufout
606 );
607 if (written < 0) {
608 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
609 goto moonbr_io_write_impl_block;
610 } else if (errno != EINTR) moonbr_io_return_errmsg();
611 } else {
612 handle->writebufout += written;
613 handle->writeleft -= written;
614 if (handle->flushedleft) {
615 if (written >= handle->flushedleft) {
616 handle->flushedleft = 0;
617 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
618 } else {
619 handle->flushedleft -= written;
620 }
621 }
622 }
623 }
624 if (handle->writebufout == handle->writebufin) {
625 handle->writebufin = 0;
626 handle->writebufout = 0;
627 }
628 if (nonblocking) lua_pushinteger(L, 0);
629 else lua_pushvalue(L, 1);
630 handle->writeerr = 0;
631 return 1;
632 moonbr_io_write_impl_block:
633 lua_pushinteger(L, handle->writeleft);
634 handle->writeerr = 0;
635 return 1;
636 }
638 static int moonbr_io_write(lua_State *L) {
639 return moonbr_io_write_impl(L, 0, 0);
640 }
642 static int moonbr_io_write_nb(lua_State *L) {
643 return moonbr_io_write_impl(L, 1, 0);
644 }
646 static int moonbr_io_flush(lua_State *L) {
647 return moonbr_io_write_impl(L, 0, 1);
648 }
650 static int moonbr_io_flush_nb(lua_State *L) {
651 return moonbr_io_write_impl(L, 1, 1);
652 }
654 #if LUA_VERSION_NUM >= 503
655 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
656 #else
657 static int moonbr_io_write_cont(lua_State *L) {
658 #endif
659 while (1) {
660 lua_pushcfunction(L, moonbr_io_write_nb);
661 lua_pushvalue(L, 1);
662 lua_call(L, 1, 2);
663 if (lua_isnil(L, -2)) return 2;
664 if (!lua_tointeger(L, -2)) {
665 lua_pushvalue(L, 1);
666 return 1;
667 }
668 lua_pop(L, 2);
669 lua_pushvalue(L, 2);
670 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
671 }
672 }
674 static int moonbr_io_write_call(lua_State *L) {
675 lua_pushcfunction(L, moonbr_io_write_nb);
676 lua_insert(L, 3);
677 lua_pushvalue(L, 1);
678 lua_insert(L, 4);
679 lua_call(L, lua_gettop(L) - 3, 2);
680 if (lua_isnil(L, -2)) return 2;
681 if (!lua_tointeger(L, -2)) {
682 lua_pushvalue(L, 1);
683 return 1;
684 }
685 #if LUA_VERSION_NUM >= 503
686 return moonbr_io_write_cont(L, 0, 0);
687 #else
688 return moonbr_io_write_cont(L);
689 #endif
690 }
692 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
694 static int moonbr_io_flush_call(lua_State *L) {
695 lua_pushcfunction(L, moonbr_io_flush_nb);
696 lua_insert(L, 3);
697 lua_pushvalue(L, 1);
698 lua_insert(L, 4);
699 lua_call(L, lua_gettop(L) - 3, 2);
700 if (lua_isnil(L, -2)) return 2;
701 if (!lua_tointeger(L, -2)) {
702 lua_pushvalue(L, 1);
703 return 1;
704 }
705 #if LUA_VERSION_NUM >= 503
706 return moonbr_io_write_cont(L, 0, 0);
707 #else
708 return moonbr_io_write_cont(L);
709 #endif
710 }
712 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
714 static int moonbr_io_finish(lua_State *L) {
715 moonbr_io_handle_t *handle;
716 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
717 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
718 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
719 if (handle->writeleft) {
720 lua_pushcfunction(L, moonbr_io_flush);
721 lua_pushvalue(L, 1);
722 if (lua_pcall(L, 1, 2, 0)) {
723 handle->finished = 1;
724 lua_error(L);
725 }
726 if (!lua_toboolean(L, -2)) {
727 handle->finished = 1;
728 return 2;
729 }
730 }
731 handle->finished = 1;
732 #ifdef MOONBR_IO_USE_TLS
733 if ((handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) && !handle->tls) {
734 #else
735 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
736 #endif
737 if (shutdown(handle->fd, SHUT_WR)) moonbr_io_return_errmsg();
738 } else {
739 #ifdef MOONBR_IO_USE_TLS
740 if (handle->tls) {
741 int status;
742 if (moonbr_io_handle_set_nonblocking(L, handle, 1)) moonbr_io_return_errmsg();
743 do status = tls_close(handle->tls);
744 while (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT);
745 if (status) {
746 close(handle->fd);
747 handle->fd = -1;
748 lua_pushnil(L);
749 lua_pushstring(L, tls_error(handle->tls));
750 return 2;
751 }
752 }
753 #endif
754 if (close(handle->fd)) {
755 handle->fd = -1;
756 moonbr_io_return_errmsg();
757 }
758 handle->fd = -1; /* fake EOF on read */
759 }
760 lua_pushboolean(L, 1);
761 return 1;
762 }
764 static int moonbr_io_close_impl(lua_State *L, int nonblocking, int reset) {
765 moonbr_io_handle_t *handle;
766 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
767 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
768 if (!reset && handle->fd >= 0) {
769 if (handle->writeleft) {
770 lua_pushcfunction(L, nonblocking ? moonbr_io_flush_nb : moonbr_io_flush);
771 lua_pushvalue(L, 1);
772 if (lua_pcall(L, 1, 2, 0)) {
773 handle->closed = 1;
774 close(handle->fd);
775 handle->fd = -1;
776 lua_error(L);
777 }
778 if (!nonblocking) handle->closed = 1; /* TODO: handle nonblocking case */
779 if (!lua_toboolean(L, -2)) {
780 close(handle->fd);
781 handle->fd = -1;
782 return 2;
783 }
784 #if LUA_VERSION_NUM >= 503
785 if (nonblocking && lua_tointeger(L, -2)) {
786 #else
787 if (nonblocking && lua_tonumber(L, -2)) {
788 #endif
789 lua_pushliteral(L, "flush");
790 lua_pushvalue(L, -3);
791 return 2;
792 }
793 } else {
794 handle->closed = 1;
795 }
796 #ifdef MOONBR_IO_USE_TLS
797 if (handle->tls) {
798 int status;
799 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
800 do status = tls_close(handle->tls);
801 while (!nonblocking && (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT));
802 if (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT) {
803 handle->tlsclosing = status; /* TODO: handle polling */
804 lua_pushliteral(L, "close");
805 return 1;
806 }
807 if (status) {
808 close(handle->fd);
809 handle->fd = -1;
810 lua_pushnil(L);
811 lua_pushstring(L, tls_error(handle->tls));
812 return 2;
813 }
814 }
815 #endif
816 if (moonbr_io_handle_set_linger(L, handle, -1)) {
817 moonbr_io_prepare_errmsg();
818 close(handle->fd);
819 handle->fd = -1;
820 moonbr_io_return_prepared_errmsg();
821 }
822 } else {
823 handle->closed = 1;
824 }
825 if (handle->fd >= 0) {
826 if (close(handle->fd)) {
827 handle->fd = -1;
828 moonbr_io_return_errmsg();
829 }
830 handle->fd = -1;
831 }
832 lua_pushboolean(L, 1);
833 return 1;
835 }
837 static int moonbr_io_close(lua_State *L) {
838 return moonbr_io_close_impl(L, 0, 0);
839 }
841 static int moonbr_io_reset(lua_State *L) {
842 return moonbr_io_close_impl(L, 0, 1);
843 }
845 static int moonbr_io_handlegc(lua_State *L) {
846 moonbr_io_handle_t *handle;
847 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
848 if (handle->fd >= 0) {
849 lua_pushcfunction(L, moonbr_io_reset);
850 lua_pushvalue(L, 1);
851 lua_pushinteger(L, 0);
852 lua_call(L, 2, 0);
853 }
854 #ifdef MOONBR_IO_USE_TLS
855 if (handle->tls) {
856 tls_free(handle->tls);
857 handle->tls = NULL;
858 }
859 if (handle->servertls) {
860 tls_free(handle->servertls);
861 handle->servertls = NULL;
862 }
863 #endif
864 return 0;
865 }
867 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
868 moonbr_io_handle_t *handle;
869 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
870 if (!handle->closed) {
871 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
872 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
873 lua_call(L, 1, 0);
874 }
875 }
877 static int moonbr_io_pushhandle_impl(lua_State *L) {
878 int *fd;
879 moonbr_io_handle_t *handle;
880 struct sockaddr addr;
881 socklen_t addrlen;
882 fd = lua_touserdata(L, 1);
883 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
884 handle->fd = -1; /* avoid closing incomplete handle */
885 addrlen = sizeof(addr);
886 if (getsockname(*fd, &addr, &addrlen)) {
887 if (errno != ENOTSOCK) {
888 moonbr_io_prepare_errmsg();
889 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
890 }
891 handle->issock = 0;
892 } else {
893 handle->issock = 1;
894 handle->addrfam = addr.sa_family;
895 }
896 handle->finished = 0;
897 handle->closed = 0;
898 handle->nonblocking = -1;
899 handle->nopush = -1;
900 handle->readerr = 0;
901 handle->readbufin = 0;
902 handle->readbufout = 0;
903 handle->writeerr = 0;
904 handle->writeleft = 0;
905 handle->flushedleft = 0;
906 handle->writeqin = 0;
907 handle->writeqout = 0;
908 handle->writeqoff = 0;
909 handle->writebufin = 0;
910 handle->writebufout = 0;
911 #ifdef MOONBR_IO_USE_TLS
912 handle->tls = NULL;
913 handle->servertls = NULL;
914 handle->tlshandshake = 0;
915 handle->tlsclosing = 0;
916 #endif
917 handle->fd = *fd; /* required for set_linger call */
918 if (moonbr_io_handle_set_linger(L, handle, 0)) {
919 moonbr_io_prepare_errmsg();
920 handle->fd = -1;
921 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
922 }
923 handle->fd = -1; /* avoid closing incomplete handle */
924 luaL_setmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
925 lua_newtable(L); // uservalue
926 lua_newtable(L);
927 lua_setfield(L, -2, "writequeue");
928 lua_newtable(L); // public
929 if (handle->addrfam == AF_INET6) {
930 struct sockaddr_in6 addr_in6;
931 char addrstrbuf[INET6_ADDRSTRLEN];
932 const char *addrstr;
933 addrlen = sizeof(addr_in6);
934 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
935 moonbr_io_prepare_errmsg();
936 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
937 }
938 if (addrlen > sizeof(addr_in6)) {
939 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
940 }
941 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
942 if (!addrstr) {
943 moonbr_io_prepare_errmsg();
944 luaL_error(L, "Could not format local IP address: %s", errmsg);
945 } else {
946 lua_pushstring(L, addrstr);
947 lua_setfield(L, -2, "local_ip6");
948 }
949 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
950 lua_setfield(L, -2, "local_tcpport");
951 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
952 moonbr_io_prepare_errmsg();
953 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
954 }
955 if (addrlen > sizeof(addr_in6)) {
956 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
957 }
958 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
959 if (!addrstr) {
960 moonbr_io_prepare_errmsg();
961 luaL_error(L, "Could not format remote IP address: %s", errmsg);
962 } else {
963 lua_pushstring(L, addrstr);
964 lua_setfield(L, -2, "remote_ip6");
965 }
966 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
967 lua_setfield(L, -2, "remote_tcpport");
968 } else if (handle->addrfam == AF_INET) {
969 struct sockaddr_in addr_in;
970 char addrstrbuf[INET_ADDRSTRLEN];
971 const char *addrstr;
972 addrlen = sizeof(addr_in);
973 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
974 moonbr_io_prepare_errmsg();
975 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
976 }
977 if (addrlen > sizeof(addr_in)) {
978 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
979 }
980 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
981 if (!addrstr) {
982 moonbr_io_prepare_errmsg();
983 luaL_error(L, "Could not format local IP address: %s", errmsg);
984 } else {
985 lua_pushstring(L, addrstr);
986 lua_setfield(L, -2, "local_ip4");
987 }
988 lua_pushinteger(L, ntohs(addr_in.sin_port));
989 lua_setfield(L, -2, "local_tcpport");
990 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
991 moonbr_io_prepare_errmsg();
992 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
993 }
994 if (addrlen > sizeof(addr_in)) {
995 luaL_error(L, "Could not determine remote 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 remote IP address: %s", errmsg);
1001 } else {
1002 lua_pushstring(L, addrstr);
1003 lua_setfield(L, -2, "remote_ip4");
1005 lua_pushinteger(L, ntohs(addr_in.sin_port));
1006 lua_setfield(L, -2, "remote_tcpport");
1008 luaL_setmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1009 lua_setfield(L, -2, "public");
1010 lua_setuservalue(L, -2);
1011 handle->fd = *fd;
1012 *fd = -1; /* closing is now handled by garbage collection */
1013 return 1;
1016 void moonbr_io_pushhandle(lua_State *L, int fd) {
1017 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1018 lua_pushlightuserdata(L, &fd);
1019 if (lua_pcall(L, 1, 1, 0)) {
1020 if (fd != -1) close(fd); // TODO: correct to close file descriptor here?
1021 lua_error(L);
1025 static int moonbr_io_handleindex(lua_State *L) {
1026 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1027 luaL_checkany(L, 2);
1028 lua_getuservalue(L, 1);
1029 lua_getfield(L, -1, "public");
1030 lua_pushvalue(L, 2);
1031 lua_gettable(L, -2);
1032 return 1;
1035 static int moonbr_io_handlenewindex(lua_State *L) {
1036 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1037 luaL_checkany(L, 2);
1038 luaL_checkany(L, 3);
1039 lua_getuservalue(L, 1);
1040 lua_getfield(L, -1, "public");
1041 lua_pushvalue(L, 2);
1042 lua_pushvalue(L, 3);
1043 lua_settable(L, -3);
1044 return 0;
1047 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
1048 const char *path;
1049 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1050 const int path_maxlen = sizeof(struct sockaddr_un) - (
1051 (void *)sockaddr.sun_path - (void *)&sockaddr
1052 ) - 1; /* one byte for termination */
1053 int sock;
1054 path = luaL_checkstring(L, 1);
1055 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1056 strcpy(sockaddr.sun_path, path);
1057 sock = socket(
1058 PF_LOCAL,
1059 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1061 );
1062 if (sock < 0) moonbr_io_return_errmsg();
1063 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1064 if (!nonblocking && errno == EINTR) {
1065 moonbr_io_prepare_errmsg();
1066 close(sock);
1067 moonbr_io_return_prepared_errmsg();
1068 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1070 moonbr_io_pushhandle(L, sock);
1071 return 1;
1074 static int moonbr_io_localconnect(lua_State *L) {
1075 return moonbr_io_localconnect_impl(L, 0);
1078 static int moonbr_io_localconnect_nb(lua_State *L) {
1079 return moonbr_io_localconnect_impl(L, 1);
1082 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
1083 const char *host, *port;
1084 struct addrinfo hints = { 0, };
1085 struct addrinfo *res, *addrinfo;
1086 int errcode;
1087 int sock;
1088 host = luaL_checkstring(L, 1);
1089 port = luaL_checkstring(L, 2);
1090 hints.ai_family = AF_UNSPEC;
1091 hints.ai_socktype = SOCK_STREAM;
1092 hints.ai_protocol = IPPROTO_TCP;
1093 hints.ai_flags = AI_ADDRCONFIG;
1094 errcode = getaddrinfo(host, port, &hints, &res);
1095 if (errcode) {
1096 freeaddrinfo(res);
1097 if (errcode == EAI_SYSTEM) {
1098 moonbr_io_prepare_errmsg();
1099 lua_pushnil(L);
1100 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1101 } else {
1102 lua_pushnil(L);
1103 lua_pushstring(L, gai_strerror(errcode));
1105 return 2;
1107 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1108 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1110 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1111 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1113 addrinfo = res;
1114 moonbr_io_tcpconnect_found:
1115 sock = socket(
1116 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1117 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1118 addrinfo->ai_protocol
1119 );
1120 if (sock < 0) {
1121 moonbr_io_prepare_errmsg();
1122 freeaddrinfo(res);
1123 moonbr_io_return_prepared_errmsg();
1125 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1126 freeaddrinfo(res);
1127 if (!nonblocking && errno == EINTR) {
1128 moonbr_io_prepare_errmsg();
1129 close(sock);
1130 moonbr_io_return_prepared_errmsg();
1131 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1132 } else {
1133 freeaddrinfo(res);
1135 moonbr_io_pushhandle(L, sock);
1136 return 1;
1139 static int moonbr_io_tcpconnect(lua_State *L) {
1140 return moonbr_io_tcpconnect_impl(L, 0);
1143 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1144 return moonbr_io_tcpconnect_impl(L, 1);
1147 static int moonbr_io_locallisten(lua_State *L) {
1148 moonbr_io_listener_t *listener;
1149 const char *path;
1150 struct stat sb;
1151 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1152 const int path_maxlen = sizeof(struct sockaddr_un) - (
1153 (void *)sockaddr.sun_path - (void *)&sockaddr
1154 ) - 1; /* one byte for termination */
1155 int sock;
1156 path = luaL_checkstring(L, 1);
1157 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1158 strcpy(sockaddr.sun_path, path);
1159 if (stat(path, &sb) == 0) {
1160 if (S_ISSOCK(sb.st_mode)) unlink(path);
1162 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1163 listener->fd = -1;
1164 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1165 sock = socket(
1166 PF_LOCAL,
1167 SOCK_STREAM | SOCK_CLOEXEC,
1169 );
1170 if (sock < 0) moonbr_io_return_errmsg();
1171 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1172 moonbr_io_prepare_errmsg();
1173 close(sock);
1174 moonbr_io_return_prepared_errmsg();
1176 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1177 moonbr_io_prepare_errmsg();
1178 close(sock);
1179 moonbr_io_return_prepared_errmsg();
1181 listener->fd = sock;
1182 listener->addrfam = AF_LOCAL;
1183 listener->nonblocking = -1;
1184 return 1;
1187 static int moonbr_io_tcplisten(lua_State *L) {
1188 moonbr_io_listener_t *listener;
1189 const char *host, *port;
1190 struct addrinfo hints = { 0, };
1191 struct addrinfo *res, *addrinfo;
1192 int errcode;
1193 int sock;
1194 host = luaL_optstring(L, 1, NULL);
1195 port = luaL_checkstring(L, 2);
1196 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1197 listener->fd = -1;
1198 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1199 hints.ai_family = AF_UNSPEC;
1200 hints.ai_socktype = SOCK_STREAM;
1201 hints.ai_protocol = IPPROTO_TCP;
1202 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1203 errcode = getaddrinfo(host, port, &hints, &res);
1204 if (errcode) {
1205 freeaddrinfo(res);
1206 if (errcode == EAI_SYSTEM) {
1207 moonbr_io_prepare_errmsg();
1208 lua_pushnil(L);
1209 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1210 } else {
1211 lua_pushnil(L);
1212 lua_pushstring(L, gai_strerror(errcode));
1214 return 2;
1216 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1217 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1219 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1220 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1222 addrinfo = res;
1223 moonbr_io_tcpconnect_found:
1224 listener->addrfam = addrinfo->ai_family;
1225 sock = socket(
1226 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1227 addrinfo->ai_socktype | SOCK_CLOEXEC,
1228 addrinfo->ai_protocol
1229 );
1230 if (sock < 0) {
1231 moonbr_io_prepare_errmsg();
1232 freeaddrinfo(res);
1233 moonbr_io_return_prepared_errmsg();
1236 static const int reuseval = 1;
1237 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1238 moonbr_io_prepare_errmsg();
1239 freeaddrinfo(res);
1240 close(sock);
1241 lua_pushnil(L);
1242 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1243 return 2;
1246 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1247 moonbr_io_prepare_errmsg();
1248 freeaddrinfo(res);
1249 close(sock);
1250 moonbr_io_return_prepared_errmsg();
1252 freeaddrinfo(res);
1253 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1254 moonbr_io_prepare_errmsg();
1255 close(sock);
1256 moonbr_io_return_prepared_errmsg();
1258 listener->fd = sock;
1259 listener->nonblocking = -1;
1260 return 1;
1263 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1264 moonbr_io_listener_t *listener;
1265 int fd;
1266 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1267 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1268 if (listener->nonblocking != nonblocking) {
1269 int flags;
1270 flags = fcntl(listener->fd, F_GETFL, 0);
1271 if (flags == -1) {
1272 moonbr_io_prepare_errmsg();
1273 close(listener->fd);
1274 listener->fd = -1;
1275 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1277 if (nonblocking) flags |= O_NONBLOCK;
1278 else flags &= ~O_NONBLOCK;
1279 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1280 moonbr_io_prepare_errmsg();
1281 close(listener->fd);
1282 listener->fd = -1;
1283 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1285 listener->nonblocking = nonblocking;
1287 while (1) {
1288 #if defined(__linux__) && !defined(_GNU_SOURCE)
1289 fd = accept(listener->fd, NULL, NULL);
1290 if (fd != -1) {
1291 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1292 moonbr_io_prepare_errmsg();
1293 close(listener->fd);
1294 listener->fd = -1;
1295 close(fd);
1296 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1299 #else
1300 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1301 #endif
1302 if (fd < 0) {
1303 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1304 lua_pushboolean(L, 0);
1305 lua_pushliteral(L, "No incoming connection pending");
1306 return 2;
1307 } else if (errno != EINTR) moonbr_io_return_errmsg();
1308 } else {
1309 moonbr_io_pushhandle(L, fd);
1310 return 1;
1315 static int moonbr_io_accept(lua_State *L) {
1316 return moonbr_io_accept_impl(L, 0);
1319 static int moonbr_io_accept_nb(lua_State *L) {
1320 return moonbr_io_accept_impl(L, 1);
1323 static int moonbr_io_unlisten(lua_State *L) {
1324 moonbr_io_listener_t *listener;
1325 struct sockaddr_un addr;
1326 socklen_t addrlen;
1327 struct stat sb;
1328 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1329 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1330 addrlen = sizeof(addr);
1331 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1332 if (close(listener->fd)) {
1333 moonbr_io_prepare_errmsg();
1334 listener->fd = -1;
1335 if (addrlen && addrlen <= sizeof(addr)) {
1336 if (stat(addr.sun_path, &sb) == 0) {
1337 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1340 moonbr_io_return_prepared_errmsg();
1342 listener->fd = -1;
1343 if (addrlen && addrlen <= sizeof(addr)) {
1344 if (stat(addr.sun_path, &sb) == 0) {
1345 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1348 lua_pushboolean(L, 1);
1349 return 1;
1352 static int moonbr_io_listenergc(lua_State *L) {
1353 moonbr_io_listener_t *listener;
1354 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1355 if (listener->fd >= 0) close(listener->fd);
1356 listener->fd = -1;
1357 return 0;
1360 static int moonbr_io_exec(lua_State *L) {
1361 char **argv;
1362 int i, argc;
1363 int sockin[2], sockout[2], sockerr[2];
1364 volatile int errorcond = 0;
1365 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
1366 moonbr_io_child_t *child;
1367 argc = lua_gettop(L);
1368 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1369 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1370 argv[argc] = NULL;
1371 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1372 child->pid = 0;
1373 lua_newtable(L);
1374 lua_setuservalue(L, -2);
1375 luaL_setmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1376 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
1377 moonbr_io_prepare_errmsg();
1378 lua_pushnil(L);
1379 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1380 return 2;
1382 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
1383 moonbr_io_prepare_errmsg();
1384 close(sockin[0]);
1385 close(sockin[1]);
1386 lua_pushnil(L);
1387 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1388 return 2;
1390 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
1391 moonbr_io_prepare_errmsg();
1392 close(sockin[0]);
1393 close(sockin[1]);
1394 close(sockout[0]);
1395 close(sockout[1]);
1396 lua_pushnil(L);
1397 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1398 return 2;
1400 child->pid = vfork();
1401 if (child->pid == -1) {
1402 moonbr_io_prepare_errmsg();
1403 close(sockin[0]);
1404 close(sockin[1]);
1405 close(sockout[0]);
1406 close(sockout[1]);
1407 close(sockerr[0]);
1408 close(sockerr[1]);
1409 lua_pushnil(L);
1410 lua_pushfstring(L, "Could not fork: %s", errmsg);
1411 return 2;
1413 if (!child->pid) {
1414 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
1415 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
1416 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
1417 closefrom(3);
1418 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1419 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1420 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1421 if (execvp(argv[0], argv)) {
1422 errorcond = 2;
1423 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1424 _exit(0);
1426 moonbr_io_exec_error1:
1427 errorcond = 1;
1428 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1429 _exit(0);
1431 close(sockin[1]);
1432 close(sockout[1]);
1433 close(sockerr[1]);
1434 if (errorcond) {
1435 int status;
1436 close(sockin[0]);
1437 close(sockout[0]);
1438 close(sockerr[0]);
1439 while (waitpid(child->pid, &status, 0) == -1) {
1440 if (errno != EINTR) {
1441 moonbr_io_prepare_errmsg();
1442 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1445 child->pid = 0;
1446 lua_pushnil(L);
1447 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1448 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1449 return 2;
1451 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1452 lua_pushlightuserdata(L, &sockin[0]);
1453 if (lua_pcall(L, 1, 1, 0)) {
1454 if (sockin[0] != -1) close(sockin[0]);
1455 close(sockout[0]);
1456 close(sockerr[0]);
1457 goto moonbr_io_exec_error2;
1459 lua_setfield(L, -2, "stdin");
1460 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1461 lua_pushlightuserdata(L, &sockout[0]);
1462 if (lua_pcall(L, 1, 1, 0)) {
1463 if (sockout[0] != -1) close(sockout[0]);
1464 close(sockerr[0]);
1465 goto moonbr_io_exec_error2;
1467 lua_setfield(L, -2, "stdout");
1468 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1469 lua_pushlightuserdata(L, &sockerr[0]);
1470 if (lua_pcall(L, 1, 1, 0)) {
1471 if (sockerr[0] != -1) close(sockerr[0]);
1472 goto moonbr_io_exec_error2;
1474 lua_setfield(L, -2, "stderr");
1475 return 1;
1476 moonbr_io_exec_error2:
1478 int status;
1479 while (waitpid(child->pid, &status, 0) == -1) {
1480 if (errno != EINTR) {
1481 moonbr_io_prepare_errmsg();
1482 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
1486 child->pid = 0;
1487 return lua_error(L);
1490 static int moonbr_io_childindex(lua_State *L) {
1491 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1492 luaL_checkany(L, 2);
1493 lua_getuservalue(L, 1);
1494 lua_pushvalue(L, 2);
1495 lua_gettable(L, -2);
1496 if (lua_isnil(L, -1)) {
1497 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1498 lua_pushvalue(L, 2);
1499 lua_gettable(L, -2);
1501 return 1;
1504 static int moonbr_io_childnewindex(lua_State *L) {
1505 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1506 luaL_checkany(L, 2);
1507 luaL_checkany(L, 3);
1508 lua_getuservalue(L, 1);
1509 lua_pushvalue(L, 2);
1510 lua_pushvalue(L, 3);
1511 lua_settable(L, -3);
1512 return 0;
1515 static int moonbr_io_childgc(lua_State *L) {
1516 moonbr_io_child_t *child;
1517 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1518 if (child->pid) {
1519 int status;
1520 if (kill(child->pid, SIGKILL)) {
1521 moonbr_io_prepare_errmsg();
1522 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1524 while (waitpid(child->pid, &status, 0) == -1) {
1525 if (errno != EINTR) {
1526 moonbr_io_prepare_errmsg();
1527 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1531 return 0;
1534 static int moonbr_io_kill(lua_State *L) {
1535 moonbr_io_child_t *child;
1536 int sig;
1537 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1538 sig = luaL_optinteger(L, 2, SIGTERM);
1539 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
1540 if (kill(child->pid, sig)) {
1541 moonbr_io_prepare_errmsg();
1542 luaL_error(L, "Error in kill call: %s", errmsg);
1544 lua_settop(L, 1);
1545 return 1;
1548 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1549 moonbr_io_child_t *child;
1550 pid_t waitedpid;
1551 int status;
1552 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1553 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
1554 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1555 if (errno != EINTR) {
1556 moonbr_io_prepare_errmsg();
1557 luaL_error(L, "Error in waitpid call: %s", errmsg);
1560 if (!waitedpid) {
1561 lua_pushboolean(L, 0);
1562 lua_pushliteral(L, "Process is still running");
1563 return 2;
1564 } else {
1565 child->pid = 0;
1566 if (WIFEXITED(status)) {
1567 lua_pushinteger(L, WEXITSTATUS(status));
1568 } else if (WIFSIGNALED(status)) {
1569 lua_pushinteger(L, -WTERMSIG(status));
1570 } else {
1571 luaL_error(L, "Unexpected status value returned by waitpid call");
1573 return 1;
1577 static int moonbr_io_wait(lua_State *L) {
1578 return moonbr_io_wait_impl(L, 0);
1581 static int moonbr_io_wait_nb(lua_State *L) {
1582 return moonbr_io_wait_impl(L, 1);
1585 #if LUA_VERSION_NUM >= 503
1586 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1587 #else
1588 static int moonbr_io_wait_cont(lua_State *L) {
1589 #endif
1590 #if !(LUA_VERSION_NUM >= 503)
1591 int ctx = 0;
1592 lua_getctx(L, &ctx);
1593 #endif
1594 while (1) {
1595 lua_pushcfunction(L, moonbr_io_wait_nb);
1596 lua_pushvalue(L, 1);
1597 lua_call(L, 1, 1);
1598 if (!lua_isnil(L, -1)) break;
1599 lua_pushvalue(L, 2);
1600 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1602 return 1;
1605 static int moonbr_io_wait_call(lua_State *L) {
1606 lua_settop(L, 2);
1607 #if LUA_VERSION_NUM >= 503
1608 return moonbr_io_wait_cont(L, 0, 0);
1609 #else
1610 return moonbr_io_wait_cont(L);
1611 #endif
1614 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1616 static void moonbr_io_signalhandler(int sig) {
1617 int errno2 = errno;
1618 char buf[1] = {sig};
1619 write(moonbr_io_signalfd_write, buf, 1);
1620 errno = errno2;
1623 static int moonbr_io_signalsocket(lua_State *L) {
1624 int i, argc, sig;
1625 if (moonbr_io_signalfd_read < 0) {
1626 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, moonbr_io_signalfds)) {
1627 luaL_error(L, "Could not create socket pair for signal queueing");
1630 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
1631 lua_insert(L, 1);
1632 argc = lua_gettop(L);
1633 for (i=2; i<=argc; i++) {
1634 if (lua_type(L, i) == LUA_TSTRING) {
1635 lua_pushvalue(L, i);
1636 lua_gettable(L, 1);
1637 sig = lua_tointeger(L, -1);
1638 lua_pop(L, 1);
1639 if (!sig) {
1640 lua_pushvalue(L, i);
1641 luaL_error(L, "Unknown signal \"%s\"", lua_tostring(L, i));
1643 } else {
1644 sig = luaL_checkinteger(L, i);
1646 errno = 0;
1647 signal(sig, moonbr_io_signalhandler);
1648 if (errno) luaL_error(L, "Could not install signal handler (invalid signal number?)");
1650 lua_settop(L, 0);
1651 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALSOCKET_REGKEY);
1652 if (lua_isnil(L, -1)) {
1653 int fd = dup(moonbr_io_signalfd_read); /* TODO: determine how mooonbr_io_pushhandle acts in case of error */
1654 if (fd < 0) luaL_error(L, "Error in dup() system call");
1655 moonbr_io_pushhandle(L, fd);
1656 lua_pushvalue(L, -1);
1657 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALSOCKET_REGKEY);
1659 return 1;
1662 static int moonbr_io_getpid(lua_State *L) {
1663 lua_pushinteger(L, getpid());
1664 return 1;
1667 #ifdef MOONBR_IO_USE_TLS
1669 #define moonbr_io_poll_tls() \
1670 if (!handle->tlshandshake) { \
1671 lua_pushboolean(L, 1); \
1672 return 1; \
1673 } \
1674 if (handle->tlshandshake == TLS_WANT_POLLIN) { \
1675 if (fd < 0) { \
1676 lua_pushboolean(L, 1); \
1677 return 1; \
1678 } \
1679 FD_SET(fd, &readfds); \
1680 if (fd+1 > nfds) nfds = fd+1; \
1681 continue; \
1682 } \
1683 if (handle->tlshandshake == TLS_WANT_POLLOUT) { \
1684 if (fd < 0) { \
1685 lua_pushboolean(L, 1); \
1686 return 1; \
1687 } \
1688 FD_SET(fd, &writefds); \
1689 if (fd+1 > nfds) nfds = fd+1; \
1690 continue; \
1691 } \
1692 while (0)
1694 #endif /* MOONBR_IO_USE_TLS */
1696 static int moonbr_io_poll(lua_State *L) {
1697 moonbr_io_handle_t *handle;
1698 moonbr_io_listener_t *listener;
1699 int fd, isnum;
1700 int nfds = 0;
1701 fd_set readfds, writefds, exceptfds;
1702 struct timeval timeout = {0, };
1703 int status;
1704 FD_ZERO(&readfds);
1705 FD_ZERO(&writefds);
1706 FD_ZERO(&exceptfds);
1707 if (!lua_isnoneornil(L, 1)) {
1708 luaL_checktype(L, 1, LUA_TTABLE);
1709 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1710 if (lua_toboolean(L, -1)) {
1711 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1712 if (handle) {
1713 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1714 fd = handle->fd;
1715 #if MOONBR_IO_USE_TLS
1716 moonbr_io_poll_tls();
1717 #endif
1718 if (
1719 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1720 handle->readbufin != handle->readbufout /* data pending in buffer */
1721 ) {
1722 lua_pushboolean(L, 1);
1723 return 1;
1725 } else {
1726 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1727 if (listener) {
1728 fd = listener->fd;
1729 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1730 } else {
1731 fd = lua_tointegerx(L, -2, &isnum);
1732 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1735 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1736 FD_SET(fd, &readfds);
1737 if (fd+1 > nfds) nfds = fd+1;
1741 if (!lua_isnoneornil(L, 2)) {
1742 luaL_checktype(L, 2, LUA_TTABLE);
1743 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1744 if (lua_toboolean(L, -1)) {
1745 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1746 if (handle) {
1747 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1748 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1749 fd = handle->fd;
1750 #if MOONBR_IO_USE_TLS
1751 moonbr_io_poll_tls();
1752 #endif
1753 } else {
1754 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1755 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1756 fd = lua_tointegerx(L, -2, &isnum);
1757 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1759 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1760 FD_SET(fd, &writefds);
1761 if (fd+1 > nfds) nfds = fd+1;
1765 if (!lua_isnoneornil(L, 3)) {
1766 lua_Number n;
1767 n = lua_tonumberx(L, 3, &isnum);
1768 if (isnum && n<0) {
1769 lua_pushboolean(L, 0);
1770 lua_pushliteral(L, "Negative timeout");
1771 return 2;
1772 } else if (isnum && n>=0 && n<100000000) {
1773 timeout.tv_sec = n;
1774 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1775 } else {
1776 luaL_argcheck(L, 0, 3, "not a valid timeout");
1778 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1779 } else {
1780 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1782 if (status == -1) {
1783 if (errno == EINTR) {
1784 lua_pushboolean(L, 1);
1785 return 1;
1786 } else {
1787 moonbr_io_prepare_errmsg();
1788 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1790 } else if (status == 0) {
1791 lua_pushboolean(L, 0);
1792 lua_pushliteral(L, "Timeout while polling file descriptors");
1793 return 2;
1794 } else {
1795 lua_pushboolean(L, 1);
1796 return 1;
1800 static int moonbr_io_timeref(lua_State *L) {
1801 lua_Number sub;
1802 struct timespec tp;
1803 sub = luaL_optnumber(L, 1, 0);
1804 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1805 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1807 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1808 return 1;
1811 #ifdef MOONBR_IO_USE_TLS
1813 #define moonbr_io_tlsconf_string(name, field, func) \
1814 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1815 lua_getfield(L, 1, (field)); \
1816 valuetype = lua_type(L, -1); \
1817 if (valuetype != LUA_TNIL) { \
1818 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1819 value = lua_tostring(L, -1); \
1820 if (func(tlsconf->config, value)) { \
1821 lua_pushnil(L); \
1822 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
1823 return 2; \
1824 } \
1825 } \
1826 lua_pop(L, 1);
1828 #define moonbr_io_tlsconf_binary(name, field, func) \
1829 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1830 lua_getfield(L, 1, (field)); \
1831 valuetype = lua_type(L, -1); \
1832 if (valuetype != LUA_TNIL) { \
1833 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1834 value = lua_tolstring(L, -1, &valuelen); \
1835 if (func(tlsconf->config, (void *)value, valuelen)) { \
1836 lua_pushnil(L); \
1837 lua_pushliteral(L, "Could not set " name); \
1838 return 2; \
1839 } \
1840 } \
1841 lua_pop(L, 1);
1843 static int moonbr_io_tlsconf(lua_State *L) {
1844 moonbr_io_tlsconf_t *tlsconf;
1845 int valuetype;
1846 const char *value;
1847 size_t valuelen;
1848 luaL_checktype(L, 1, LUA_TTABLE);
1849 tlsconf = lua_newuserdata(L, sizeof(moonbr_io_tlsconf_t));
1850 tlsconf->config = tls_config_new();
1851 if (!tlsconf->config) {
1852 return luaL_error(L, "Could not allocate memory for TLS configuration");
1854 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
1855 lua_getfield(L, 1, "mode");
1856 value = lua_tostring(L, -1);
1857 if (value && !strcmp(value, "server")) tlsconf->server = 1;
1858 else if (value && !strcmp(value, "client")) tlsconf->server = 0;
1859 else luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
1860 lua_pop(L, 1);
1861 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
1862 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
1863 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
1864 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
1865 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
1866 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
1867 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
1868 #if LUA_VERSION_NUM >= 503
1869 valuetype = lua_getfield(L, 1, "verify_client");
1870 #else
1871 lua_getfield(L, 1, "verify_client");
1872 #endif
1873 if (lua_toboolean(L, -1)) {
1874 value = lua_tostring(L, -1);
1875 if (value && !strcmp(value, "required")) {
1876 tls_config_verify_client(tlsconf->config);
1877 } else if (value && !strcmp(value, "optional")) {
1878 tls_config_verify_client_optional(tlsconf->config);
1879 } else {
1880 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
1883 lua_pop(L, 1);
1884 // TODO: configurable legacy support
1885 // tls_config_set_protocols(tlsconf->config, TLS_PROTOCOLS_ALL);
1886 // tls_config_set_ciphers(tlsconf->config, "legacy");
1887 return 1;
1890 static int moonbr_io_tlsconfgc(lua_State *L) {
1891 moonbr_io_tlsconf_t *tlsconf;
1892 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1893 if (tlsconf->config) tls_config_free(tlsconf->config);
1894 tlsconf->config = NULL;
1895 return 0;
1898 static int moonbr_io_starttls(lua_State *L) {
1899 moonbr_io_handle_t *handle;
1900 moonbr_io_tlsconf_t *tlsconf;
1901 const char *servername;
1902 struct tls *tls, *tls2;
1903 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1904 if (lua_type(L, 2) == LUA_TTABLE) {
1905 lua_pushcfunction(L, moonbr_io_tlsconf);
1906 lua_pushvalue(L, 2);
1907 lua_call(L, 1, 2);
1908 if (lua_isnil(L, -2)) return 2;
1909 lua_pop(L, 1);
1910 lua_replace(L, 2);
1912 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
1913 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
1914 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
1915 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
1916 if (handle->readbufin || handle->writebufin) {
1917 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
1919 if (tlsconf->server) tls = tls_server();
1920 else {
1921 servername = luaL_checkstring(L, 3);
1922 tls = tls_client();
1924 if (!tls) {
1925 return luaL_error(L, "Could not allocate memory for TLS context");
1927 if (tls_configure(tls, tlsconf->config)) goto moonbr_io_starttls_error;
1928 if (tlsconf->server) {
1929 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
1930 handle->servertls = tls;
1931 handle->tls = tls2;
1932 } else {
1933 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
1934 handle->tls = tls;
1936 lua_settop(L, 1);
1937 return 1;
1938 moonbr_io_starttls_error:
1939 lua_pushnil(L);
1940 lua_pushstring(L, tls_error(tls));
1941 tls_free(tls);
1942 return 2;
1945 #endif /* MOONBR_IO_USE_TLS */
1947 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1948 {"read", moonbr_io_read},
1949 {"read_nb", moonbr_io_read_nb},
1950 {"read_call", moonbr_io_read_call},
1951 {"read_yield", moonbr_io_read_yield},
1952 {"drain", moonbr_io_drain},
1953 {"drain_nb", moonbr_io_drain_nb},
1954 {"drain_call", moonbr_io_drain_call},
1955 {"drain_yield", moonbr_io_drain_yield},
1956 {"write", moonbr_io_write},
1957 {"write_nb", moonbr_io_write_nb},
1958 {"write_call", moonbr_io_write_call},
1959 {"write_yield", moonbr_io_write_yield},
1960 {"flush", moonbr_io_flush},
1961 {"flush_nb", moonbr_io_flush_nb},
1962 {"flush_call", moonbr_io_flush_call},
1963 {"flush_yield", moonbr_io_flush_yield},
1964 {"finish", moonbr_io_finish},
1965 {"close", moonbr_io_close},
1966 {"reset", moonbr_io_reset},
1967 #ifdef MOONBR_IO_USE_TLS
1968 {"starttls", moonbr_io_starttls},
1969 #endif
1970 {NULL, NULL}
1971 };
1973 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1974 {"__index", moonbr_io_handleindex},
1975 {"__newindex", moonbr_io_handlenewindex},
1976 {"__gc", moonbr_io_handlegc},
1977 {NULL, NULL}
1978 };
1980 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1981 {"accept", moonbr_io_accept},
1982 {"accept_nb", moonbr_io_accept_nb},
1983 {"close", moonbr_io_unlisten},
1984 {NULL, NULL}
1985 };
1987 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1988 {"__gc", moonbr_io_listenergc},
1989 {NULL, NULL}
1990 };
1992 static const struct luaL_Reg moonbr_io_child_methods[] = {
1993 {"kill", moonbr_io_kill},
1994 {"wait", moonbr_io_wait},
1995 {"wait_nb", moonbr_io_wait_nb},
1996 {"wait_call", moonbr_io_wait_call},
1997 {"wait_yield", moonbr_io_wait_yield},
1998 {NULL, NULL}
1999 };
2001 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
2002 {"__index", moonbr_io_childindex},
2003 {"__newindex", moonbr_io_childnewindex},
2004 {"__gc", moonbr_io_childgc},
2005 {NULL, NULL}
2006 };
2008 static const struct luaL_Reg moonbr_io_module_funcs[] = {
2009 {"localconnect", moonbr_io_localconnect},
2010 {"localconnect_nb", moonbr_io_localconnect_nb},
2011 {"tcpconnect", moonbr_io_tcpconnect},
2012 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
2013 {"locallisten", moonbr_io_locallisten},
2014 {"tcplisten", moonbr_io_tcplisten},
2015 {"exec", moonbr_io_exec},
2016 {"signalsocket", moonbr_io_signalsocket},
2017 {"getpid", moonbr_io_getpid},
2018 {"poll", moonbr_io_poll},
2019 {"timeref", moonbr_io_timeref},
2020 #ifdef MOONBR_IO_USE_TLS
2021 {"tlsconf", moonbr_io_tlsconf},
2022 #endif
2023 {NULL, NULL}
2024 };
2026 #ifdef MOONBR_IO_USE_TLS
2028 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
2029 {"__gc", moonbr_io_tlsconfgc},
2030 {NULL, NULL}
2031 };
2033 #endif /* MOONBR_IO_USE_TLS */
2035 int luaopen_moonbridge_io(lua_State *L) {
2037 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
2038 moonbr_io_signalfd_read = -1;
2039 moonbr_io_signalfd_write = -1;
2041 lua_newtable(L); // module
2043 lua_newtable(L); // public metatable
2044 lua_newtable(L); // handle methods
2045 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
2046 lua_pushvalue(L, -1);
2047 lua_setfield(L, -4, "handle_pt");
2048 lua_setfield(L, -2, "__index");
2049 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
2051 lua_newtable(L); // handle metatable
2052 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
2053 lua_pushvalue(L, -1);
2054 lua_setfield(L, -3, "handle_mt");
2055 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
2057 lua_newtable(L); // listener metatable
2058 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
2059 lua_newtable(L); // listener methods
2060 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
2061 lua_pushvalue(L, -1);
2062 lua_setfield(L, -4, "listener_pt");
2063 lua_setfield(L, -2, "__index");
2064 lua_pushvalue(L, -1);
2065 lua_setfield(L, -3, "listener_mt");
2066 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
2068 lua_newtable(L); // child methods
2069 luaL_setfuncs(L, moonbr_io_child_methods, 0);
2070 lua_pushvalue(L, -1);
2071 lua_setfield(L, -3, "child_pt");
2072 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
2073 lua_newtable(L); // child metatable
2074 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
2075 lua_pushvalue(L, -1);
2076 lua_setfield(L, -3, "child_mt");
2077 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
2079 #ifdef MOONBR_IO_USE_TLS
2080 if(tls_init()) {
2081 return luaL_error(L, "Could not initialize TLS library");
2083 lua_newtable(L); // tlsconf metatable
2084 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
2085 lua_pushvalue(L, -1);
2086 lua_setfield(L, -3, "tlsconf_mt");
2087 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
2088 #endif
2090 moonbr_io_pushhandle(L, 0);
2091 lua_setfield(L, -2, "stdin");
2092 moonbr_io_pushhandle(L, 1);
2093 lua_setfield(L, -2, "stdout");
2094 moonbr_io_pushhandle(L, 2);
2095 lua_setfield(L, -2, "stderr");
2097 lua_newtable(L); // signal numbers
2098 lua_pushinteger(L, SIGHUP); lua_setfield(L, -2, "HUP");
2099 lua_pushinteger(L, SIGINT); lua_setfield(L, -2, "INT");
2100 lua_pushinteger(L, SIGQUIT); lua_setfield(L, -2, "QUIT");
2101 lua_pushinteger(L, SIGABRT); lua_setfield(L, -2, "ABRT");
2102 lua_pushinteger(L, SIGPIPE); lua_setfield(L, -2, "PIPE");
2103 lua_pushinteger(L, SIGALRM); lua_setfield(L, -2, "ALRM");
2104 lua_pushinteger(L, SIGTERM); lua_setfield(L, -2, "TERM");
2105 lua_pushinteger(L, SIGTSTP); lua_setfield(L, -2, "TSTP");
2106 lua_pushinteger(L, SIGCONT); lua_setfield(L, -2, "CONT");
2107 lua_pushinteger(L, SIGVTALRM); lua_setfield(L, -2, "VTALRM");
2108 #ifdef SIGINFO
2109 lua_pushinteger(L, SIGINFO); lua_setfield(L, -2, "INFO");
2110 #endif
2111 lua_pushinteger(L, SIGUSR1); lua_setfield(L, -2, "USR1");
2112 lua_pushinteger(L, SIGUSR2); lua_setfield(L, -2, "USR2");
2113 lua_pushvalue(L, -1);
2114 lua_setfield(L, -3, "signals");
2115 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
2117 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
2118 return 1;

Impressum / About Us