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