moonbridge

view moonbridge_io.c @ 257:77a7ca00ad34

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

Impressum / About Us