moonbridge

view moonbridge_io.c @ 237:1fd00eed96ee

Work on optional libtls integration for moonbridge_io (tls_config stub)
author jbe
date Sat Aug 20 21:54:15 2016 +0200 (2016-08-20)
parents 6bab0621806a
children 90e6db450677
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 } moonbr_io_handle_t;
87 typedef struct {
88 int fd;
89 sa_family_t addrfam;
90 int nonblocking;
91 } moonbr_io_listener_t;
93 typedef struct {
94 pid_t pid;
95 } moonbr_io_child_t;
97 static int moonbr_io_yield(lua_State *L) {
98 return lua_yield(L, lua_gettop(L));
99 }
101 #if LUA_VERSION_NUM >= 503
102 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
103 #else
104 static int moonbr_io_cont_returnall(lua_State *L) {
105 #endif
106 return lua_gettop(L);
107 }
109 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
110 static int yieldfunc(lua_State *L) { \
111 int args; \
112 lua_pushcfunction(L, callfunc); \
113 lua_insert(L, 1); \
114 args = lua_gettop(L); \
115 lua_pushcfunction(L, moonbr_io_yield); \
116 lua_insert(L, 3); \
117 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
118 return lua_gettop(L); \
119 }
121 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
122 int flags;
123 if (handle->nonblocking == nonblocking) return;
124 flags = fcntl(handle->fd, F_GETFL, 0);
125 if (flags == -1) {
126 moonbr_io_errmsg();
127 close(handle->fd);
128 handle->fd = -1;
129 handle->closed = 1;
130 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
131 }
132 if (nonblocking) flags |= O_NONBLOCK;
133 else flags &= ~O_NONBLOCK;
134 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
135 moonbr_io_errmsg();
136 close(handle->fd);
137 handle->fd = -1;
138 handle->closed = 1;
139 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
140 }
141 handle->nonblocking = nonblocking;
142 }
144 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
145 struct linger lingerval = { 0, };
146 if (!handle->issock) return;
147 if (timeout >= 0) {
148 lingerval.l_onoff = 1;
149 lingerval.l_linger = timeout;
150 }
151 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
152 moonbr_io_errmsg();
153 close(handle->fd);
154 handle->fd = -1;
155 handle->closed = 1;
156 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
157 }
158 }
160 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
161 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
162 if (
163 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
164 handle->nopush == nopush
165 ) return;
166 #if defined(TCP_NOPUSH)
167 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
168 #elif defined(TCP_CORK)
169 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
170 #endif
171 moonbr_io_errmsg();
172 close(handle->fd);
173 handle->fd = -1;
174 handle->closed = 1;
175 #if defined(TCP_NOPUSH)
176 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
177 #elif defined(TCP_CORK)
178 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
179 #endif
180 }
181 handle->nopush = nopush;
182 #else
183 #warning Neither TCP_NOPUSH nor TCP_CORK is available
184 #endif
185 }
187 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
188 moonbr_io_handle_t *handle;
189 lua_Integer maxread;
190 const char *terminatorstr;
191 size_t terminatorlen;
192 char terminator = 0; /* initialize to avoid compiler warning */
193 luaL_Buffer luabuf;
194 size_t luabufcnt = 0;
195 int remaining;
196 char *terminatorpos;
197 ssize_t bytesread;
198 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
199 maxread = luaL_optinteger(L, 2, -1);
200 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
201 if (terminatorlen) {
202 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
203 terminator = terminatorstr[0];
204 }
205 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
206 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
207 if (handle->readerr) {
208 lua_pushnil(L);
209 lua_pushliteral(L, "Previous read error");
210 return 2;
211 }
212 if (handle->fd < 0) {
213 /* fake EOF to simulate shutdown */
214 if (!drain) lua_pushliteral(L, "");
215 else lua_pushinteger(L, 0);
216 lua_pushliteral(L, "eof");
217 return 2;
218 }
219 handle->readerr = 1;
220 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
221 if (!drain) luaL_buffinit(L, &luabuf);
222 while (1) {
223 remaining = -1;
224 terminatorpos = NULL;
225 if (
226 maxread >= 0 &&
227 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
228 ) {
229 remaining = (size_t)maxread - luabufcnt;
230 if (terminatorlen) {
231 terminatorpos = memchr(
232 handle->readbuf + handle->readbufout,
233 terminator,
234 remaining
235 );
236 }
237 } else if (terminatorlen) {
238 terminatorpos = memchr(
239 handle->readbuf + handle->readbufout,
240 terminator,
241 handle->readbufin - handle->readbufout
242 );
243 }
244 if (terminatorpos) remaining = 1 + (
245 terminatorpos - (handle->readbuf + handle->readbufout)
246 );
247 if (remaining >= 0) {
248 if (!drain) {
249 luaL_addlstring(
250 &luabuf,
251 handle->readbuf + handle->readbufout,
252 remaining
253 );
254 luaL_pushresult(&luabuf);
255 } else {
256 lua_pushinteger(L, luabufcnt + remaining);
257 }
258 if (terminatorpos) lua_pushliteral(L, "term");
259 else lua_pushliteral(L, "maxlen");
260 handle->readbufout += remaining;
261 if (handle->readbufout == handle->readbufin) {
262 handle->readbufin = 0;
263 handle->readbufout = 0;
264 }
265 handle->readerr = 0;
266 return 2;
267 }
268 if (!drain) luaL_addlstring(
269 &luabuf,
270 handle->readbuf + handle->readbufout,
271 handle->readbufin - handle->readbufout
272 );
273 luabufcnt += handle->readbufin - handle->readbufout;
274 handle->readbufout = 0;
275 do {
276 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
277 } while (bytesread < 0 && (errno == EINTR));
278 if (
279 bytesread == 0 || (
280 nonblocking &&
281 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
282 )
283 ) {
284 handle->readbufin = 0;
285 if (!drain) luaL_pushresult(&luabuf);
286 else lua_pushinteger(L, luabufcnt);
287 if (bytesread == 0) lua_pushliteral(L, "eof");
288 else lua_pushliteral(L, "block");
289 handle->readerr = 0;
290 return 2;
291 }
292 if (bytesread < 0) {
293 moonbr_io_errmsg();
294 lua_pushnil(L);
295 lua_pushstring(L, errmsg);
296 return 2;
297 }
298 handle->readbufin = bytesread;
299 }
300 }
302 static int moonbr_io_read(lua_State *L) {
303 return moonbr_io_read_impl(L, 0, 0);
304 }
306 static int moonbr_io_read_nb(lua_State *L) {
307 return moonbr_io_read_impl(L, 1, 0);
308 }
310 static int moonbr_io_drain(lua_State *L) {
311 return moonbr_io_read_impl(L, 0, 1);
312 }
314 static int moonbr_io_drain_nb(lua_State *L) {
315 return moonbr_io_read_impl(L, 1, 1);
316 }
318 #if LUA_VERSION_NUM >= 503
319 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
320 #else
321 static int moonbr_io_read_cont(lua_State *L) {
322 #endif
323 lua_Integer remaining;
324 size_t len;
325 #if !(LUA_VERSION_NUM >= 503)
326 int ctx = 0;
327 lua_getctx(L, &ctx);
328 #endif
329 remaining = lua_tointeger(L, 3);
330 while (1) {
331 lua_pushcfunction(L, moonbr_io_read_nb);
332 lua_pushvalue(L, 1);
333 lua_pushvalue(L, 3);
334 lua_pushvalue(L, 4);
335 lua_call(L, 3, 2);
336 if (lua_isnil(L, -2)) return 2;
337 lua_insert(L, -2);
338 len = lua_rawlen(L, -1);
339 if (ctx == 0) {
340 lua_replace(L, 5);
341 ctx = 1;
342 } else if (ctx == 1) {
343 lua_pushvalue(L, 5);
344 lua_newtable(L);
345 lua_replace(L, 5);
346 lua_rawseti(L, 5, 2);
347 lua_rawseti(L, 5, 1);
348 ctx = 2;
349 } else {
350 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
351 }
352 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
353 lua_pop(L, 1);
354 if (remaining >= 0 && len) {
355 remaining -= len;
356 lua_pushinteger(L, remaining);
357 lua_replace(L, 3);
358 }
359 lua_pushvalue(L, 2);
360 lua_callk(L, 0, 0, ctx, moonbr_io_read_cont);
361 }
362 if (ctx == 1) {
363 lua_pushvalue(L, 5);
364 } else {
365 luaL_Buffer buf;
366 lua_Integer i, chunkcount;
367 chunkcount = lua_rawlen(L, 5);
368 luaL_buffinit(L, &buf);
369 for (i=1; i<=chunkcount && i>0; i++) {
370 lua_rawgeti(L, 5, i);
371 luaL_addvalue(&buf);
372 }
373 luaL_pushresult(&buf);
374 }
375 lua_pushvalue(L, -2);
376 return 2;
377 }
379 static int moonbr_io_read_call(lua_State *L) {
380 lua_settop(L, 4);
381 lua_pushnil(L);
382 #if LUA_VERSION_NUM >= 503
383 return moonbr_io_read_cont(L, 0, 0);
384 #else
385 return moonbr_io_read_cont(L);
386 #endif
387 }
389 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
391 #if LUA_VERSION_NUM >= 503
392 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
393 #else
394 static int moonbr_io_drain_cont(lua_State *L) {
395 #endif
396 lua_Integer remaining, len;
397 size_t totallen = 0;
398 #if !(LUA_VERSION_NUM >= 503)
399 int ctx = 0;
400 lua_getctx(L, &ctx);
401 #endif
402 remaining = lua_tointeger(L, 3);
403 while (1) {
404 lua_pushcfunction(L, moonbr_io_drain_nb);
405 lua_pushvalue(L, 1);
406 lua_pushvalue(L, 3);
407 lua_pushvalue(L, 4);
408 lua_call(L, 3, 2);
409 if (lua_isnil(L, -2)) return 2;
410 lua_insert(L, -2);
411 len = lua_tointeger(L, -1);
412 lua_pop(L, 1);
413 totallen += len;
414 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
415 lua_pop(L, 1);
416 if (remaining >= 0 && len) {
417 remaining -= len;
418 lua_pushinteger(L, remaining);
419 lua_replace(L, 3);
420 }
421 lua_pushvalue(L, 2);
422 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
423 }
424 lua_pushinteger(L, totallen);
425 lua_pushvalue(L, -2);
426 return 2;
427 }
429 static int moonbr_io_drain_call(lua_State *L) {
430 #if LUA_VERSION_NUM >= 503
431 return moonbr_io_drain_cont(L, 0, 0);
432 #else
433 return moonbr_io_drain_cont(L);
434 #endif
435 }
437 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
439 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
440 moonbr_io_handle_t *handle;
441 int i, top;
442 const char *str;
443 size_t strlen;
444 ssize_t written;
445 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
446 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
447 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
448 if (handle->writeerr) {
449 lua_pushnil(L);
450 lua_pushliteral(L, "Previous write error");
451 return 2;
452 }
453 handle->writeerr = 1;
454 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
455 top = lua_gettop(L);
456 lua_getuservalue(L, 1);
457 lua_getfield(L, -1, "writequeue");
458 for (i=2; i<=top; i++) {
459 luaL_checklstring(L, i, &strlen);
460 lua_pushvalue(L, i);
461 lua_rawseti(L, -2, handle->writeqin++);
462 handle->writeleft += strlen;
463 }
464 if (flush) handle->flushedleft = handle->writeleft;
465 while (handle->writeqout != handle->writeqin) {
466 lua_rawgeti(L, -1, handle->writeqout);
467 str = lua_tolstring(L, -1, &strlen);
468 while (handle->writeqoff < strlen) {
469 if (
470 strlen - handle->writeqoff <
471 MOONBR_IO_WRITEBUFLEN - handle->writebufin
472 ) {
473 memcpy(
474 handle->writebuf + handle->writebufin,
475 str + handle->writeqoff,
476 strlen - handle->writeqoff
477 );
478 handle->writebufin += strlen - handle->writeqoff;
479 break;
480 } else {
481 memcpy(
482 handle->writebuf + handle->writebufin,
483 str + handle->writeqoff,
484 MOONBR_IO_WRITEBUFLEN - handle->writebufin
485 );
486 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
487 handle->writebufin = MOONBR_IO_WRITEBUFLEN;
488 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
489 moonbr_io_handle_set_nopush(L, handle, 1);
490 written = write(
491 handle->fd,
492 handle->writebuf + handle->writebufout,
493 MOONBR_IO_WRITEBUFLEN - handle->writebufout
494 );
495 if (written < 0) {
496 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
497 goto moonbr_io_write_impl_block;
498 } else if (errno != EINTR) {
499 moonbr_io_errmsg();
500 lua_pushnil(L);
501 lua_pushstring(L, errmsg);
502 return 2;
503 }
504 } else {
505 handle->writebufout += written;
506 handle->writeleft -= written;
507 if (handle->flushedleft) {
508 if (written >= handle->flushedleft) {
509 handle->flushedleft = 0;
510 moonbr_io_handle_set_nopush(L, handle, 0);
511 } else {
512 handle->flushedleft -= written;
513 }
514 }
515 }
516 }
517 handle->writebufin = 0;
518 handle->writebufout = 0;
519 }
520 }
521 handle->writeqoff = 0;
522 lua_pop(L, 1);
523 lua_pushnil(L);
524 lua_rawseti(L, -2, handle->writeqout++);
525 }
526 while (handle->flushedleft) {
527 moonbr_io_handle_set_nopush(L, handle, 1);
528 written = write(
529 handle->fd,
530 handle->writebuf + handle->writebufout,
531 handle->writebufin - handle->writebufout
532 );
533 if (written < 0) {
534 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
535 goto moonbr_io_write_impl_block;
536 } else if (errno != EINTR) {
537 moonbr_io_errmsg();
538 lua_pushnil(L);
539 lua_pushstring(L, errmsg);
540 return 2;
541 }
542 } else {
543 handle->writebufout += written;
544 handle->writeleft -= written;
545 if (handle->flushedleft) {
546 if (written >= handle->flushedleft) {
547 handle->flushedleft = 0;
548 moonbr_io_handle_set_nopush(L, handle, 0);
549 } else {
550 handle->flushedleft -= written;
551 }
552 }
553 }
554 }
555 if (handle->writebufout == handle->writebufin) {
556 handle->writebufin = 0;
557 handle->writebufout = 0;
558 }
559 if (nonblocking) lua_pushinteger(L, 0);
560 else lua_pushvalue(L, 1);
561 handle->writeerr = 0;
562 return 1;
563 moonbr_io_write_impl_block:
564 lua_pushinteger(L, handle->writeleft);
565 handle->writeerr = 0;
566 return 1;
567 }
569 static int moonbr_io_write(lua_State *L) {
570 return moonbr_io_write_impl(L, 0, 0);
571 }
573 static int moonbr_io_write_nb(lua_State *L) {
574 return moonbr_io_write_impl(L, 1, 0);
575 }
577 static int moonbr_io_flush(lua_State *L) {
578 return moonbr_io_write_impl(L, 0, 1);
579 }
581 static int moonbr_io_flush_nb(lua_State *L) {
582 return moonbr_io_write_impl(L, 1, 1);
583 }
585 #if LUA_VERSION_NUM >= 503
586 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
587 #else
588 static int moonbr_io_write_cont(lua_State *L) {
589 #endif
590 while (1) {
591 lua_pushcfunction(L, moonbr_io_write_nb);
592 lua_pushvalue(L, 1);
593 lua_call(L, 1, 2);
594 if (lua_isnil(L, -2)) return 2;
595 if (!lua_tointeger(L, -2)) {
596 lua_pushvalue(L, 1);
597 return 1;
598 }
599 lua_pop(L, 2);
600 lua_pushvalue(L, 2);
601 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
602 }
603 }
605 static int moonbr_io_write_call(lua_State *L) {
606 lua_pushcfunction(L, moonbr_io_write_nb);
607 lua_insert(L, 3);
608 lua_pushvalue(L, 1);
609 lua_insert(L, 4);
610 lua_call(L, lua_gettop(L) - 3, 2);
611 if (lua_isnil(L, -2)) return 2;
612 if (!lua_tointeger(L, -2)) {
613 lua_pushvalue(L, 1);
614 return 1;
615 }
616 #if LUA_VERSION_NUM >= 503
617 return moonbr_io_write_cont(L, 0, 0);
618 #else
619 return moonbr_io_write_cont(L);
620 #endif
621 }
623 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
625 static int moonbr_io_flush_call(lua_State *L) {
626 lua_pushcfunction(L, moonbr_io_flush_nb);
627 lua_insert(L, 3);
628 lua_pushvalue(L, 1);
629 lua_insert(L, 4);
630 lua_call(L, lua_gettop(L) - 3, 2);
631 if (lua_isnil(L, -2)) return 2;
632 if (!lua_tointeger(L, -2)) {
633 lua_pushvalue(L, 1);
634 return 1;
635 }
636 #if LUA_VERSION_NUM >= 503
637 return moonbr_io_write_cont(L, 0, 0);
638 #else
639 return moonbr_io_write_cont(L);
640 #endif
641 }
643 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
645 static int moonbr_io_finish(lua_State *L) {
646 moonbr_io_handle_t *handle;
647 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
648 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
649 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
650 if (handle->writeleft) {
651 lua_pushcfunction(L, moonbr_io_flush);
652 lua_pushvalue(L, 1);
653 if (lua_pcall(L, 1, 2, 0)) {
654 handle->finished = 1;
655 lua_error(L);
656 }
657 if (!lua_toboolean(L, -2)) {
658 handle->finished = 1;
659 return 2;
660 }
661 }
662 handle->finished = 1;
663 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
664 if (shutdown(handle->fd, SHUT_WR)) {
665 moonbr_io_errmsg();
666 lua_pushnil(L);
667 lua_pushstring(L, errmsg);
668 return 2;
669 }
670 } else {
671 if (close(handle->fd)) {
672 moonbr_io_errmsg();
673 handle->fd = -1;
674 lua_pushnil(L);
675 lua_pushstring(L, errmsg);
676 return 2;
677 }
678 handle->fd = -1; /* fake EOF on read */
679 }
680 lua_pushboolean(L, 1);
681 return 1;
682 }
684 static int moonbr_io_close_impl(lua_State *L, int reset) {
685 moonbr_io_handle_t *handle;
686 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
687 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
688 if (!reset) {
689 if (handle->writeleft) {
690 lua_pushcfunction(L, moonbr_io_flush);
691 lua_pushvalue(L, 1);
692 if (lua_pcall(L, 1, 2, 0)) {
693 handle->closed = 1;
694 close(handle->fd);
695 handle->fd = -1;
696 lua_error(L);
697 }
698 handle->closed = 1;
699 if (!lua_toboolean(L, -2)) {
700 close(handle->fd);
701 handle->fd = -1;
702 return 2;
703 }
704 } else {
705 handle->closed = 1;
706 moonbr_io_handle_set_linger(L, handle, -1);
707 }
708 } else {
709 handle->closed = 1;
710 }
711 if (handle->fd >= 0) {
712 if (close(handle->fd)) {
713 moonbr_io_errmsg();
714 handle->fd = -1;
715 lua_pushnil(L);
716 lua_pushstring(L, errmsg);
717 return 2;
718 }
719 handle->fd = -1;
720 }
721 lua_pushboolean(L, 1);
722 return 1;
724 }
726 static int moonbr_io_close(lua_State *L) {
727 return moonbr_io_close_impl(L, 0);
728 }
730 static int moonbr_io_reset(lua_State *L) {
731 return moonbr_io_close_impl(L, 1);
732 }
734 static int moonbr_io_handlegc(lua_State *L) {
735 moonbr_io_handle_t *handle;
736 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
737 if (handle->fd >= 0) {
738 lua_pushcfunction(L, moonbr_io_reset);
739 lua_pushvalue(L, 1);
740 lua_pushinteger(L, 0);
741 lua_call(L, 2, 0);
742 }
743 return 0;
744 }
746 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
747 moonbr_io_handle_t *handle;
748 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
749 if (!handle->closed) {
750 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
751 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
752 lua_call(L, 1, 0);
753 }
754 }
756 static int moonbr_io_pushhandle_impl(lua_State *L) {
757 int *fd;
758 moonbr_io_handle_t *handle;
759 struct sockaddr addr;
760 socklen_t addrlen;
761 fd = lua_touserdata(L, 1);
762 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
763 handle->fd = -1; /* avoid closing incomplete handle */
764 addrlen = sizeof(addr);
765 if (getsockname(*fd, &addr, &addrlen)) {
766 if (errno != ENOTSOCK) {
767 moonbr_io_errmsg();
768 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
769 }
770 handle->issock = 0;
771 } else {
772 handle->issock = 1;
773 handle->addrfam = addr.sa_family;
774 }
775 handle->finished = 0;
776 handle->closed = 0;
777 handle->nonblocking = -1;
778 handle->nopush = -1;
779 handle->readerr = 0;
780 handle->readbufin = 0;
781 handle->readbufout = 0;
782 handle->writeerr = 0;
783 handle->writeleft = 0;
784 handle->flushedleft = 0;
785 handle->writeqin = 0;
786 handle->writeqout = 0;
787 handle->writeqoff = 0;
788 handle->writebufin = 0;
789 handle->writebufout = 0;
790 handle->fd = *fd; /* required for set_linger call */
791 moonbr_io_handle_set_linger(L, handle, 0);
792 handle->fd = -1; /* avoid closing incomplete handle */
793 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
794 lua_setmetatable(L, -2);
795 lua_newtable(L); // uservalue
796 lua_newtable(L);
797 lua_setfield(L, -2, "writequeue");
798 lua_newtable(L); // public
799 if (handle->addrfam == AF_INET6) {
800 struct sockaddr_in6 addr_in6;
801 char addrstrbuf[INET6_ADDRSTRLEN];
802 const char *addrstr;
803 addrlen = sizeof(addr_in6);
804 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
805 moonbr_io_errmsg();
806 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
807 }
808 if (addrlen > sizeof(addr_in6)) {
809 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
810 }
811 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
812 if (!addrstr) {
813 moonbr_io_errmsg();
814 luaL_error(L, "Could not format local IP address: %s", errmsg);
815 } else {
816 lua_pushstring(L, addrstr);
817 lua_setfield(L, -2, "local_ip6");
818 }
819 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
820 lua_setfield(L, -2, "local_tcpport");
821 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
822 moonbr_io_errmsg();
823 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
824 }
825 if (addrlen > sizeof(addr_in6)) {
826 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
827 }
828 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
829 if (!addrstr) {
830 moonbr_io_errmsg();
831 luaL_error(L, "Could not format remote IP address: %s", errmsg);
832 } else {
833 lua_pushstring(L, addrstr);
834 lua_setfield(L, -2, "remote_ip6");
835 }
836 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
837 lua_setfield(L, -2, "remote_tcpport");
838 } else if (handle->addrfam == AF_INET) {
839 struct sockaddr_in addr_in;
840 char addrstrbuf[INET_ADDRSTRLEN];
841 const char *addrstr;
842 addrlen = sizeof(addr_in);
843 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
844 moonbr_io_errmsg();
845 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
846 }
847 if (addrlen > sizeof(addr_in)) {
848 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
849 }
850 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
851 if (!addrstr) {
852 moonbr_io_errmsg();
853 luaL_error(L, "Could not format local IP address: %s", errmsg);
854 } else {
855 lua_pushstring(L, addrstr);
856 lua_setfield(L, -2, "local_ip4");
857 }
858 lua_pushinteger(L, ntohs(addr_in.sin_port));
859 lua_setfield(L, -2, "local_tcpport");
860 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
861 moonbr_io_errmsg();
862 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
863 }
864 if (addrlen > sizeof(addr_in)) {
865 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
866 }
867 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
868 if (!addrstr) {
869 moonbr_io_errmsg();
870 luaL_error(L, "Could not format remote IP address: %s", errmsg);
871 } else {
872 lua_pushstring(L, addrstr);
873 lua_setfield(L, -2, "remote_ip4");
874 }
875 lua_pushinteger(L, ntohs(addr_in.sin_port));
876 lua_setfield(L, -2, "remote_tcpport");
877 }
878 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
879 lua_setmetatable(L, -2);
880 lua_setfield(L, -2, "public");
881 lua_setuservalue(L, -2);
882 handle->fd = *fd;
883 *fd = -1; /* closing is now handled by garbage collection */
884 return 1;
885 }
887 void moonbr_io_pushhandle(lua_State *L, int fd) {
888 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
889 lua_pushlightuserdata(L, &fd);
890 if (lua_pcall(L, 1, 1, 0)) {
891 if (fd != -1) close(fd);
892 lua_error(L);
893 }
894 }
896 static int moonbr_io_handleindex(lua_State *L) {
897 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
898 luaL_checkany(L, 2);
899 lua_getuservalue(L, 1);
900 lua_getfield(L, -1, "public");
901 lua_pushvalue(L, 2);
902 lua_gettable(L, -2);
903 return 1;
904 }
906 static int moonbr_io_handlenewindex(lua_State *L) {
907 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
908 luaL_checkany(L, 2);
909 luaL_checkany(L, 3);
910 lua_getuservalue(L, 1);
911 lua_getfield(L, -1, "public");
912 lua_pushvalue(L, 2);
913 lua_pushvalue(L, 3);
914 lua_settable(L, -3);
915 return 0;
916 }
918 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
919 const char *path;
920 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
921 const int path_maxlen = sizeof(struct sockaddr_un) - (
922 (void *)sockaddr.sun_path - (void *)&sockaddr
923 ) - 1; /* one byte for termination */
924 int sock;
925 path = luaL_checkstring(L, 1);
926 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
927 strcpy(sockaddr.sun_path, path);
928 sock = socket(
929 PF_LOCAL,
930 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
931 0
932 );
933 if (sock < 0) {
934 moonbr_io_errmsg();
935 lua_pushnil(L);
936 lua_pushstring(L, errmsg);
937 return 2;
938 }
939 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
940 if (!nonblocking && errno == EINTR) {
941 moonbr_io_errmsg();
942 close(sock);
943 lua_pushnil(L);
944 lua_pushstring(L, errmsg);
945 return 2;
946 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
947 moonbr_io_errmsg();
948 lua_pushnil(L);
949 lua_pushstring(L, errmsg);
950 return 2;
951 }
952 }
953 moonbr_io_pushhandle(L, sock);
954 return 1;
955 }
957 static int moonbr_io_localconnect(lua_State *L) {
958 return moonbr_io_localconnect_impl(L, 0);
959 }
961 static int moonbr_io_localconnect_nb(lua_State *L) {
962 return moonbr_io_localconnect_impl(L, 1);
963 }
965 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
966 const char *host, *port;
967 struct addrinfo hints = { 0, };
968 struct addrinfo *res, *addrinfo;
969 int errcode;
970 int sock;
971 host = luaL_checkstring(L, 1);
972 port = luaL_checkstring(L, 2);
973 hints.ai_family = AF_UNSPEC;
974 hints.ai_socktype = SOCK_STREAM;
975 hints.ai_protocol = IPPROTO_TCP;
976 hints.ai_flags = AI_ADDRCONFIG;
977 errcode = getaddrinfo(host, port, &hints, &res);
978 if (errcode) {
979 freeaddrinfo(res);
980 if (errcode == EAI_SYSTEM) {
981 moonbr_io_errmsg();
982 lua_pushnil(L);
983 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
984 } else {
985 lua_pushnil(L);
986 lua_pushstring(L, gai_strerror(errcode));
987 }
988 return 2;
989 }
990 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
991 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
992 }
993 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
994 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
995 }
996 addrinfo = res;
997 moonbr_io_tcpconnect_found:
998 sock = socket(
999 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1000 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
1001 addrinfo->ai_protocol
1002 );
1003 if (sock < 0) {
1004 moonbr_io_errmsg();
1005 freeaddrinfo(res);
1006 lua_pushnil(L);
1007 lua_pushstring(L, errmsg);
1008 return 2;
1010 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1011 freeaddrinfo(res);
1012 if (!nonblocking && errno == EINTR) {
1013 moonbr_io_errmsg();
1014 close(sock);
1015 lua_pushnil(L);
1016 lua_pushstring(L, errmsg);
1017 return 2;
1018 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
1019 moonbr_io_errmsg();
1020 lua_pushnil(L);
1021 lua_pushstring(L, errmsg);
1022 return 2;
1024 } else {
1025 freeaddrinfo(res);
1027 moonbr_io_pushhandle(L, sock);
1028 return 1;
1031 static int moonbr_io_tcpconnect(lua_State *L) {
1032 return moonbr_io_tcpconnect_impl(L, 0);
1035 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1036 return moonbr_io_tcpconnect_impl(L, 1);
1039 static int moonbr_io_locallisten(lua_State *L) {
1040 moonbr_io_listener_t *listener;
1041 const char *path;
1042 struct stat sb;
1043 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1044 const int path_maxlen = sizeof(struct sockaddr_un) - (
1045 (void *)sockaddr.sun_path - (void *)&sockaddr
1046 ) - 1; /* one byte for termination */
1047 int sock;
1048 path = luaL_checkstring(L, 1);
1049 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1050 strcpy(sockaddr.sun_path, path);
1051 if (stat(path, &sb) == 0) {
1052 if (S_ISSOCK(sb.st_mode)) unlink(path);
1054 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1055 listener->fd = -1;
1056 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1057 sock = socket(
1058 PF_LOCAL,
1059 SOCK_STREAM | SOCK_CLOEXEC,
1061 );
1062 if (sock < 0) {
1063 moonbr_io_errmsg();
1064 lua_pushnil(L);
1065 lua_pushstring(L, errmsg);
1066 return 2;
1068 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1069 moonbr_io_errmsg();
1070 close(sock);
1071 lua_pushnil(L);
1072 lua_pushstring(L, errmsg);
1073 return 2;
1075 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1076 moonbr_io_errmsg();
1077 close(sock);
1078 lua_pushnil(L);
1079 lua_pushstring(L, errmsg);
1080 return 2;
1082 listener->fd = sock;
1083 listener->addrfam = AF_LOCAL;
1084 listener->nonblocking = -1;
1085 return 1;
1088 static int moonbr_io_tcplisten(lua_State *L) {
1089 moonbr_io_listener_t *listener;
1090 const char *host, *port;
1091 struct addrinfo hints = { 0, };
1092 struct addrinfo *res, *addrinfo;
1093 int errcode;
1094 int sock;
1095 host = luaL_optstring(L, 1, NULL);
1096 port = luaL_checkstring(L, 2);
1097 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1098 listener->fd = -1;
1099 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1100 hints.ai_family = AF_UNSPEC;
1101 hints.ai_socktype = SOCK_STREAM;
1102 hints.ai_protocol = IPPROTO_TCP;
1103 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1104 errcode = getaddrinfo(host, port, &hints, &res);
1105 if (errcode) {
1106 freeaddrinfo(res);
1107 if (errcode == EAI_SYSTEM) {
1108 moonbr_io_errmsg();
1109 lua_pushnil(L);
1110 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1111 } else {
1112 lua_pushnil(L);
1113 lua_pushstring(L, gai_strerror(errcode));
1115 return 2;
1117 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1118 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1120 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1121 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1123 addrinfo = res;
1124 moonbr_io_tcpconnect_found:
1125 listener->addrfam = addrinfo->ai_family;
1126 sock = socket(
1127 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1128 addrinfo->ai_socktype | SOCK_CLOEXEC,
1129 addrinfo->ai_protocol
1130 );
1131 if (sock < 0) {
1132 moonbr_io_errmsg();
1133 freeaddrinfo(res);
1134 lua_pushnil(L);
1135 lua_pushstring(L, errmsg);
1136 return 2;
1139 static const int reuseval = 1;
1140 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1141 moonbr_io_errmsg();
1142 freeaddrinfo(res);
1143 close(sock);
1144 lua_pushnil(L);
1145 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1146 return 2;
1149 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1150 moonbr_io_errmsg();
1151 freeaddrinfo(res);
1152 close(sock);
1153 lua_pushnil(L);
1154 lua_pushstring(L, errmsg);
1155 return 2;
1157 freeaddrinfo(res);
1158 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1159 moonbr_io_errmsg();
1160 close(sock);
1161 lua_pushnil(L);
1162 lua_pushstring(L, errmsg);
1163 return 2;
1165 listener->fd = sock;
1166 listener->nonblocking = -1;
1167 return 1;
1170 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1171 moonbr_io_listener_t *listener;
1172 int fd;
1173 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1174 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1175 if (listener->nonblocking != nonblocking) {
1176 int flags;
1177 flags = fcntl(listener->fd, F_GETFL, 0);
1178 if (flags == -1) {
1179 moonbr_io_errmsg();
1180 close(listener->fd);
1181 listener->fd = -1;
1182 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1184 if (nonblocking) flags |= O_NONBLOCK;
1185 else flags &= ~O_NONBLOCK;
1186 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1187 moonbr_io_errmsg();
1188 close(listener->fd);
1189 listener->fd = -1;
1190 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1192 listener->nonblocking = nonblocking;
1194 while (1) {
1195 #if defined(__linux__) && !defined(_GNU_SOURCE)
1196 fd = accept(listener->fd, NULL, NULL);
1197 if (fd != -1) {
1198 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1199 moonbr_io_errmsg();
1200 close(listener->fd);
1201 listener->fd = -1;
1202 close(fd);
1203 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1206 #else
1207 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1208 #endif
1209 if (fd < 0) {
1210 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1211 lua_pushboolean(L, 0);
1212 lua_pushliteral(L, "No incoming connection pending");
1213 return 2;
1214 } else if (errno != EINTR) {
1215 moonbr_io_errmsg();
1216 lua_pushnil(L);
1217 lua_pushstring(L, errmsg);
1218 return 2;
1220 } else {
1221 moonbr_io_pushhandle(L, fd);
1222 return 1;
1227 static int moonbr_io_accept(lua_State *L) {
1228 return moonbr_io_accept_impl(L, 0);
1231 static int moonbr_io_accept_nb(lua_State *L) {
1232 return moonbr_io_accept_impl(L, 1);
1235 static int moonbr_io_unlisten(lua_State *L) {
1236 moonbr_io_listener_t *listener;
1237 struct sockaddr_un addr;
1238 socklen_t addrlen;
1239 struct stat sb;
1240 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1241 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1242 addrlen = sizeof(addr);
1243 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1244 if (close(listener->fd)) {
1245 moonbr_io_errmsg();
1246 listener->fd = -1;
1247 if (addrlen && addrlen <= sizeof(addr)) {
1248 if (stat(addr.sun_path, &sb) == 0) {
1249 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1252 lua_pushnil(L);
1253 lua_pushstring(L, errmsg);
1254 return 2;
1256 listener->fd = -1;
1257 if (addrlen && addrlen <= sizeof(addr)) {
1258 if (stat(addr.sun_path, &sb) == 0) {
1259 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1262 lua_pushboolean(L, 1);
1263 return 1;
1266 static int moonbr_io_listenergc(lua_State *L) {
1267 moonbr_io_listener_t *listener;
1268 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1269 if (listener->fd >= 0) close(listener->fd);
1270 listener->fd = -1;
1271 return 0;
1274 static int moonbr_io_exec(lua_State *L) {
1275 char **argv;
1276 int i, argc;
1277 int sockin[2], sockout[2], sockerr[2];
1278 volatile int errorcond = 0;
1279 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
1280 moonbr_io_child_t *child;
1281 argc = lua_gettop(L);
1282 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1283 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1284 argv[argc] = NULL;
1285 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1286 child->pid = 0;
1287 lua_newtable(L);
1288 lua_setuservalue(L, -2);
1289 luaL_getmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1290 lua_setmetatable(L, -2);
1291 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
1292 moonbr_io_errmsg();
1293 lua_pushnil(L);
1294 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1295 return 2;
1297 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
1298 moonbr_io_errmsg();
1299 close(sockin[0]);
1300 close(sockin[1]);
1301 lua_pushnil(L);
1302 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1303 return 2;
1305 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
1306 moonbr_io_errmsg();
1307 close(sockin[0]);
1308 close(sockin[1]);
1309 close(sockout[0]);
1310 close(sockout[1]);
1311 lua_pushnil(L);
1312 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1313 return 2;
1315 child->pid = vfork();
1316 if (child->pid == -1) {
1317 moonbr_io_errmsg();
1318 close(sockin[0]);
1319 close(sockin[1]);
1320 close(sockout[0]);
1321 close(sockout[1]);
1322 close(sockerr[0]);
1323 close(sockerr[1]);
1324 lua_pushnil(L);
1325 lua_pushfstring(L, "Could not fork: %s", errmsg);
1326 return 2;
1328 if (!child->pid) {
1329 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
1330 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
1331 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
1332 closefrom(3);
1333 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1334 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1335 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1336 if (execvp(argv[0], argv)) {
1337 errorcond = 2;
1338 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1339 _exit(0);
1341 moonbr_io_exec_error1:
1342 errorcond = 1;
1343 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1344 _exit(0);
1346 close(sockin[1]);
1347 close(sockout[1]);
1348 close(sockerr[1]);
1349 if (errorcond) {
1350 int status;
1351 close(sockin[0]);
1352 close(sockout[0]);
1353 close(sockerr[0]);
1354 while (waitpid(child->pid, &status, 0) == -1) {
1355 if (errno != EINTR) {
1356 moonbr_io_errmsg();
1357 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1360 child->pid = 0;
1361 lua_pushnil(L);
1362 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1363 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1364 return 2;
1366 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1367 lua_pushlightuserdata(L, &sockin[0]);
1368 if (lua_pcall(L, 1, 1, 0)) {
1369 if (sockin[0] != -1) close(sockin[0]);
1370 close(sockout[0]);
1371 close(sockerr[0]);
1372 goto moonbr_io_exec_error2;
1374 lua_setfield(L, -2, "stdin");
1375 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1376 lua_pushlightuserdata(L, &sockout[0]);
1377 if (lua_pcall(L, 1, 1, 0)) {
1378 if (sockout[0] != -1) close(sockout[0]);
1379 close(sockerr[0]);
1380 goto moonbr_io_exec_error2;
1382 lua_setfield(L, -2, "stdout");
1383 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1384 lua_pushlightuserdata(L, &sockerr[0]);
1385 if (lua_pcall(L, 1, 1, 0)) {
1386 if (sockerr[0] != -1) close(sockerr[0]);
1387 goto moonbr_io_exec_error2;
1389 lua_setfield(L, -2, "stderr");
1390 return 1;
1391 moonbr_io_exec_error2:
1393 int status;
1394 while (waitpid(child->pid, &status, 0) == -1) {
1395 if (errno != EINTR) {
1396 moonbr_io_errmsg();
1397 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
1401 child->pid = 0;
1402 return lua_error(L);
1405 static int moonbr_io_childindex(lua_State *L) {
1406 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1407 luaL_checkany(L, 2);
1408 lua_getuservalue(L, 1);
1409 lua_pushvalue(L, 2);
1410 lua_gettable(L, -2);
1411 if (lua_isnil(L, -1)) {
1412 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1413 lua_pushvalue(L, 2);
1414 lua_gettable(L, -2);
1416 return 1;
1419 static int moonbr_io_childnewindex(lua_State *L) {
1420 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1421 luaL_checkany(L, 2);
1422 luaL_checkany(L, 3);
1423 lua_getuservalue(L, 1);
1424 lua_pushvalue(L, 2);
1425 lua_pushvalue(L, 3);
1426 lua_settable(L, -3);
1427 return 0;
1430 static int moonbr_io_childgc(lua_State *L) {
1431 moonbr_io_child_t *child;
1432 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1433 if (child->pid) {
1434 int status;
1435 if (kill(child->pid, SIGKILL)) {
1436 moonbr_io_errmsg();
1437 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1439 while (waitpid(child->pid, &status, 0) == -1) {
1440 if (errno != EINTR) {
1441 moonbr_io_errmsg();
1442 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1446 return 0;
1449 static int moonbr_io_kill(lua_State *L) {
1450 moonbr_io_child_t *child;
1451 int sig;
1452 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1453 sig = luaL_optinteger(L, 2, SIGTERM);
1454 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
1455 if (kill(child->pid, sig)) {
1456 moonbr_io_errmsg();
1457 luaL_error(L, "Error in kill call: %s", errmsg);
1459 lua_settop(L, 1);
1460 return 1;
1463 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1464 moonbr_io_child_t *child;
1465 pid_t waitedpid;
1466 int status;
1467 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1468 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
1469 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1470 if (errno != EINTR) {
1471 moonbr_io_errmsg();
1472 luaL_error(L, "Error in waitpid call: %s", errmsg);
1475 if (!waitedpid) {
1476 lua_pushboolean(L, 0);
1477 lua_pushliteral(L, "Process is still running");
1478 return 2;
1479 } else {
1480 child->pid = 0;
1481 if (WIFEXITED(status)) {
1482 lua_pushinteger(L, WEXITSTATUS(status));
1483 } else if (WIFSIGNALED(status)) {
1484 lua_pushinteger(L, -WTERMSIG(status));
1485 } else {
1486 luaL_error(L, "Unexpected status value returned by waitpid call");
1488 return 1;
1492 static int moonbr_io_wait(lua_State *L) {
1493 return moonbr_io_wait_impl(L, 0);
1496 static int moonbr_io_wait_nb(lua_State *L) {
1497 return moonbr_io_wait_impl(L, 1);
1500 #if LUA_VERSION_NUM >= 503
1501 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1502 #else
1503 static int moonbr_io_wait_cont(lua_State *L) {
1504 #endif
1505 #if !(LUA_VERSION_NUM >= 503)
1506 int ctx = 0;
1507 lua_getctx(L, &ctx);
1508 #endif
1509 while (1) {
1510 lua_pushcfunction(L, moonbr_io_wait_nb);
1511 lua_pushvalue(L, 1);
1512 lua_call(L, 1, 1);
1513 if (!lua_isnil(L, -1)) break;
1514 lua_pushvalue(L, 2);
1515 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1517 return 1;
1520 static int moonbr_io_wait_call(lua_State *L) {
1521 lua_settop(L, 2);
1522 #if LUA_VERSION_NUM >= 503
1523 return moonbr_io_wait_cont(L, 0, 0);
1524 #else
1525 return moonbr_io_wait_cont(L);
1526 #endif
1529 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1531 static int moonbr_io_poll(lua_State *L) {
1532 moonbr_io_handle_t *handle;
1533 moonbr_io_listener_t *listener;
1534 int fd, isnum;
1535 int nfds = 0;
1536 fd_set readfds, writefds, exceptfds;
1537 struct timeval timeout = {0, };
1538 int status;
1539 FD_ZERO(&readfds);
1540 FD_ZERO(&writefds);
1541 FD_ZERO(&exceptfds);
1542 if (!lua_isnoneornil(L, 1)) {
1543 luaL_checktype(L, 1, LUA_TTABLE);
1544 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1545 if (lua_toboolean(L, -1)) {
1546 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1547 if (handle) {
1548 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1549 fd = handle->fd;
1550 if (
1551 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1552 handle->readbufin != handle->readbufout /* data pending in buffer */
1553 ) {
1554 lua_pushboolean(L, 1);
1555 return 1;
1557 } else {
1558 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1559 if (listener) {
1560 fd = listener->fd;
1561 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1562 } else {
1563 fd = lua_tointegerx(L, -2, &isnum);
1564 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1567 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1568 FD_SET(fd, &readfds);
1569 if (fd+1 > nfds) nfds = fd+1;
1573 if (!lua_isnoneornil(L, 2)) {
1574 luaL_checktype(L, 2, LUA_TTABLE);
1575 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1576 if (lua_toboolean(L, -1)) {
1577 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1578 if (handle) {
1579 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1580 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1581 fd = handle->fd;
1582 } else {
1583 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1584 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1585 fd = lua_tointegerx(L, -2, &isnum);
1586 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1588 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1589 FD_SET(fd, &writefds);
1590 if (fd+1 > nfds) nfds = fd+1;
1594 if (!lua_isnoneornil(L, 3)) {
1595 lua_Number n;
1596 n = lua_tonumberx(L, 3, &isnum);
1597 if (isnum && n<0) {
1598 lua_pushboolean(L, 0);
1599 lua_pushliteral(L, "Negative timeout");
1600 return 2;
1601 } else if (isnum && n>=0 && n<100000000) {
1602 timeout.tv_sec = n;
1603 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1604 } else {
1605 luaL_argcheck(L, 0, 3, "not a valid timeout");
1607 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1608 } else {
1609 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1611 if (status == -1) {
1612 if (errno == EINTR) {
1613 lua_pushnil(L);
1614 lua_pushliteral(L, "Signal received while polling file descriptors");
1615 return 2;
1616 } else {
1617 moonbr_io_errmsg();
1618 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1620 } else if (status == 0) {
1621 lua_pushboolean(L, 0);
1622 lua_pushliteral(L, "Timeout while polling file descriptors");
1623 return 2;
1624 } else {
1625 lua_pushboolean(L, 1);
1626 return 1;
1630 static int moonbr_io_timeref(lua_State *L) {
1631 lua_Number sub;
1632 struct timespec tp;
1633 sub = luaL_optnumber(L, 1, 0);
1634 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1635 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1637 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1638 return 1;
1641 #ifdef MOONBR_IO_USE_TLS
1642 static int moonbr_io_tlsconf(lua_State *L) {
1643 struct tls_config *tlsconf;
1644 luaL_checktype(L, 1, LUA_TTABLE);
1645 tlsconf = tls_config_new();
1646 if (!tlsconf) {
1647 return luaL_error(L, "Could not allocate memory for TLS configuration");
1649 lua_pushlightuserdata(L, tlsconf);
1650 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
1651 lua_pushvalue(L, 1);
1652 lua_setuservalue(L, -2);
1653 return 1;
1656 static int moonbr_io_tlsconfindex(lua_State *L) {
1657 struct tls_config *tlsconf;
1658 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1659 luaL_checkany(L, 2);
1660 #if LUA_VERSION_NUM >= 503
1661 if (lua_getuservalue(L, 1) == LUA_TNIL) {
1662 #else
1663 lua_getuservalue(L, 1);
1664 if (lua_isnil(L, -1)) {
1665 #endif
1666 return luaL_error(L, "Attempt to use a destroyed TLS configuration");
1668 lua_pushvalue(L, 2);
1669 lua_gettable(L, -2);
1670 return 1;
1673 static int moonbr_io_tlsconfgc(lua_State *L) {
1674 struct tls_config *tlsconf;
1675 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
1676 #if LUA_VERSION_NUM >= 503
1677 if (lua_getuservalue(L, 1) == LUA_TNIL) return 0;
1678 #else
1679 lua_getuservalue(L, 1);
1680 if (lua_isnil(L, -1)) return 0;
1681 #endif
1682 tls_config_free(tlsconf);
1683 lua_pushnil(L);
1684 lua_setuservalue(L, 1);
1685 return 0;
1687 #endif
1689 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1690 {"read", moonbr_io_read},
1691 {"read_nb", moonbr_io_read_nb},
1692 {"read_call", moonbr_io_read_call},
1693 {"read_yield", moonbr_io_read_yield},
1694 {"drain", moonbr_io_drain},
1695 {"drain_nb", moonbr_io_drain_nb},
1696 {"drain_call", moonbr_io_drain_call},
1697 {"drain_yield", moonbr_io_drain_yield},
1698 {"write", moonbr_io_write},
1699 {"write_nb", moonbr_io_write_nb},
1700 {"write_call", moonbr_io_write_call},
1701 {"write_yield", moonbr_io_write_yield},
1702 {"flush", moonbr_io_flush},
1703 {"flush_nb", moonbr_io_flush_nb},
1704 {"flush_call", moonbr_io_flush_call},
1705 {"flush_yield", moonbr_io_flush_yield},
1706 {"finish", moonbr_io_finish},
1707 {"close", moonbr_io_close},
1708 {"reset", moonbr_io_reset},
1709 {NULL, NULL}
1710 };
1712 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1713 {"__index", moonbr_io_handleindex},
1714 {"__newindex", moonbr_io_handlenewindex},
1715 {"__gc", moonbr_io_handlegc},
1716 {NULL, NULL}
1717 };
1719 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1720 {"accept", moonbr_io_accept},
1721 {"accept_nb", moonbr_io_accept_nb},
1722 {"close", moonbr_io_unlisten},
1723 {NULL, NULL}
1724 };
1726 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1727 {"__gc", moonbr_io_listenergc},
1728 {NULL, NULL}
1729 };
1731 static const struct luaL_Reg moonbr_io_child_methods[] = {
1732 {"kill", moonbr_io_kill},
1733 {"wait", moonbr_io_wait},
1734 {"wait_nb", moonbr_io_wait_nb},
1735 {"wait_call", moonbr_io_wait_call},
1736 {"wait_yield", moonbr_io_wait_yield},
1737 {NULL, NULL}
1738 };
1740 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
1741 {"__index", moonbr_io_childindex},
1742 {"__newindex", moonbr_io_childnewindex},
1743 {"__gc", moonbr_io_childgc},
1744 {NULL, NULL}
1745 };
1747 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1748 {"localconnect", moonbr_io_localconnect},
1749 {"localconnect_nb", moonbr_io_localconnect_nb},
1750 {"tcpconnect", moonbr_io_tcpconnect},
1751 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1752 {"locallisten", moonbr_io_locallisten},
1753 {"tcplisten", moonbr_io_tcplisten},
1754 {"exec", moonbr_io_exec},
1755 {"poll", moonbr_io_poll},
1756 {"timeref", moonbr_io_timeref},
1757 #ifdef MOONBR_IO_USE_TLS
1758 {"tlsconf", moonbr_io_tlsconf},
1759 #endif
1760 {NULL, NULL}
1761 };
1763 #ifdef MOONBR_IO_USE_TLS
1764 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
1765 {"__index", moonbr_io_tlsconfindex},
1766 {"__gc", moonbr_io_tlsconfgc},
1767 {NULL, NULL}
1768 };
1769 #endif
1771 int luaopen_moonbridge_io(lua_State *L) {
1773 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1775 lua_newtable(L); // module
1777 lua_newtable(L); // public metatable
1778 lua_newtable(L); // handle methods
1779 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1780 lua_pushvalue(L, -1);
1781 lua_setfield(L, -4, "handle_pt");
1782 lua_setfield(L, -2, "__index");
1783 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1785 lua_newtable(L); // handle metatable
1786 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1787 lua_pushvalue(L, -1);
1788 lua_setfield(L, -3, "handle_mt");
1789 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1791 lua_newtable(L); // listener metatable
1792 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1793 lua_newtable(L); // listener methods
1794 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1795 lua_pushvalue(L, -1);
1796 lua_setfield(L, -4, "listener_pt");
1797 lua_setfield(L, -2, "__index");
1798 lua_pushvalue(L, -1);
1799 lua_setfield(L, -3, "listener_mt");
1800 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1802 lua_newtable(L); // child methods
1803 luaL_setfuncs(L, moonbr_io_child_methods, 0);
1804 lua_pushvalue(L, -1);
1805 lua_setfield(L, -3, "child_pt");
1806 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
1807 lua_newtable(L); // child metatable
1808 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
1809 lua_pushvalue(L, -1);
1810 lua_setfield(L, -3, "child_mt");
1811 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
1813 #ifdef MOONBR_IO_USE_TLS
1814 if(tls_init()) {
1815 return luaL_error(L, "Could not initialize TLS library");
1817 lua_newtable(L); // tlsconf metatable
1818 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
1819 lua_pushvalue(L, -1);
1820 lua_setfield(L, -3, "tlsconf_mt");
1821 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
1822 #endif
1824 moonbr_io_pushhandle(L, 0);
1825 lua_setfield(L, -2, "stdin");
1826 moonbr_io_pushhandle(L, 1);
1827 lua_setfield(L, -2, "stdout");
1828 moonbr_io_pushhandle(L, 2);
1829 lua_setfield(L, -2, "stderr");
1831 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1832 return 1;

Impressum / About Us