moonbridge

view moonbridge_io.c @ 260:1dc729343830

Use (blocking) tls_close() on :finish() and :close()
author jbe
date Mon Sep 19 01:12:38 2016 +0200 (2016-09-19)
parents 385b6607785a
children 6c634c96805b
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_HANDLE_MT_REGKEY "moonbridge_io_handle"
59 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
60 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
61 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
62 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
64 #ifdef MOONBR_IO_USE_TLS
66 #define MOONBR_IO_TLSCONF_MT_REGKEY "moonbridge_io_tlsconf"
68 typedef struct {
69 struct tls_config *config;
70 int server;
71 } moonbr_io_tlsconf_t;
73 #endif /* MOONBR_IO_USE_TLS */
75 typedef struct {
76 int fd;
77 int issock;
78 sa_family_t addrfam;
79 int finished;
80 int closed;
81 int nonblocking;
82 int nopush;
83 int readerr;
84 int readbufin;
85 int readbufout;
86 int writeerr;
87 size_t writeleft;
88 size_t flushedleft;
89 #if LUA_VERSION_NUM >= 503
90 lua_Integer writeqin;
91 lua_Integer writeqout;
92 #else
93 int writeqin;
94 int writeqout;
95 #endif
96 size_t writeqoff;
97 int writebufin;
98 int writebufout;
99 char readbuf[MOONBR_IO_READBUFLEN];
100 char writebuf[MOONBR_IO_WRITEBUFLEN];
101 #ifdef MOONBR_IO_USE_TLS
102 struct tls *tls;
103 struct tls *servertls;
104 int tlshandshake;
105 #endif
106 } moonbr_io_handle_t;
108 typedef struct {
109 int fd;
110 sa_family_t addrfam;
111 int nonblocking;
112 } moonbr_io_listener_t;
114 typedef struct {
115 pid_t pid;
116 } moonbr_io_child_t;
118 static int moonbr_io_yield(lua_State *L) {
119 return lua_yield(L, lua_gettop(L));
120 }
122 #if LUA_VERSION_NUM >= 503
123 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
124 #else
125 static int moonbr_io_cont_returnall(lua_State *L) {
126 #endif
127 return lua_gettop(L);
128 }
130 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
131 static int yieldfunc(lua_State *L) { \
132 int args; \
133 lua_pushcfunction(L, callfunc); \
134 lua_insert(L, 1); \
135 args = lua_gettop(L); \
136 lua_pushcfunction(L, moonbr_io_yield); \
137 lua_insert(L, 3); \
138 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
139 return lua_gettop(L); \
140 }
142 static int moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
143 int flags;
144 if (handle->nonblocking == nonblocking) return 0;
145 flags = fcntl(handle->fd, F_GETFL, 0);
146 if (flags == -1) return -1;
147 if (nonblocking) flags |= O_NONBLOCK;
148 else flags &= ~O_NONBLOCK;
149 if (fcntl(handle->fd, F_SETFL, flags) == -1) return -1;
150 handle->nonblocking = nonblocking;
151 return 0;
152 }
154 static int moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
155 struct linger lingerval = { 0, };
156 if (!handle->issock) return 0;
157 if (timeout >= 0) {
158 lingerval.l_onoff = 1;
159 lingerval.l_linger = timeout;
160 }
161 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) return -1;
162 return 0;
163 }
165 static inline int moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
166 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
167 if (
168 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
169 handle->nopush == nopush
170 ) return 0;
171 #if defined(TCP_NOPUSH)
172 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) return -1;
173 #elif defined(TCP_CORK)
174 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) return -1;
175 #endif
176 handle->nopush = nopush;
177 #else
178 #warning Neither TCP_NOPUSH nor TCP_CORK is available
179 #endif
180 return 0;
181 }
183 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
184 moonbr_io_handle_t *handle;
185 lua_Integer maxread;
186 const char *terminatorstr;
187 size_t terminatorlen;
188 char terminator = 0; /* initialize to avoid compiler warning */
189 luaL_Buffer luabuf;
190 size_t luabufcnt = 0;
191 int remaining;
192 char *terminatorpos;
193 ssize_t bytesread;
194 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
195 maxread = luaL_optinteger(L, 2, -1);
196 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
197 if (terminatorlen) {
198 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
199 terminator = terminatorstr[0];
200 }
201 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
202 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
203 if (handle->readerr) {
204 lua_pushnil(L);
205 lua_pushliteral(L, "Previous read error");
206 return 2;
207 }
208 if (handle->fd < 0) {
209 /* fake EOF to simulate shutdown */
210 if (!drain) lua_pushliteral(L, "");
211 else lua_pushinteger(L, 0);
212 lua_pushliteral(L, "eof");
213 return 2;
214 }
215 handle->readerr = 1;
216 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
217 if (!drain) luaL_buffinit(L, &luabuf);
218 while (1) {
219 remaining = -1;
220 terminatorpos = NULL;
221 if (
222 maxread >= 0 &&
223 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
224 ) {
225 remaining = (size_t)maxread - luabufcnt;
226 if (terminatorlen) {
227 terminatorpos = memchr(
228 handle->readbuf + handle->readbufout,
229 terminator,
230 remaining
231 );
232 }
233 } else if (terminatorlen) {
234 terminatorpos = memchr(
235 handle->readbuf + handle->readbufout,
236 terminator,
237 handle->readbufin - handle->readbufout
238 );
239 }
240 if (terminatorpos) remaining = 1 + (
241 terminatorpos - (handle->readbuf + handle->readbufout)
242 );
243 if (remaining >= 0) {
244 if (!drain) {
245 luaL_addlstring(
246 &luabuf,
247 handle->readbuf + handle->readbufout,
248 remaining
249 );
250 luaL_pushresult(&luabuf);
251 } else {
252 lua_pushinteger(L, luabufcnt + remaining);
253 }
254 if (terminatorpos) lua_pushliteral(L, "term");
255 else lua_pushliteral(L, "maxlen");
256 handle->readbufout += remaining;
257 if (handle->readbufout == handle->readbufin) {
258 handle->readbufin = 0;
259 handle->readbufout = 0;
260 }
261 handle->readerr = 0;
262 return 2;
263 }
264 if (!drain) luaL_addlstring(
265 &luabuf,
266 handle->readbuf + handle->readbufout,
267 handle->readbufin - handle->readbufout
268 );
269 luabufcnt += handle->readbufin - handle->readbufout;
270 handle->readbufout = 0;
271 #ifdef MOONBR_IO_USE_TLS
272 if (handle->tls) {
273 do {
274 if (!handle->tlshandshake) {
275 do bytesread = tls_handshake(handle->tls);
276 while (!nonblocking && (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT));
277 if (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT) {
278 handle->tlshandshake = bytesread;
279 errno = EAGAIN;
280 break;
281 }
282 if (bytesread < 0) {
283 lua_pushnil(L);
284 lua_pushstring(L, tls_error(handle->tls));
285 return 2;
286 }
287 handle->tlshandshake = 1;
288 }
289 do bytesread = tls_read(handle->tls, handle->readbuf, MOONBR_IO_READBUFLEN);
290 while (!nonblocking && (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT));
291 if (bytesread == TLS_WANT_POLLIN || bytesread == TLS_WANT_POLLOUT) {
292 errno = EAGAIN;
293 break;
294 }
295 if (bytesread < 0) {
296 lua_pushnil(L);
297 lua_pushstring(L, tls_error(handle->tls));
298 return 2;
299 }
300 } while (0);
301 }
302 else
303 #endif
304 do bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
305 while (bytesread < 0 && (errno == EINTR));
306 if (
307 bytesread == 0 || (
308 nonblocking &&
309 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
310 )
311 ) {
312 handle->readbufin = 0;
313 if (!drain) luaL_pushresult(&luabuf);
314 else lua_pushinteger(L, luabufcnt);
315 if (bytesread == 0) lua_pushliteral(L, "eof");
316 else lua_pushliteral(L, "block");
317 handle->readerr = 0;
318 return 2;
319 }
320 if (bytesread < 0) moonbr_io_return_errmsg();
321 handle->readbufin = bytesread;
322 }
323 }
325 static int moonbr_io_read(lua_State *L) {
326 return moonbr_io_read_impl(L, 0, 0);
327 }
329 static int moonbr_io_read_nb(lua_State *L) {
330 return moonbr_io_read_impl(L, 1, 0);
331 }
333 static int moonbr_io_drain(lua_State *L) {
334 return moonbr_io_read_impl(L, 0, 1);
335 }
337 static int moonbr_io_drain_nb(lua_State *L) {
338 return moonbr_io_read_impl(L, 1, 1);
339 }
341 #if LUA_VERSION_NUM >= 503
342 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
343 #else
344 static int moonbr_io_read_cont(lua_State *L) {
345 #endif
346 lua_Integer remaining;
347 size_t len;
348 #if !(LUA_VERSION_NUM >= 503)
349 int ctx = 0;
350 lua_getctx(L, &ctx);
351 #endif
352 remaining = lua_tointeger(L, 3);
353 while (1) {
354 lua_pushcfunction(L, moonbr_io_read_nb);
355 lua_pushvalue(L, 1);
356 lua_pushvalue(L, 3);
357 lua_pushvalue(L, 4);
358 lua_call(L, 3, 2);
359 if (lua_isnil(L, -2)) return 2;
360 lua_insert(L, -2);
361 len = lua_rawlen(L, -1);
362 if (ctx == 0) {
363 lua_replace(L, 5);
364 ctx = 1;
365 } else if (ctx == 1) {
366 lua_pushvalue(L, 5);
367 lua_newtable(L);
368 lua_replace(L, 5);
369 lua_rawseti(L, 5, 2);
370 lua_rawseti(L, 5, 1);
371 ctx = 2;
372 } else {
373 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
374 }
375 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
376 lua_pop(L, 1);
377 if (remaining >= 0 && len) {
378 remaining -= len;
379 lua_pushinteger(L, remaining);
380 lua_replace(L, 3);
381 }
382 lua_pushvalue(L, 2);
383 lua_callk(L, 0, 0, ctx, moonbr_io_read_cont);
384 }
385 if (ctx == 1) {
386 lua_pushvalue(L, 5);
387 } else {
388 luaL_Buffer buf;
389 lua_Integer i, chunkcount;
390 chunkcount = lua_rawlen(L, 5);
391 luaL_buffinit(L, &buf);
392 for (i=1; i<=chunkcount && i>0; i++) {
393 lua_rawgeti(L, 5, i);
394 luaL_addvalue(&buf);
395 }
396 luaL_pushresult(&buf);
397 }
398 lua_pushvalue(L, -2);
399 return 2;
400 }
402 static int moonbr_io_read_call(lua_State *L) {
403 lua_settop(L, 4);
404 lua_pushnil(L);
405 #if LUA_VERSION_NUM >= 503
406 return moonbr_io_read_cont(L, 0, 0);
407 #else
408 return moonbr_io_read_cont(L);
409 #endif
410 }
412 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
414 #if LUA_VERSION_NUM >= 503
415 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
416 #else
417 static int moonbr_io_drain_cont(lua_State *L) {
418 #endif
419 lua_Integer remaining, len;
420 size_t totallen = 0;
421 #if !(LUA_VERSION_NUM >= 503)
422 int ctx = 0;
423 lua_getctx(L, &ctx);
424 #endif
425 remaining = lua_tointeger(L, 3);
426 while (1) {
427 lua_pushcfunction(L, moonbr_io_drain_nb);
428 lua_pushvalue(L, 1);
429 lua_pushvalue(L, 3);
430 lua_pushvalue(L, 4);
431 lua_call(L, 3, 2);
432 if (lua_isnil(L, -2)) return 2;
433 lua_insert(L, -2);
434 len = lua_tointeger(L, -1);
435 lua_pop(L, 1);
436 totallen += len;
437 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
438 lua_pop(L, 1);
439 if (remaining >= 0 && len) {
440 remaining -= len;
441 lua_pushinteger(L, remaining);
442 lua_replace(L, 3);
443 }
444 lua_pushvalue(L, 2);
445 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
446 }
447 lua_pushinteger(L, totallen);
448 lua_pushvalue(L, -2);
449 return 2;
450 }
452 static int moonbr_io_drain_call(lua_State *L) {
453 #if LUA_VERSION_NUM >= 503
454 return moonbr_io_drain_cont(L, 0, 0);
455 #else
456 return moonbr_io_drain_cont(L);
457 #endif
458 }
460 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
462 #ifdef MOONBR_IO_USE_TLS
464 #define moonbr_io_write_tls(buf, buflen) \
465 if (handle->tls) { \
466 do { \
467 if (!handle->tlshandshake) { \
468 do written = tls_handshake(handle->tls); \
469 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
470 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
471 handle->tlshandshake = written; \
472 errno = EAGAIN; \
473 break; \
474 } \
475 if (written < 0) { \
476 lua_pushnil(L); \
477 lua_pushstring(L, tls_error(handle->tls)); \
478 return 2; \
479 } \
480 handle->tlshandshake = 1; \
481 } \
482 do written = tls_write(handle->tls, (buf), (buflen)); \
483 while (!nonblocking && (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT)); \
484 if (written == TLS_WANT_POLLIN || written == TLS_WANT_POLLOUT) { \
485 errno = EAGAIN; \
486 break; \
487 } \
488 if (written < 0) { \
489 lua_pushnil(L); \
490 lua_pushstring(L, tls_error(handle->tls)); \
491 return 2; \
492 } \
493 } while (0); \
494 } \
495 else
497 #endif /* MOONBR_IO_USE_TLS */
499 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
500 moonbr_io_handle_t *handle;
501 int i, top;
502 const char *str;
503 size_t strlen;
504 ssize_t written;
505 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
506 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
507 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
508 if (handle->writeerr) {
509 lua_pushnil(L);
510 lua_pushliteral(L, "Previous write error");
511 return 2;
512 }
513 handle->writeerr = 1;
514 if (moonbr_io_handle_set_nonblocking(L, handle, nonblocking)) moonbr_io_return_errmsg();
515 top = lua_gettop(L);
516 lua_getuservalue(L, 1);
517 lua_getfield(L, -1, "writequeue");
518 for (i=2; i<=top; i++) {
519 luaL_checklstring(L, i, &strlen);
520 lua_pushvalue(L, i);
521 lua_rawseti(L, -2, handle->writeqin++);
522 handle->writeleft += strlen;
523 }
524 if (flush) handle->flushedleft = handle->writeleft;
525 while (handle->writeqout != handle->writeqin) {
526 lua_rawgeti(L, -1, handle->writeqout);
527 str = lua_tolstring(L, -1, &strlen);
528 while (handle->writeqoff < strlen) {
529 if (
530 strlen - handle->writeqoff <
531 MOONBR_IO_WRITEBUFLEN - handle->writebufin
532 ) {
533 memcpy(
534 handle->writebuf + handle->writebufin,
535 str + handle->writeqoff,
536 strlen - handle->writeqoff
537 );
538 handle->writebufin += strlen - handle->writeqoff;
539 break;
540 } else {
541 memcpy(
542 handle->writebuf + handle->writebufin,
543 str + handle->writeqoff,
544 MOONBR_IO_WRITEBUFLEN - handle->writebufin
545 );
546 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
547 handle->writebufin = MOONBR_IO_WRITEBUFLEN;
548 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
549 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
550 #ifdef MOONBR_IO_USE_TLS
551 moonbr_io_write_tls(
552 handle->writebuf + handle->writebufout,
553 MOONBR_IO_WRITEBUFLEN - handle->writebufout
554 )
555 #endif
556 written = write(
557 handle->fd,
558 handle->writebuf + handle->writebufout,
559 MOONBR_IO_WRITEBUFLEN - handle->writebufout
560 );
561 if (written < 0) {
562 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
563 goto moonbr_io_write_impl_block;
564 } else if (errno != EINTR) moonbr_io_return_errmsg();
565 } else {
566 handle->writebufout += written;
567 handle->writeleft -= written;
568 if (handle->flushedleft) {
569 if (written >= handle->flushedleft) {
570 handle->flushedleft = 0;
571 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
572 } else {
573 handle->flushedleft -= written;
574 }
575 }
576 }
577 }
578 handle->writebufin = 0;
579 handle->writebufout = 0;
580 }
581 }
582 handle->writeqoff = 0;
583 lua_pop(L, 1);
584 lua_pushnil(L);
585 lua_rawseti(L, -2, handle->writeqout++);
586 }
587 while (handle->flushedleft) {
588 if (moonbr_io_handle_set_nopush(L, handle, 1)) moonbr_io_return_errmsg();
589 #ifdef MOONBR_IO_USE_TLS
590 moonbr_io_write_tls(
591 handle->writebuf + handle->writebufout,
592 handle->writebufin - handle->writebufout
593 )
594 #endif
595 written = write(
596 handle->fd,
597 handle->writebuf + handle->writebufout,
598 handle->writebufin - handle->writebufout
599 );
600 if (written < 0) {
601 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
602 goto moonbr_io_write_impl_block;
603 } else if (errno != EINTR) moonbr_io_return_errmsg();
604 } else {
605 handle->writebufout += written;
606 handle->writeleft -= written;
607 if (handle->flushedleft) {
608 if (written >= handle->flushedleft) {
609 handle->flushedleft = 0;
610 if (moonbr_io_handle_set_nopush(L, handle, 0)) moonbr_io_return_errmsg();
611 } else {
612 handle->flushedleft -= written;
613 }
614 }
615 }
616 }
617 if (handle->writebufout == handle->writebufin) {
618 handle->writebufin = 0;
619 handle->writebufout = 0;
620 }
621 if (nonblocking) lua_pushinteger(L, 0);
622 else lua_pushvalue(L, 1);
623 handle->writeerr = 0;
624 return 1;
625 moonbr_io_write_impl_block:
626 lua_pushinteger(L, handle->writeleft);
627 handle->writeerr = 0;
628 return 1;
629 }
631 static int moonbr_io_write(lua_State *L) {
632 return moonbr_io_write_impl(L, 0, 0);
633 }
635 static int moonbr_io_write_nb(lua_State *L) {
636 return moonbr_io_write_impl(L, 1, 0);
637 }
639 static int moonbr_io_flush(lua_State *L) {
640 return moonbr_io_write_impl(L, 0, 1);
641 }
643 static int moonbr_io_flush_nb(lua_State *L) {
644 return moonbr_io_write_impl(L, 1, 1);
645 }
647 #if LUA_VERSION_NUM >= 503
648 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
649 #else
650 static int moonbr_io_write_cont(lua_State *L) {
651 #endif
652 while (1) {
653 lua_pushcfunction(L, moonbr_io_write_nb);
654 lua_pushvalue(L, 1);
655 lua_call(L, 1, 2);
656 if (lua_isnil(L, -2)) return 2;
657 if (!lua_tointeger(L, -2)) {
658 lua_pushvalue(L, 1);
659 return 1;
660 }
661 lua_pop(L, 2);
662 lua_pushvalue(L, 2);
663 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
664 }
665 }
667 static int moonbr_io_write_call(lua_State *L) {
668 lua_pushcfunction(L, moonbr_io_write_nb);
669 lua_insert(L, 3);
670 lua_pushvalue(L, 1);
671 lua_insert(L, 4);
672 lua_call(L, lua_gettop(L) - 3, 2);
673 if (lua_isnil(L, -2)) return 2;
674 if (!lua_tointeger(L, -2)) {
675 lua_pushvalue(L, 1);
676 return 1;
677 }
678 #if LUA_VERSION_NUM >= 503
679 return moonbr_io_write_cont(L, 0, 0);
680 #else
681 return moonbr_io_write_cont(L);
682 #endif
683 }
685 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
687 static int moonbr_io_flush_call(lua_State *L) {
688 lua_pushcfunction(L, moonbr_io_flush_nb);
689 lua_insert(L, 3);
690 lua_pushvalue(L, 1);
691 lua_insert(L, 4);
692 lua_call(L, lua_gettop(L) - 3, 2);
693 if (lua_isnil(L, -2)) return 2;
694 if (!lua_tointeger(L, -2)) {
695 lua_pushvalue(L, 1);
696 return 1;
697 }
698 #if LUA_VERSION_NUM >= 503
699 return moonbr_io_write_cont(L, 0, 0);
700 #else
701 return moonbr_io_write_cont(L);
702 #endif
703 }
705 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
707 static int moonbr_io_finish(lua_State *L) {
708 moonbr_io_handle_t *handle;
709 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
710 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
711 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
712 if (handle->writeleft) {
713 lua_pushcfunction(L, moonbr_io_flush);
714 lua_pushvalue(L, 1);
715 if (lua_pcall(L, 1, 2, 0)) {
716 handle->finished = 1;
717 lua_error(L);
718 }
719 if (!lua_toboolean(L, -2)) {
720 handle->finished = 1;
721 return 2;
722 }
723 }
724 handle->finished = 1;
725 #ifdef MOONBR_IO_USE_TLS
726 if ((handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) && !handle->tls) {
727 #else
728 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
729 #endif
730 if (shutdown(handle->fd, SHUT_WR)) moonbr_io_return_errmsg();
731 } else {
732 #ifdef MOONBR_IO_USE_TLS
733 if (handle->tls) {
734 int status;
735 if (moonbr_io_handle_set_nonblocking(L, handle, 1)) moonbr_io_return_errmsg();
736 do status = tls_close(handle->tls);
737 while (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT);
738 if (status) {
739 close(handle->fd);
740 handle->fd = -1;
741 lua_pushnil(L);
742 lua_pushstring(L, tls_error(handle->tls));
743 return 2;
744 }
745 }
746 #endif
747 if (close(handle->fd)) {
748 handle->fd = -1;
749 moonbr_io_return_errmsg();
750 }
751 handle->fd = -1; /* fake EOF on read */
752 }
753 lua_pushboolean(L, 1);
754 return 1;
755 }
757 static int moonbr_io_close_impl(lua_State *L, int reset) {
758 moonbr_io_handle_t *handle;
759 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
760 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
761 if (!reset && handle->fd >= 0) {
762 if (handle->writeleft) {
763 lua_pushcfunction(L, moonbr_io_flush);
764 lua_pushvalue(L, 1);
765 if (lua_pcall(L, 1, 2, 0)) {
766 handle->closed = 1;
767 close(handle->fd);
768 handle->fd = -1;
769 lua_error(L);
770 }
771 handle->closed = 1;
772 if (!lua_toboolean(L, -2)) {
773 close(handle->fd);
774 handle->fd = -1;
775 return 2;
776 }
777 } else {
778 handle->closed = 1;
779 }
780 #ifdef MOONBR_IO_USE_TLS
781 if (handle->tls) {
782 int status;
783 if (moonbr_io_handle_set_nonblocking(L, handle, 1)) moonbr_io_return_errmsg();
784 do status = tls_close(handle->tls);
785 while (status == TLS_WANT_POLLIN || status == TLS_WANT_POLLOUT);
786 if (status) {
787 close(handle->fd);
788 handle->fd = -1;
789 lua_pushnil(L);
790 lua_pushstring(L, tls_error(handle->tls));
791 return 2;
792 }
793 }
794 #endif
795 if (moonbr_io_handle_set_linger(L, handle, -1)) {
796 moonbr_io_prepare_errmsg();
797 close(handle->fd);
798 handle->fd = -1;
799 moonbr_io_return_prepared_errmsg();
800 }
801 } else {
802 handle->closed = 1;
803 }
804 if (handle->fd >= 0) {
805 if (close(handle->fd)) {
806 handle->fd = -1;
807 moonbr_io_return_errmsg();
808 }
809 handle->fd = -1;
810 }
811 lua_pushboolean(L, 1);
812 return 1;
814 }
816 static int moonbr_io_close(lua_State *L) {
817 return moonbr_io_close_impl(L, 0);
818 }
820 static int moonbr_io_reset(lua_State *L) {
821 return moonbr_io_close_impl(L, 1);
822 }
824 static int moonbr_io_handlegc(lua_State *L) {
825 moonbr_io_handle_t *handle;
826 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
827 if (handle->fd >= 0) {
828 lua_pushcfunction(L, moonbr_io_reset);
829 lua_pushvalue(L, 1);
830 lua_pushinteger(L, 0);
831 lua_call(L, 2, 0);
832 }
833 #ifdef MOONBR_IO_USE_TLS
834 if (handle->tls) {
835 tls_free(handle->tls);
836 handle->tls = NULL;
837 }
838 if (handle->servertls) {
839 tls_free(handle->servertls);
840 handle->servertls = NULL;
841 }
842 #endif
843 return 0;
844 }
846 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
847 moonbr_io_handle_t *handle;
848 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
849 if (!handle->closed) {
850 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
851 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
852 lua_call(L, 1, 0);
853 }
854 }
856 static int moonbr_io_pushhandle_impl(lua_State *L) {
857 int *fd;
858 moonbr_io_handle_t *handle;
859 struct sockaddr addr;
860 socklen_t addrlen;
861 fd = lua_touserdata(L, 1);
862 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
863 handle->fd = -1; /* avoid closing incomplete handle */
864 addrlen = sizeof(addr);
865 if (getsockname(*fd, &addr, &addrlen)) {
866 if (errno != ENOTSOCK) {
867 moonbr_io_prepare_errmsg();
868 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
869 }
870 handle->issock = 0;
871 } else {
872 handle->issock = 1;
873 handle->addrfam = addr.sa_family;
874 }
875 handle->finished = 0;
876 handle->closed = 0;
877 handle->nonblocking = -1;
878 handle->nopush = -1;
879 handle->readerr = 0;
880 handle->readbufin = 0;
881 handle->readbufout = 0;
882 handle->writeerr = 0;
883 handle->writeleft = 0;
884 handle->flushedleft = 0;
885 handle->writeqin = 0;
886 handle->writeqout = 0;
887 handle->writeqoff = 0;
888 handle->writebufin = 0;
889 handle->writebufout = 0;
890 #ifdef MOONBR_IO_USE_TLS
891 handle->tls = NULL;
892 handle->servertls = NULL;
893 handle->tlshandshake = 0;
894 #endif
895 handle->fd = *fd; /* required for set_linger call */
896 if (moonbr_io_handle_set_linger(L, handle, 0)) {
897 moonbr_io_prepare_errmsg();
898 handle->fd = -1;
899 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
900 }
901 handle->fd = -1; /* avoid closing incomplete handle */
902 luaL_setmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
903 lua_newtable(L); // uservalue
904 lua_newtable(L);
905 lua_setfield(L, -2, "writequeue");
906 lua_newtable(L); // public
907 if (handle->addrfam == AF_INET6) {
908 struct sockaddr_in6 addr_in6;
909 char addrstrbuf[INET6_ADDRSTRLEN];
910 const char *addrstr;
911 addrlen = sizeof(addr_in6);
912 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
913 moonbr_io_prepare_errmsg();
914 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
915 }
916 if (addrlen > sizeof(addr_in6)) {
917 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
918 }
919 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
920 if (!addrstr) {
921 moonbr_io_prepare_errmsg();
922 luaL_error(L, "Could not format local IP address: %s", errmsg);
923 } else {
924 lua_pushstring(L, addrstr);
925 lua_setfield(L, -2, "local_ip6");
926 }
927 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
928 lua_setfield(L, -2, "local_tcpport");
929 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
930 moonbr_io_prepare_errmsg();
931 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
932 }
933 if (addrlen > sizeof(addr_in6)) {
934 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
935 }
936 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
937 if (!addrstr) {
938 moonbr_io_prepare_errmsg();
939 luaL_error(L, "Could not format remote IP address: %s", errmsg);
940 } else {
941 lua_pushstring(L, addrstr);
942 lua_setfield(L, -2, "remote_ip6");
943 }
944 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
945 lua_setfield(L, -2, "remote_tcpport");
946 } else if (handle->addrfam == AF_INET) {
947 struct sockaddr_in addr_in;
948 char addrstrbuf[INET_ADDRSTRLEN];
949 const char *addrstr;
950 addrlen = sizeof(addr_in);
951 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
952 moonbr_io_prepare_errmsg();
953 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
954 }
955 if (addrlen > sizeof(addr_in)) {
956 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
957 }
958 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
959 if (!addrstr) {
960 moonbr_io_prepare_errmsg();
961 luaL_error(L, "Could not format local IP address: %s", errmsg);
962 } else {
963 lua_pushstring(L, addrstr);
964 lua_setfield(L, -2, "local_ip4");
965 }
966 lua_pushinteger(L, ntohs(addr_in.sin_port));
967 lua_setfield(L, -2, "local_tcpport");
968 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
969 moonbr_io_prepare_errmsg();
970 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
971 }
972 if (addrlen > sizeof(addr_in)) {
973 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
974 }
975 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
976 if (!addrstr) {
977 moonbr_io_prepare_errmsg();
978 luaL_error(L, "Could not format remote IP address: %s", errmsg);
979 } else {
980 lua_pushstring(L, addrstr);
981 lua_setfield(L, -2, "remote_ip4");
982 }
983 lua_pushinteger(L, ntohs(addr_in.sin_port));
984 lua_setfield(L, -2, "remote_tcpport");
985 }
986 luaL_setmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
987 lua_setfield(L, -2, "public");
988 lua_setuservalue(L, -2);
989 handle->fd = *fd;
990 *fd = -1; /* closing is now handled by garbage collection */
991 return 1;
992 }
994 void moonbr_io_pushhandle(lua_State *L, int fd) {
995 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
996 lua_pushlightuserdata(L, &fd);
997 if (lua_pcall(L, 1, 1, 0)) {
998 if (fd != -1) close(fd); // TODO: correct to close file descriptor here?
999 lua_error(L);
1003 static int moonbr_io_handleindex(lua_State *L) {
1004 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1005 luaL_checkany(L, 2);
1006 lua_getuservalue(L, 1);
1007 lua_getfield(L, -1, "public");
1008 lua_pushvalue(L, 2);
1009 lua_gettable(L, -2);
1010 return 1;
1013 static int moonbr_io_handlenewindex(lua_State *L) {
1014 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1015 luaL_checkany(L, 2);
1016 luaL_checkany(L, 3);
1017 lua_getuservalue(L, 1);
1018 lua_getfield(L, -1, "public");
1019 lua_pushvalue(L, 2);
1020 lua_pushvalue(L, 3);
1021 lua_settable(L, -3);
1022 return 0;
1025 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
1026 const char *path;
1027 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1028 const int path_maxlen = sizeof(struct sockaddr_un) - (
1029 (void *)sockaddr.sun_path - (void *)&sockaddr
1030 ) - 1; /* one byte for termination */
1031 int sock;
1032 path = luaL_checkstring(L, 1);
1033 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1034 strcpy(sockaddr.sun_path, path);
1035 sock = socket(
1036 PF_LOCAL,
1037 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1039 );
1040 if (sock < 0) moonbr_io_return_errmsg();
1041 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1042 if (!nonblocking && errno == EINTR) {
1043 moonbr_io_prepare_errmsg();
1044 close(sock);
1045 moonbr_io_return_prepared_errmsg();
1046 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1048 moonbr_io_pushhandle(L, sock);
1049 return 1;
1052 static int moonbr_io_localconnect(lua_State *L) {
1053 return moonbr_io_localconnect_impl(L, 0);
1056 static int moonbr_io_localconnect_nb(lua_State *L) {
1057 return moonbr_io_localconnect_impl(L, 1);
1060 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
1061 const char *host, *port;
1062 struct addrinfo hints = { 0, };
1063 struct addrinfo *res, *addrinfo;
1064 int errcode;
1065 int sock;
1066 host = luaL_checkstring(L, 1);
1067 port = luaL_checkstring(L, 2);
1068 hints.ai_family = AF_UNSPEC;
1069 hints.ai_socktype = SOCK_STREAM;
1070 hints.ai_protocol = IPPROTO_TCP;
1071 hints.ai_flags = AI_ADDRCONFIG;
1072 errcode = getaddrinfo(host, port, &hints, &res);
1073 if (errcode) {
1074 freeaddrinfo(res);
1075 if (errcode == EAI_SYSTEM) {
1076 moonbr_io_prepare_errmsg();
1077 lua_pushnil(L);
1078 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1079 } else {
1080 lua_pushnil(L);
1081 lua_pushstring(L, gai_strerror(errcode));
1083 return 2;
1085 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1086 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1088 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1089 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1091 addrinfo = res;
1092 moonbr_io_tcpconnect_found:
1093 sock = socket(
1094 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1095 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1096 addrinfo->ai_protocol
1097 );
1098 if (sock < 0) {
1099 moonbr_io_prepare_errmsg();
1100 freeaddrinfo(res);
1101 moonbr_io_return_prepared_errmsg();
1103 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1104 freeaddrinfo(res);
1105 if (!nonblocking && errno == EINTR) {
1106 moonbr_io_prepare_errmsg();
1107 close(sock);
1108 moonbr_io_return_prepared_errmsg();
1109 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
1110 } else {
1111 freeaddrinfo(res);
1113 moonbr_io_pushhandle(L, sock);
1114 return 1;
1117 static int moonbr_io_tcpconnect(lua_State *L) {
1118 return moonbr_io_tcpconnect_impl(L, 0);
1121 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1122 return moonbr_io_tcpconnect_impl(L, 1);
1125 static int moonbr_io_locallisten(lua_State *L) {
1126 moonbr_io_listener_t *listener;
1127 const char *path;
1128 struct stat sb;
1129 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1130 const int path_maxlen = sizeof(struct sockaddr_un) - (
1131 (void *)sockaddr.sun_path - (void *)&sockaddr
1132 ) - 1; /* one byte for termination */
1133 int sock;
1134 path = luaL_checkstring(L, 1);
1135 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1136 strcpy(sockaddr.sun_path, path);
1137 if (stat(path, &sb) == 0) {
1138 if (S_ISSOCK(sb.st_mode)) unlink(path);
1140 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1141 listener->fd = -1;
1142 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1143 sock = socket(
1144 PF_LOCAL,
1145 SOCK_STREAM | SOCK_CLOEXEC,
1147 );
1148 if (sock < 0) moonbr_io_return_errmsg();
1149 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1150 moonbr_io_prepare_errmsg();
1151 close(sock);
1152 moonbr_io_return_prepared_errmsg();
1154 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1155 moonbr_io_prepare_errmsg();
1156 close(sock);
1157 moonbr_io_return_prepared_errmsg();
1159 listener->fd = sock;
1160 listener->addrfam = AF_LOCAL;
1161 listener->nonblocking = -1;
1162 return 1;
1165 static int moonbr_io_tcplisten(lua_State *L) {
1166 moonbr_io_listener_t *listener;
1167 const char *host, *port;
1168 struct addrinfo hints = { 0, };
1169 struct addrinfo *res, *addrinfo;
1170 int errcode;
1171 int sock;
1172 host = luaL_optstring(L, 1, NULL);
1173 port = luaL_checkstring(L, 2);
1174 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1175 listener->fd = -1;
1176 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1177 hints.ai_family = AF_UNSPEC;
1178 hints.ai_socktype = SOCK_STREAM;
1179 hints.ai_protocol = IPPROTO_TCP;
1180 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1181 errcode = getaddrinfo(host, port, &hints, &res);
1182 if (errcode) {
1183 freeaddrinfo(res);
1184 if (errcode == EAI_SYSTEM) {
1185 moonbr_io_prepare_errmsg();
1186 lua_pushnil(L);
1187 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1188 } else {
1189 lua_pushnil(L);
1190 lua_pushstring(L, gai_strerror(errcode));
1192 return 2;
1194 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1195 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1197 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1198 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1200 addrinfo = res;
1201 moonbr_io_tcpconnect_found:
1202 listener->addrfam = addrinfo->ai_family;
1203 sock = socket(
1204 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1205 addrinfo->ai_socktype | SOCK_CLOEXEC,
1206 addrinfo->ai_protocol
1207 );
1208 if (sock < 0) {
1209 moonbr_io_prepare_errmsg();
1210 freeaddrinfo(res);
1211 moonbr_io_return_prepared_errmsg();
1214 static const int reuseval = 1;
1215 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1216 moonbr_io_prepare_errmsg();
1217 freeaddrinfo(res);
1218 close(sock);
1219 lua_pushnil(L);
1220 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1221 return 2;
1224 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1225 moonbr_io_prepare_errmsg();
1226 freeaddrinfo(res);
1227 close(sock);
1228 moonbr_io_return_prepared_errmsg();
1230 freeaddrinfo(res);
1231 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1232 moonbr_io_prepare_errmsg();
1233 close(sock);
1234 moonbr_io_return_prepared_errmsg();
1236 listener->fd = sock;
1237 listener->nonblocking = -1;
1238 return 1;
1241 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1242 moonbr_io_listener_t *listener;
1243 int fd;
1244 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1245 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1246 if (listener->nonblocking != nonblocking) {
1247 int flags;
1248 flags = fcntl(listener->fd, F_GETFL, 0);
1249 if (flags == -1) {
1250 moonbr_io_prepare_errmsg();
1251 close(listener->fd);
1252 listener->fd = -1;
1253 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1255 if (nonblocking) flags |= O_NONBLOCK;
1256 else flags &= ~O_NONBLOCK;
1257 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1258 moonbr_io_prepare_errmsg();
1259 close(listener->fd);
1260 listener->fd = -1;
1261 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1263 listener->nonblocking = nonblocking;
1265 while (1) {
1266 #if defined(__linux__) && !defined(_GNU_SOURCE)
1267 fd = accept(listener->fd, NULL, NULL);
1268 if (fd != -1) {
1269 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1270 moonbr_io_prepare_errmsg();
1271 close(listener->fd);
1272 listener->fd = -1;
1273 close(fd);
1274 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1277 #else
1278 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1279 #endif
1280 if (fd < 0) {
1281 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1282 lua_pushboolean(L, 0);
1283 lua_pushliteral(L, "No incoming connection pending");
1284 return 2;
1285 } else if (errno != EINTR) moonbr_io_return_errmsg();
1286 } else {
1287 moonbr_io_pushhandle(L, fd);
1288 return 1;
1293 static int moonbr_io_accept(lua_State *L) {
1294 return moonbr_io_accept_impl(L, 0);
1297 static int moonbr_io_accept_nb(lua_State *L) {
1298 return moonbr_io_accept_impl(L, 1);
1301 static int moonbr_io_unlisten(lua_State *L) {
1302 moonbr_io_listener_t *listener;
1303 struct sockaddr_un addr;
1304 socklen_t addrlen;
1305 struct stat sb;
1306 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1307 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1308 addrlen = sizeof(addr);
1309 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1310 if (close(listener->fd)) {
1311 moonbr_io_prepare_errmsg();
1312 listener->fd = -1;
1313 if (addrlen && addrlen <= sizeof(addr)) {
1314 if (stat(addr.sun_path, &sb) == 0) {
1315 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1318 moonbr_io_return_prepared_errmsg();
1320 listener->fd = -1;
1321 if (addrlen && addrlen <= sizeof(addr)) {
1322 if (stat(addr.sun_path, &sb) == 0) {
1323 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1326 lua_pushboolean(L, 1);
1327 return 1;
1330 static int moonbr_io_listenergc(lua_State *L) {
1331 moonbr_io_listener_t *listener;
1332 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1333 if (listener->fd >= 0) close(listener->fd);
1334 listener->fd = -1;
1335 return 0;
1338 static int moonbr_io_exec(lua_State *L) {
1339 char **argv;
1340 int i, argc;
1341 int sockin[2], sockout[2], sockerr[2];
1342 volatile int errorcond = 0;
1343 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
1344 moonbr_io_child_t *child;
1345 argc = lua_gettop(L);
1346 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1347 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1348 argv[argc] = NULL;
1349 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1350 child->pid = 0;
1351 lua_newtable(L);
1352 lua_setuservalue(L, -2);
1353 luaL_setmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1354 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
1355 moonbr_io_prepare_errmsg();
1356 lua_pushnil(L);
1357 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1358 return 2;
1360 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
1361 moonbr_io_prepare_errmsg();
1362 close(sockin[0]);
1363 close(sockin[1]);
1364 lua_pushnil(L);
1365 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1366 return 2;
1368 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
1369 moonbr_io_prepare_errmsg();
1370 close(sockin[0]);
1371 close(sockin[1]);
1372 close(sockout[0]);
1373 close(sockout[1]);
1374 lua_pushnil(L);
1375 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1376 return 2;
1378 child->pid = vfork();
1379 if (child->pid == -1) {
1380 moonbr_io_prepare_errmsg();
1381 close(sockin[0]);
1382 close(sockin[1]);
1383 close(sockout[0]);
1384 close(sockout[1]);
1385 close(sockerr[0]);
1386 close(sockerr[1]);
1387 lua_pushnil(L);
1388 lua_pushfstring(L, "Could not fork: %s", errmsg);
1389 return 2;
1391 if (!child->pid) {
1392 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
1393 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
1394 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
1395 closefrom(3);
1396 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1397 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1398 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1399 if (execvp(argv[0], argv)) {
1400 errorcond = 2;
1401 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1402 _exit(0);
1404 moonbr_io_exec_error1:
1405 errorcond = 1;
1406 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1407 _exit(0);
1409 close(sockin[1]);
1410 close(sockout[1]);
1411 close(sockerr[1]);
1412 if (errorcond) {
1413 int status;
1414 close(sockin[0]);
1415 close(sockout[0]);
1416 close(sockerr[0]);
1417 while (waitpid(child->pid, &status, 0) == -1) {
1418 if (errno != EINTR) {
1419 moonbr_io_prepare_errmsg();
1420 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1423 child->pid = 0;
1424 lua_pushnil(L);
1425 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1426 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1427 return 2;
1429 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1430 lua_pushlightuserdata(L, &sockin[0]);
1431 if (lua_pcall(L, 1, 1, 0)) {
1432 if (sockin[0] != -1) close(sockin[0]);
1433 close(sockout[0]);
1434 close(sockerr[0]);
1435 goto moonbr_io_exec_error2;
1437 lua_setfield(L, -2, "stdin");
1438 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1439 lua_pushlightuserdata(L, &sockout[0]);
1440 if (lua_pcall(L, 1, 1, 0)) {
1441 if (sockout[0] != -1) close(sockout[0]);
1442 close(sockerr[0]);
1443 goto moonbr_io_exec_error2;
1445 lua_setfield(L, -2, "stdout");
1446 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1447 lua_pushlightuserdata(L, &sockerr[0]);
1448 if (lua_pcall(L, 1, 1, 0)) {
1449 if (sockerr[0] != -1) close(sockerr[0]);
1450 goto moonbr_io_exec_error2;
1452 lua_setfield(L, -2, "stderr");
1453 return 1;
1454 moonbr_io_exec_error2:
1456 int status;
1457 while (waitpid(child->pid, &status, 0) == -1) {
1458 if (errno != EINTR) {
1459 moonbr_io_prepare_errmsg();
1460 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
1464 child->pid = 0;
1465 return lua_error(L);
1468 static int moonbr_io_childindex(lua_State *L) {
1469 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1470 luaL_checkany(L, 2);
1471 lua_getuservalue(L, 1);
1472 lua_pushvalue(L, 2);
1473 lua_gettable(L, -2);
1474 if (lua_isnil(L, -1)) {
1475 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1476 lua_pushvalue(L, 2);
1477 lua_gettable(L, -2);
1479 return 1;
1482 static int moonbr_io_childnewindex(lua_State *L) {
1483 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1484 luaL_checkany(L, 2);
1485 luaL_checkany(L, 3);
1486 lua_getuservalue(L, 1);
1487 lua_pushvalue(L, 2);
1488 lua_pushvalue(L, 3);
1489 lua_settable(L, -3);
1490 return 0;
1493 static int moonbr_io_childgc(lua_State *L) {
1494 moonbr_io_child_t *child;
1495 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1496 if (child->pid) {
1497 int status;
1498 if (kill(child->pid, SIGKILL)) {
1499 moonbr_io_prepare_errmsg();
1500 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1502 while (waitpid(child->pid, &status, 0) == -1) {
1503 if (errno != EINTR) {
1504 moonbr_io_prepare_errmsg();
1505 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1509 return 0;
1512 static int moonbr_io_kill(lua_State *L) {
1513 moonbr_io_child_t *child;
1514 int sig;
1515 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1516 sig = luaL_optinteger(L, 2, SIGTERM);
1517 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
1518 if (kill(child->pid, sig)) {
1519 moonbr_io_prepare_errmsg();
1520 luaL_error(L, "Error in kill call: %s", errmsg);
1522 lua_settop(L, 1);
1523 return 1;
1526 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1527 moonbr_io_child_t *child;
1528 pid_t waitedpid;
1529 int status;
1530 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1531 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
1532 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1533 if (errno != EINTR) {
1534 moonbr_io_prepare_errmsg();
1535 luaL_error(L, "Error in waitpid call: %s", errmsg);
1538 if (!waitedpid) {
1539 lua_pushboolean(L, 0);
1540 lua_pushliteral(L, "Process is still running");
1541 return 2;
1542 } else {
1543 child->pid = 0;
1544 if (WIFEXITED(status)) {
1545 lua_pushinteger(L, WEXITSTATUS(status));
1546 } else if (WIFSIGNALED(status)) {
1547 lua_pushinteger(L, -WTERMSIG(status));
1548 } else {
1549 luaL_error(L, "Unexpected status value returned by waitpid call");
1551 return 1;
1555 static int moonbr_io_wait(lua_State *L) {
1556 return moonbr_io_wait_impl(L, 0);
1559 static int moonbr_io_wait_nb(lua_State *L) {
1560 return moonbr_io_wait_impl(L, 1);
1563 #if LUA_VERSION_NUM >= 503
1564 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1565 #else
1566 static int moonbr_io_wait_cont(lua_State *L) {
1567 #endif
1568 #if !(LUA_VERSION_NUM >= 503)
1569 int ctx = 0;
1570 lua_getctx(L, &ctx);
1571 #endif
1572 while (1) {
1573 lua_pushcfunction(L, moonbr_io_wait_nb);
1574 lua_pushvalue(L, 1);
1575 lua_call(L, 1, 1);
1576 if (!lua_isnil(L, -1)) break;
1577 lua_pushvalue(L, 2);
1578 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1580 return 1;
1583 static int moonbr_io_wait_call(lua_State *L) {
1584 lua_settop(L, 2);
1585 #if LUA_VERSION_NUM >= 503
1586 return moonbr_io_wait_cont(L, 0, 0);
1587 #else
1588 return moonbr_io_wait_cont(L);
1589 #endif
1592 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1594 #ifdef MOONBR_IO_USE_TLS
1596 #define moonbr_io_poll_tls() \
1597 if (!handle->tlshandshake) { \
1598 lua_pushboolean(L, 1); \
1599 return 1; \
1600 } \
1601 if (handle->tlshandshake == TLS_WANT_POLLIN) { \
1602 if (fd < 0) { \
1603 lua_pushboolean(L, 1); \
1604 return 1; \
1605 } \
1606 FD_SET(fd, &readfds); \
1607 if (fd+1 > nfds) nfds = fd+1; \
1608 continue; \
1609 } \
1610 if (handle->tlshandshake == TLS_WANT_POLLOUT) { \
1611 if (fd < 0) { \
1612 lua_pushboolean(L, 1); \
1613 return 1; \
1614 } \
1615 FD_SET(fd, &writefds); \
1616 if (fd+1 > nfds) nfds = fd+1; \
1617 continue; \
1618 } \
1619 while (0)
1621 #endif /* MOONBR_IO_USE_TLS */
1623 static int moonbr_io_poll(lua_State *L) {
1624 moonbr_io_handle_t *handle;
1625 moonbr_io_listener_t *listener;
1626 int fd, isnum;
1627 int nfds = 0;
1628 fd_set readfds, writefds, exceptfds;
1629 struct timeval timeout = {0, };
1630 int status;
1631 FD_ZERO(&readfds);
1632 FD_ZERO(&writefds);
1633 FD_ZERO(&exceptfds);
1634 if (!lua_isnoneornil(L, 1)) {
1635 luaL_checktype(L, 1, LUA_TTABLE);
1636 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1637 if (lua_toboolean(L, -1)) {
1638 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1639 if (handle) {
1640 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1641 fd = handle->fd;
1642 #if MOONBR_IO_USE_TLS
1643 moonbr_io_poll_tls();
1644 #endif
1645 if (
1646 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1647 handle->readbufin != handle->readbufout /* data pending in buffer */
1648 ) {
1649 lua_pushboolean(L, 1);
1650 return 1;
1652 } else {
1653 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1654 if (listener) {
1655 fd = listener->fd;
1656 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1657 } else {
1658 fd = lua_tointegerx(L, -2, &isnum);
1659 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1662 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1663 FD_SET(fd, &readfds);
1664 if (fd+1 > nfds) nfds = fd+1;
1668 if (!lua_isnoneornil(L, 2)) {
1669 luaL_checktype(L, 2, LUA_TTABLE);
1670 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1671 if (lua_toboolean(L, -1)) {
1672 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1673 if (handle) {
1674 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1675 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1676 fd = handle->fd;
1677 #if MOONBR_IO_USE_TLS
1678 moonbr_io_poll_tls();
1679 #endif
1680 } else {
1681 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1682 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1683 fd = lua_tointegerx(L, -2, &isnum);
1684 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1686 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1687 FD_SET(fd, &writefds);
1688 if (fd+1 > nfds) nfds = fd+1;
1692 if (!lua_isnoneornil(L, 3)) {
1693 lua_Number n;
1694 n = lua_tonumberx(L, 3, &isnum);
1695 if (isnum && n<0) {
1696 lua_pushboolean(L, 0);
1697 lua_pushliteral(L, "Negative timeout");
1698 return 2;
1699 } else if (isnum && n>=0 && n<100000000) {
1700 timeout.tv_sec = n;
1701 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1702 } else {
1703 luaL_argcheck(L, 0, 3, "not a valid timeout");
1705 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1706 } else {
1707 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1709 if (status == -1) {
1710 if (errno == EINTR) {
1711 lua_pushnil(L);
1712 lua_pushliteral(L, "Signal received while polling file descriptors");
1713 return 2;
1714 } else {
1715 moonbr_io_prepare_errmsg();
1716 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1718 } else if (status == 0) {
1719 lua_pushboolean(L, 0);
1720 lua_pushliteral(L, "Timeout while polling file descriptors");
1721 return 2;
1722 } else {
1723 lua_pushboolean(L, 1);
1724 return 1;
1728 static int moonbr_io_timeref(lua_State *L) {
1729 lua_Number sub;
1730 struct timespec tp;
1731 sub = luaL_optnumber(L, 1, 0);
1732 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1733 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1735 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1736 return 1;
1739 #ifdef MOONBR_IO_USE_TLS
1741 #define moonbr_io_tlsconf_string(name, field, func) \
1742 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1743 lua_getfield(L, 1, (field)); \
1744 valuetype = lua_type(L, -1); \
1745 if (valuetype != LUA_TNIL) { \
1746 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1747 value = lua_tostring(L, -1); \
1748 if (func(tlsconf->config, value)) { \
1749 lua_pushnil(L); \
1750 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
1751 return 2; \
1752 } \
1753 } \
1754 lua_pop(L, 1);
1756 #define moonbr_io_tlsconf_binary(name, field, func) \
1757 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
1758 lua_getfield(L, 1, (field)); \
1759 valuetype = lua_type(L, -1); \
1760 if (valuetype != LUA_TNIL) { \
1761 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
1762 value = lua_tolstring(L, -1, &valuelen); \
1763 if (func(tlsconf->config, (void *)value, valuelen)) { \
1764 lua_pushnil(L); \
1765 lua_pushliteral(L, "Could not set " name); \
1766 return 2; \
1767 } \
1768 } \
1769 lua_pop(L, 1);
1771 static int moonbr_io_tlsconf(lua_State *L) {
1772 moonbr_io_tlsconf_t *tlsconf;
1773 int valuetype;
1774 const char *value;
1775 size_t valuelen;
1776 luaL_checktype(L, 1, LUA_TTABLE);
1777 tlsconf = lua_newuserdata(L, sizeof(moonbr_io_tlsconf_t));
1778 tlsconf->config = tls_config_new();
1779 if (!tlsconf->config) {
1780 return luaL_error(L, "Could not allocate memory for TLS configuration");
1782 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
1783 lua_getfield(L, 1, "mode");
1784 value = lua_tostring(L, -1);
1785 if (value && !strcmp(value, "server")) tlsconf->server = 1;
1786 else if (value && !strcmp(value, "client")) tlsconf->server = 0;
1787 else luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
1788 lua_pop(L, 1);
1789 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
1790 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
1791 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
1792 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
1793 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
1794 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
1795 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
1796 #if LUA_VERSION_NUM >= 503
1797 valuetype = lua_getfield(L, 1, "verify_client");
1798 #else
1799 lua_getfield(L, 1, "verify_client");
1800 #endif
1801 if (lua_toboolean(L, -1)) {
1802 value = lua_tostring(L, -1);
1803 if (value && !strcmp(value, "required")) {
1804 tls_config_verify_client(tlsconf->config);
1805 } else if (value && !strcmp(value, "optional")) {
1806 tls_config_verify_client_optional(tlsconf->config);
1807 } else {
1808 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
1811 lua_pop(L, 1);
1812 // TODO: configurable legacy support
1813 // tls_config_set_protocols(tlsconf->config, TLS_PROTOCOLS_ALL);
1814 // tls_config_set_ciphers(tlsconf->config, "legacy");
1815 return 1;
1818 static int moonbr_io_tlsconfgc(lua_State *L) {
1819 moonbr_io_tlsconf_t *tlsconf;
1820 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1821 if (tlsconf->config) tls_config_free(tlsconf->config);
1822 tlsconf->config = NULL;
1823 return 0;
1826 static int moonbr_io_starttls(lua_State *L) {
1827 moonbr_io_handle_t *handle;
1828 moonbr_io_tlsconf_t *tlsconf;
1829 const char *servername;
1830 struct tls *tls, *tls2;
1831 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
1832 if (lua_type(L, 2) == LUA_TTABLE) {
1833 lua_pushcfunction(L, moonbr_io_tlsconf);
1834 lua_pushvalue(L, 2);
1835 lua_call(L, 1, 2);
1836 if (lua_isnil(L, -2)) return 2;
1837 lua_pop(L, 1);
1838 lua_replace(L, 2);
1840 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
1841 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
1842 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
1843 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
1844 if (handle->readbufin || handle->writebufin) {
1845 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
1847 if (tlsconf->server) tls = tls_server();
1848 else {
1849 servername = luaL_checkstring(L, 3);
1850 tls = tls_client();
1852 if (!tls) {
1853 return luaL_error(L, "Could not allocate memory for TLS context");
1855 if (tls_configure(tls, tlsconf->config)) goto moonbr_io_starttls_error;
1856 if (tlsconf->server) {
1857 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
1858 handle->servertls = tls;
1859 handle->tls = tls2;
1860 } else {
1861 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
1862 handle->tls = tls;
1864 lua_settop(L, 1);
1865 return 1;
1866 moonbr_io_starttls_error:
1867 lua_pushnil(L);
1868 lua_pushstring(L, tls_error(tls));
1869 tls_free(tls);
1870 return 2;
1873 #endif /* MOONBR_IO_USE_TLS */
1875 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1876 {"read", moonbr_io_read},
1877 {"read_nb", moonbr_io_read_nb},
1878 {"read_call", moonbr_io_read_call},
1879 {"read_yield", moonbr_io_read_yield},
1880 {"drain", moonbr_io_drain},
1881 {"drain_nb", moonbr_io_drain_nb},
1882 {"drain_call", moonbr_io_drain_call},
1883 {"drain_yield", moonbr_io_drain_yield},
1884 {"write", moonbr_io_write},
1885 {"write_nb", moonbr_io_write_nb},
1886 {"write_call", moonbr_io_write_call},
1887 {"write_yield", moonbr_io_write_yield},
1888 {"flush", moonbr_io_flush},
1889 {"flush_nb", moonbr_io_flush_nb},
1890 {"flush_call", moonbr_io_flush_call},
1891 {"flush_yield", moonbr_io_flush_yield},
1892 {"finish", moonbr_io_finish},
1893 {"close", moonbr_io_close},
1894 {"reset", moonbr_io_reset},
1895 #ifdef MOONBR_IO_USE_TLS
1896 {"starttls", moonbr_io_starttls},
1897 #endif
1898 {NULL, NULL}
1899 };
1901 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1902 {"__index", moonbr_io_handleindex},
1903 {"__newindex", moonbr_io_handlenewindex},
1904 {"__gc", moonbr_io_handlegc},
1905 {NULL, NULL}
1906 };
1908 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1909 {"accept", moonbr_io_accept},
1910 {"accept_nb", moonbr_io_accept_nb},
1911 {"close", moonbr_io_unlisten},
1912 {NULL, NULL}
1913 };
1915 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1916 {"__gc", moonbr_io_listenergc},
1917 {NULL, NULL}
1918 };
1920 static const struct luaL_Reg moonbr_io_child_methods[] = {
1921 {"kill", moonbr_io_kill},
1922 {"wait", moonbr_io_wait},
1923 {"wait_nb", moonbr_io_wait_nb},
1924 {"wait_call", moonbr_io_wait_call},
1925 {"wait_yield", moonbr_io_wait_yield},
1926 {NULL, NULL}
1927 };
1929 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
1930 {"__index", moonbr_io_childindex},
1931 {"__newindex", moonbr_io_childnewindex},
1932 {"__gc", moonbr_io_childgc},
1933 {NULL, NULL}
1934 };
1936 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1937 {"localconnect", moonbr_io_localconnect},
1938 {"localconnect_nb", moonbr_io_localconnect_nb},
1939 {"tcpconnect", moonbr_io_tcpconnect},
1940 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1941 {"locallisten", moonbr_io_locallisten},
1942 {"tcplisten", moonbr_io_tcplisten},
1943 {"exec", moonbr_io_exec},
1944 {"poll", moonbr_io_poll},
1945 {"timeref", moonbr_io_timeref},
1946 #ifdef MOONBR_IO_USE_TLS
1947 {"tlsconf", moonbr_io_tlsconf},
1948 #endif
1949 {NULL, NULL}
1950 };
1952 #ifdef MOONBR_IO_USE_TLS
1954 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
1955 {"__gc", moonbr_io_tlsconfgc},
1956 {NULL, NULL}
1957 };
1959 #endif /* MOONBR_IO_USE_TLS */
1961 int luaopen_moonbridge_io(lua_State *L) {
1963 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1965 lua_newtable(L); // module
1967 lua_newtable(L); // public metatable
1968 lua_newtable(L); // handle methods
1969 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1970 lua_pushvalue(L, -1);
1971 lua_setfield(L, -4, "handle_pt");
1972 lua_setfield(L, -2, "__index");
1973 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1975 lua_newtable(L); // handle metatable
1976 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1977 lua_pushvalue(L, -1);
1978 lua_setfield(L, -3, "handle_mt");
1979 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1981 lua_newtable(L); // listener metatable
1982 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1983 lua_newtable(L); // listener methods
1984 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1985 lua_pushvalue(L, -1);
1986 lua_setfield(L, -4, "listener_pt");
1987 lua_setfield(L, -2, "__index");
1988 lua_pushvalue(L, -1);
1989 lua_setfield(L, -3, "listener_mt");
1990 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1992 lua_newtable(L); // child methods
1993 luaL_setfuncs(L, moonbr_io_child_methods, 0);
1994 lua_pushvalue(L, -1);
1995 lua_setfield(L, -3, "child_pt");
1996 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
1997 lua_newtable(L); // child metatable
1998 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
1999 lua_pushvalue(L, -1);
2000 lua_setfield(L, -3, "child_mt");
2001 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
2003 #ifdef MOONBR_IO_USE_TLS
2004 if(tls_init()) {
2005 return luaL_error(L, "Could not initialize TLS library");
2007 lua_newtable(L); // tlsconf metatable
2008 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
2009 lua_pushvalue(L, -1);
2010 lua_setfield(L, -3, "tlsconf_mt");
2011 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
2012 #endif
2014 moonbr_io_pushhandle(L, 0);
2015 lua_setfield(L, -2, "stdin");
2016 moonbr_io_pushhandle(L, 1);
2017 lua_setfield(L, -2, "stdout");
2018 moonbr_io_pushhandle(L, 2);
2019 lua_setfield(L, -2, "stderr");
2021 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
2022 return 1;

Impressum / About Us