moonbridge

view moonbridge_io.c @ 278:d4c82c90d244

Make moonbridge_io.signalsocket(...) return a new socket each time it is called
author jbe
date Tue Jun 06 20:01:29 2017 +0200 (2017-06-06)
parents 8b8be1a66a98
children 1a4f89f4c712
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_MAXSIGNUM 127
59 static int moonbr_io_signalfds[2*(MOONBR_IO_MAXSIGNUM+1)];
60 #define moonbr_io_signalfd_read(x) moonbr_io_signalfds[2*(x)+0]
61 #define moonbr_io_signalfd_write(x) moonbr_io_signalfds[2*(x)+1]
63 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
64 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
65 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
66 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
67 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
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] = {'.'};
1619 write(moonbr_io_signalfd_write(sig), buf, 1);
1620 errno = errno2;
1623 static int moonbr_io_signalsocket(lua_State *L) {
1624 int sig, fd;
1625 if (lua_type(L, 1) == LUA_TSTRING) {
1626 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
1627 lua_pushvalue(L, 1);
1628 lua_gettable(L, -2);
1629 sig = lua_tointeger(L, -1);
1630 if (!sig) {
1631 lua_pushvalue(L, 1);
1632 luaL_error(L, "Unknown signal \"%s\"", lua_tostring(L, 1));
1634 } else {
1635 sig = luaL_checkinteger(L, 1);
1637 if (sig < 1 || sig > MOONBR_IO_MAXSIGNUM) {
1638 luaL_error(L, "Signal number %i out of range", sig);
1640 if (moonbr_io_signalfd_read(sig) < 0) {
1641 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, moonbr_io_signalfds+2*sig)) {
1642 luaL_error(L, "Could not create socket pair for signal queueing");
1644 errno = 0;
1645 signal(sig, moonbr_io_signalhandler);
1646 if (errno) luaL_error(L, "Could not install signal handler (invalid signal number %i?)", sig);
1648 fd = dup(moonbr_io_signalfd_read(sig));
1649 if (fd < 0) luaL_error(L, "Could not create duplicated file descriptor for signal socket");
1650 moonbr_io_pushhandle(L, fd);
1651 return 1;
1654 static int moonbr_io_getpid(lua_State *L) {
1655 lua_pushinteger(L, getpid());
1656 return 1;
1659 #ifdef MOONBR_IO_USE_TLS
1661 #define moonbr_io_poll_tls() \
1662 if (!handle->tlshandshake) { \
1663 lua_pushboolean(L, 1); \
1664 return 1; \
1665 } \
1666 if (handle->tlshandshake == TLS_WANT_POLLIN) { \
1667 if (fd < 0) { \
1668 lua_pushboolean(L, 1); \
1669 return 1; \
1670 } \
1671 FD_SET(fd, &readfds); \
1672 if (fd+1 > nfds) nfds = fd+1; \
1673 continue; \
1674 } \
1675 if (handle->tlshandshake == TLS_WANT_POLLOUT) { \
1676 if (fd < 0) { \
1677 lua_pushboolean(L, 1); \
1678 return 1; \
1679 } \
1680 FD_SET(fd, &writefds); \
1681 if (fd+1 > nfds) nfds = fd+1; \
1682 continue; \
1683 } \
1684 while (0)
1686 #endif /* MOONBR_IO_USE_TLS */
1688 static int moonbr_io_poll(lua_State *L) {
1689 moonbr_io_handle_t *handle;
1690 moonbr_io_listener_t *listener;
1691 int fd, isnum;
1692 int nfds = 0;
1693 fd_set readfds, writefds, exceptfds;
1694 struct timeval timeout = {0, };
1695 int status;
1696 FD_ZERO(&readfds);
1697 FD_ZERO(&writefds);
1698 FD_ZERO(&exceptfds);
1699 if (!lua_isnoneornil(L, 1)) {
1700 luaL_checktype(L, 1, LUA_TTABLE);
1701 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1702 if (lua_toboolean(L, -1)) {
1703 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1704 if (handle) {
1705 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1706 fd = handle->fd;
1707 #if MOONBR_IO_USE_TLS
1708 moonbr_io_poll_tls();
1709 #endif
1710 if (
1711 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1712 handle->readbufin != handle->readbufout /* data pending in buffer */
1713 ) {
1714 lua_pushboolean(L, 1);
1715 return 1;
1717 } else {
1718 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1719 if (listener) {
1720 fd = listener->fd;
1721 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1722 } else {
1723 fd = lua_tointegerx(L, -2, &isnum);
1724 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1727 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1728 FD_SET(fd, &readfds);
1729 if (fd+1 > nfds) nfds = fd+1;
1733 if (!lua_isnoneornil(L, 2)) {
1734 luaL_checktype(L, 2, LUA_TTABLE);
1735 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1736 if (lua_toboolean(L, -1)) {
1737 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1738 if (handle) {
1739 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1740 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1741 fd = handle->fd;
1742 #if MOONBR_IO_USE_TLS
1743 moonbr_io_poll_tls();
1744 #endif
1745 } else {
1746 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1747 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1748 fd = lua_tointegerx(L, -2, &isnum);
1749 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1751 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1752 FD_SET(fd, &writefds);
1753 if (fd+1 > nfds) nfds = fd+1;
1757 if (!lua_isnoneornil(L, 3)) {
1758 lua_Number n;
1759 n = lua_tonumberx(L, 3, &isnum);
1760 if (isnum && n<0) {
1761 lua_pushboolean(L, 0);
1762 lua_pushliteral(L, "Negative timeout");
1763 return 2;
1764 } else if (isnum && n>=0 && n<100000000) {
1765 timeout.tv_sec = n;
1766 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1767 } else {
1768 luaL_argcheck(L, 0, 3, "not a valid timeout");
1770 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1771 } else {
1772 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1774 if (status == -1) {
1775 if (errno == EINTR) {
1776 lua_pushboolean(L, 1);
1777 return 1;
1778 } else {
1779 moonbr_io_prepare_errmsg();
1780 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1782 } else if (status == 0) {
1783 lua_pushboolean(L, 0);
1784 lua_pushliteral(L, "Timeout while polling file descriptors");
1785 return 2;
1786 } else {
1787 lua_pushboolean(L, 1);
1788 return 1;
1792 static int moonbr_io_timeref(lua_State *L) {
1793 lua_Number sub;
1794 struct timespec tp;
1795 sub = luaL_optnumber(L, 1, 0);
1796 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1797 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1799 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1800 return 1;
1803 #ifdef MOONBR_IO_USE_TLS
1805 #define moonbr_io_tlsconf_string(name, field, func) \
1806 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1807 lua_getfield(L, 1, (field)); \
1808 valuetype = lua_type(L, -1); \
1809 if (valuetype != LUA_TNIL) { \
1810 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1811 value = lua_tostring(L, -1); \
1812 if (func(tlsconf->config, value)) { \
1813 lua_pushnil(L); \
1814 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
1815 return 2; \
1816 } \
1817 } \
1818 lua_pop(L, 1);
1820 #define moonbr_io_tlsconf_binary(name, field, func) \
1821 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1822 lua_getfield(L, 1, (field)); \
1823 valuetype = lua_type(L, -1); \
1824 if (valuetype != LUA_TNIL) { \
1825 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1826 value = lua_tolstring(L, -1, &valuelen); \
1827 if (func(tlsconf->config, (void *)value, valuelen)) { \
1828 lua_pushnil(L); \
1829 lua_pushliteral(L, "Could not set " name); \
1830 return 2; \
1831 } \
1832 } \
1833 lua_pop(L, 1);
1835 static int moonbr_io_tlsconf(lua_State *L) {
1836 moonbr_io_tlsconf_t *tlsconf;
1837 int valuetype;
1838 const char *value;
1839 size_t valuelen;
1840 luaL_checktype(L, 1, LUA_TTABLE);
1841 tlsconf = lua_newuserdata(L, sizeof(moonbr_io_tlsconf_t));
1842 tlsconf->config = tls_config_new();
1843 if (!tlsconf->config) {
1844 return luaL_error(L, "Could not allocate memory for TLS configuration");
1846 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
1847 lua_getfield(L, 1, "mode");
1848 value = lua_tostring(L, -1);
1849 if (value && !strcmp(value, "server")) tlsconf->server = 1;
1850 else if (value && !strcmp(value, "client")) tlsconf->server = 0;
1851 else luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
1852 lua_pop(L, 1);
1853 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
1854 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
1855 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
1856 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
1857 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
1858 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
1859 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
1860 #if LUA_VERSION_NUM >= 503
1861 valuetype = lua_getfield(L, 1, "verify_client");
1862 #else
1863 lua_getfield(L, 1, "verify_client");
1864 #endif
1865 if (lua_toboolean(L, -1)) {
1866 value = lua_tostring(L, -1);
1867 if (value && !strcmp(value, "required")) {
1868 tls_config_verify_client(tlsconf->config);
1869 } else if (value && !strcmp(value, "optional")) {
1870 tls_config_verify_client_optional(tlsconf->config);
1871 } else {
1872 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
1875 lua_pop(L, 1);
1876 // TODO: configurable legacy support
1877 // tls_config_set_protocols(tlsconf->config, TLS_PROTOCOLS_ALL);
1878 // tls_config_set_ciphers(tlsconf->config, "legacy");
1879 return 1;
1882 static int moonbr_io_tlsconfgc(lua_State *L) {
1883 moonbr_io_tlsconf_t *tlsconf;
1884 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1885 if (tlsconf->config) tls_config_free(tlsconf->config);
1886 tlsconf->config = NULL;
1887 return 0;
1890 static int moonbr_io_starttls(lua_State *L) {
1891 moonbr_io_handle_t *handle;
1892 moonbr_io_tlsconf_t *tlsconf;
1893 const char *servername;
1894 struct tls *tls, *tls2;
1895 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1896 if (lua_type(L, 2) == LUA_TTABLE) {
1897 lua_pushcfunction(L, moonbr_io_tlsconf);
1898 lua_pushvalue(L, 2);
1899 lua_call(L, 1, 2);
1900 if (lua_isnil(L, -2)) return 2;
1901 lua_pop(L, 1);
1902 lua_replace(L, 2);
1904 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
1905 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
1906 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
1907 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
1908 if (handle->readbufin || handle->writebufin) {
1909 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
1911 if (tlsconf->server) tls = tls_server();
1912 else {
1913 servername = luaL_checkstring(L, 3);
1914 tls = tls_client();
1916 if (!tls) {
1917 return luaL_error(L, "Could not allocate memory for TLS context");
1919 if (tls_configure(tls, tlsconf->config)) goto moonbr_io_starttls_error;
1920 if (tlsconf->server) {
1921 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
1922 handle->servertls = tls;
1923 handle->tls = tls2;
1924 } else {
1925 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
1926 handle->tls = tls;
1928 lua_settop(L, 1);
1929 return 1;
1930 moonbr_io_starttls_error:
1931 lua_pushnil(L);
1932 lua_pushstring(L, tls_error(tls));
1933 tls_free(tls);
1934 return 2;
1937 #endif /* MOONBR_IO_USE_TLS */
1939 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1940 {"read", moonbr_io_read},
1941 {"read_nb", moonbr_io_read_nb},
1942 {"read_call", moonbr_io_read_call},
1943 {"read_yield", moonbr_io_read_yield},
1944 {"drain", moonbr_io_drain},
1945 {"drain_nb", moonbr_io_drain_nb},
1946 {"drain_call", moonbr_io_drain_call},
1947 {"drain_yield", moonbr_io_drain_yield},
1948 {"write", moonbr_io_write},
1949 {"write_nb", moonbr_io_write_nb},
1950 {"write_call", moonbr_io_write_call},
1951 {"write_yield", moonbr_io_write_yield},
1952 {"flush", moonbr_io_flush},
1953 {"flush_nb", moonbr_io_flush_nb},
1954 {"flush_call", moonbr_io_flush_call},
1955 {"flush_yield", moonbr_io_flush_yield},
1956 {"finish", moonbr_io_finish},
1957 {"close", moonbr_io_close},
1958 {"reset", moonbr_io_reset},
1959 #ifdef MOONBR_IO_USE_TLS
1960 {"starttls", moonbr_io_starttls},
1961 #endif
1962 {NULL, NULL}
1963 };
1965 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1966 {"__index", moonbr_io_handleindex},
1967 {"__newindex", moonbr_io_handlenewindex},
1968 {"__gc", moonbr_io_handlegc},
1969 {NULL, NULL}
1970 };
1972 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1973 {"accept", moonbr_io_accept},
1974 {"accept_nb", moonbr_io_accept_nb},
1975 {"close", moonbr_io_unlisten},
1976 {NULL, NULL}
1977 };
1979 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1980 {"__gc", moonbr_io_listenergc},
1981 {NULL, NULL}
1982 };
1984 static const struct luaL_Reg moonbr_io_child_methods[] = {
1985 {"kill", moonbr_io_kill},
1986 {"wait", moonbr_io_wait},
1987 {"wait_nb", moonbr_io_wait_nb},
1988 {"wait_call", moonbr_io_wait_call},
1989 {"wait_yield", moonbr_io_wait_yield},
1990 {NULL, NULL}
1991 };
1993 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
1994 {"__index", moonbr_io_childindex},
1995 {"__newindex", moonbr_io_childnewindex},
1996 {"__gc", moonbr_io_childgc},
1997 {NULL, NULL}
1998 };
2000 static const struct luaL_Reg moonbr_io_module_funcs[] = {
2001 {"localconnect", moonbr_io_localconnect},
2002 {"localconnect_nb", moonbr_io_localconnect_nb},
2003 {"tcpconnect", moonbr_io_tcpconnect},
2004 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
2005 {"locallisten", moonbr_io_locallisten},
2006 {"tcplisten", moonbr_io_tcplisten},
2007 {"exec", moonbr_io_exec},
2008 {"signalsocket", moonbr_io_signalsocket},
2009 {"getpid", moonbr_io_getpid},
2010 {"poll", moonbr_io_poll},
2011 {"timeref", moonbr_io_timeref},
2012 #ifdef MOONBR_IO_USE_TLS
2013 {"tlsconf", moonbr_io_tlsconf},
2014 #endif
2015 {NULL, NULL}
2016 };
2018 #ifdef MOONBR_IO_USE_TLS
2020 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
2021 {"__gc", moonbr_io_tlsconfgc},
2022 {NULL, NULL}
2023 };
2025 #endif /* MOONBR_IO_USE_TLS */
2027 int luaopen_moonbridge_io(lua_State *L) {
2029 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
2031 int i;
2032 for (i=0; i<=MOONBR_IO_MAXSIGNUM; i++) {
2033 moonbr_io_signalfd_read(i) = -1;
2034 moonbr_io_signalfd_write(i) = -1;
2038 lua_newtable(L); // module
2040 lua_newtable(L); // public metatable
2041 lua_newtable(L); // handle methods
2042 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
2043 lua_pushvalue(L, -1);
2044 lua_setfield(L, -4, "handle_pt");
2045 lua_setfield(L, -2, "__index");
2046 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
2048 lua_newtable(L); // handle metatable
2049 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
2050 lua_pushvalue(L, -1);
2051 lua_setfield(L, -3, "handle_mt");
2052 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
2054 lua_newtable(L); // listener metatable
2055 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
2056 lua_newtable(L); // listener methods
2057 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
2058 lua_pushvalue(L, -1);
2059 lua_setfield(L, -4, "listener_pt");
2060 lua_setfield(L, -2, "__index");
2061 lua_pushvalue(L, -1);
2062 lua_setfield(L, -3, "listener_mt");
2063 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
2065 lua_newtable(L); // child methods
2066 luaL_setfuncs(L, moonbr_io_child_methods, 0);
2067 lua_pushvalue(L, -1);
2068 lua_setfield(L, -3, "child_pt");
2069 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
2070 lua_newtable(L); // child metatable
2071 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
2072 lua_pushvalue(L, -1);
2073 lua_setfield(L, -3, "child_mt");
2074 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
2076 #ifdef MOONBR_IO_USE_TLS
2077 if(tls_init()) {
2078 return luaL_error(L, "Could not initialize TLS library");
2080 lua_newtable(L); // tlsconf metatable
2081 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
2082 lua_pushvalue(L, -1);
2083 lua_setfield(L, -3, "tlsconf_mt");
2084 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
2085 #endif
2087 moonbr_io_pushhandle(L, 0);
2088 lua_setfield(L, -2, "stdin");
2089 moonbr_io_pushhandle(L, 1);
2090 lua_setfield(L, -2, "stdout");
2091 moonbr_io_pushhandle(L, 2);
2092 lua_setfield(L, -2, "stderr");
2094 lua_newtable(L); // signal numbers
2095 lua_pushinteger(L, SIGHUP); lua_setfield(L, -2, "HUP");
2096 lua_pushinteger(L, SIGINT); lua_setfield(L, -2, "INT");
2097 lua_pushinteger(L, SIGQUIT); lua_setfield(L, -2, "QUIT");
2098 lua_pushinteger(L, SIGABRT); lua_setfield(L, -2, "ABRT");
2099 lua_pushinteger(L, SIGPIPE); lua_setfield(L, -2, "PIPE");
2100 lua_pushinteger(L, SIGALRM); lua_setfield(L, -2, "ALRM");
2101 lua_pushinteger(L, SIGTERM); lua_setfield(L, -2, "TERM");
2102 lua_pushinteger(L, SIGTSTP); lua_setfield(L, -2, "TSTP");
2103 lua_pushinteger(L, SIGCONT); lua_setfield(L, -2, "CONT");
2104 lua_pushinteger(L, SIGVTALRM); lua_setfield(L, -2, "VTALRM");
2105 #ifdef SIGINFO
2106 lua_pushinteger(L, SIGINFO); lua_setfield(L, -2, "INFO");
2107 #endif
2108 lua_pushinteger(L, SIGUSR1); lua_setfield(L, -2, "USR1");
2109 lua_pushinteger(L, SIGUSR2); lua_setfield(L, -2, "USR2");
2110 lua_pushvalue(L, -1);
2111 lua_setfield(L, -3, "signals");
2112 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
2114 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
2115 return 1;

Impressum / About Us