moonbridge

view moonbridge_io.c @ 249:53962483bf1c

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

Impressum / About Us