moonbridge

view moonbridge_io.c @ 212:453b7d1a7944

Avoid use of accept4() function in favor of accept() to avoid using _GNU_SOURCE on GNU/Linux
author jbe
date Mon Jun 22 22:19:41 2015 +0200 (2015-06-22)
parents a3d569d3e85d
children 43a077f2ab49
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 #include <lua.h>
29 #include <lauxlib.h>
30 #include <lualib.h>
32 #include <assert.h>
34 #define MOONBR_IO_MAXSTRERRORLEN 80
35 #define MOONBR_IO_READBUFLEN 4096
36 #define MOONBR_IO_WRITEBUFLEN 4096
38 #define MOONBR_IO_LISTEN_BACKLOG 1024
40 #define moonbr_io_errmsg() \
41 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
42 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
44 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
45 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
46 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
47 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
48 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
50 typedef struct {
51 int fd;
52 int issock;
53 sa_family_t addrfam;
54 int finished;
55 int closed;
56 int nonblocking;
57 int nopush;
58 int readerr;
59 int readbufin;
60 int readbufout;
61 int writeerr;
62 size_t writeleft;
63 size_t flushedleft;
64 #if LUA_VERSION_NUM >= 503
65 lua_Integer writeqin;
66 lua_Integer writeqout;
67 #else
68 int writeqin;
69 int writeqout;
70 #endif
71 size_t writeqoff;
72 int writebufin;
73 int writebufout;
74 char readbuf[MOONBR_IO_READBUFLEN];
75 char writebuf[MOONBR_IO_WRITEBUFLEN];
76 } moonbr_io_handle_t;
78 typedef struct {
79 int fd;
80 sa_family_t addrfam;
81 int nonblocking;
82 } moonbr_io_listener_t;
84 typedef struct {
85 pid_t pid;
86 } moonbr_io_child_t;
88 static int moonbr_io_yield(lua_State *L) {
89 return lua_yield(L, lua_gettop(L));
90 }
92 #if LUA_VERSION_NUM >= 503
93 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
94 #else
95 static int moonbr_io_cont_returnall(lua_State *L) {
96 #endif
97 return lua_gettop(L);
98 }
100 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
101 static int yieldfunc(lua_State *L) { \
102 int args; \
103 lua_pushcfunction(L, callfunc); \
104 lua_insert(L, 1); \
105 args = lua_gettop(L); \
106 lua_pushcfunction(L, moonbr_io_yield); \
107 lua_insert(L, 3); \
108 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
109 return lua_gettop(L); \
110 }
112 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
113 int flags;
114 if (handle->nonblocking == nonblocking) return;
115 flags = fcntl(handle->fd, F_GETFL, 0);
116 if (flags == -1) {
117 moonbr_io_errmsg();
118 close(handle->fd);
119 handle->fd = -1;
120 handle->closed = 1;
121 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
122 }
123 if (nonblocking) flags |= O_NONBLOCK;
124 else flags &= ~O_NONBLOCK;
125 if (fcntl(handle->fd, F_SETFL, 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 handle->nonblocking = nonblocking;
133 }
135 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
136 struct linger lingerval = { 0, };
137 if (!handle->issock) return;
138 if (timeout >= 0) {
139 lingerval.l_onoff = 1;
140 lingerval.l_linger = timeout;
141 }
142 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
143 moonbr_io_errmsg();
144 close(handle->fd);
145 handle->fd = -1;
146 handle->closed = 1;
147 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
148 }
149 }
151 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
152 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
153 if (
154 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
155 handle->nopush == nopush
156 ) return;
157 #if defined(TCP_NOPUSH)
158 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
159 #elif defined(TCP_CORK)
160 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
161 #endif
162 moonbr_io_errmsg();
163 close(handle->fd);
164 handle->fd = -1;
165 handle->closed = 1;
166 #if defined(TCP_NOPUSH)
167 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
168 #elif defined(TCP_CORK)
169 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
170 #endif
171 }
172 handle->nopush = nopush;
173 #else
174 #warning Neither TCP_NOPUSH nor TCP_CORK is available
175 #endif
176 }
178 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
179 moonbr_io_handle_t *handle;
180 lua_Integer maxread;
181 const char *terminatorstr;
182 size_t terminatorlen;
183 char terminator = 0; /* initialize to avoid compiler warning */
184 luaL_Buffer luabuf;
185 size_t luabufcnt = 0;
186 int remaining;
187 char *terminatorpos;
188 ssize_t bytesread;
189 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
190 maxread = luaL_optinteger(L, 2, -1);
191 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
192 if (terminatorlen) {
193 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
194 terminator = terminatorstr[0];
195 }
196 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
197 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
198 if (handle->readerr) {
199 lua_pushnil(L);
200 lua_pushliteral(L, "Previous read error");
201 return 2;
202 }
203 if (handle->fd < 0) {
204 /* fake EOF to simulate shutdown */
205 if (!drain) lua_pushliteral(L, "");
206 else lua_pushinteger(L, 0);
207 lua_pushliteral(L, "eof");
208 return 2;
209 }
210 handle->readerr = 1;
211 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
212 if (!drain) luaL_buffinit(L, &luabuf);
213 while (1) {
214 remaining = -1;
215 terminatorpos = NULL;
216 if (
217 maxread >= 0 &&
218 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
219 ) {
220 remaining = (size_t)maxread - luabufcnt;
221 if (terminatorlen) {
222 terminatorpos = memchr(
223 handle->readbuf + handle->readbufout,
224 terminator,
225 remaining
226 );
227 }
228 } else if (terminatorlen) {
229 terminatorpos = memchr(
230 handle->readbuf + handle->readbufout,
231 terminator,
232 handle->readbufin - handle->readbufout
233 );
234 }
235 if (terminatorpos) remaining = 1 + (
236 terminatorpos - (handle->readbuf + handle->readbufout)
237 );
238 if (remaining >= 0) {
239 if (!drain) {
240 luaL_addlstring(
241 &luabuf,
242 handle->readbuf + handle->readbufout,
243 remaining
244 );
245 luaL_pushresult(&luabuf);
246 } else {
247 lua_pushinteger(L, luabufcnt + remaining);
248 }
249 if (terminatorpos) lua_pushliteral(L, "term");
250 else lua_pushliteral(L, "maxlen");
251 handle->readbufout += remaining;
252 if (handle->readbufout == handle->readbufin) {
253 handle->readbufin = 0;
254 handle->readbufout = 0;
255 }
256 handle->readerr = 0;
257 return 2;
258 }
259 if (!drain) luaL_addlstring(
260 &luabuf,
261 handle->readbuf + handle->readbufout,
262 handle->readbufin - handle->readbufout
263 );
264 luabufcnt += handle->readbufin - handle->readbufout;
265 handle->readbufout = 0;
266 do {
267 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
268 } while (bytesread < 0 && (errno == EINTR));
269 if (
270 bytesread == 0 || (
271 nonblocking &&
272 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
273 )
274 ) {
275 handle->readbufin = 0;
276 if (!drain) luaL_pushresult(&luabuf);
277 else lua_pushinteger(L, luabufcnt);
278 if (bytesread == 0) lua_pushliteral(L, "eof");
279 else lua_pushliteral(L, "block");
280 handle->readerr = 0;
281 return 2;
282 }
283 if (bytesread < 0) {
284 moonbr_io_errmsg();
285 lua_pushnil(L);
286 lua_pushstring(L, errmsg);
287 return 2;
288 }
289 handle->readbufin = bytesread;
290 }
291 }
293 static int moonbr_io_read(lua_State *L) {
294 return moonbr_io_read_impl(L, 0, 0);
295 }
297 static int moonbr_io_read_nb(lua_State *L) {
298 return moonbr_io_read_impl(L, 1, 0);
299 }
301 static int moonbr_io_drain(lua_State *L) {
302 return moonbr_io_read_impl(L, 0, 1);
303 }
305 static int moonbr_io_drain_nb(lua_State *L) {
306 return moonbr_io_read_impl(L, 1, 1);
307 }
309 #if LUA_VERSION_NUM >= 503
310 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
311 #else
312 static int moonbr_io_read_cont(lua_State *L) {
313 #endif
314 lua_Integer remaining;
315 size_t len;
316 #if !(LUA_VERSION_NUM >= 503)
317 int ctx = 0;
318 lua_getctx(L, &ctx);
319 #endif
320 remaining = lua_tointeger(L, 3);
321 while (1) {
322 lua_pushcfunction(L, moonbr_io_read_nb);
323 lua_pushvalue(L, 1);
324 lua_pushvalue(L, 3);
325 lua_pushvalue(L, 4);
326 lua_call(L, 3, 2);
327 if (lua_isnil(L, -2)) return 2;
328 lua_insert(L, -2);
329 len = lua_rawlen(L, -1);
330 if (ctx == 0) {
331 lua_replace(L, 5);
332 ctx = 1;
333 } else if (ctx == 1) {
334 lua_pushvalue(L, 5);
335 lua_newtable(L);
336 lua_replace(L, 5);
337 lua_rawseti(L, 5, 2);
338 lua_rawseti(L, 5, 1);
339 ctx = 2;
340 } else {
341 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
342 }
343 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
344 lua_pop(L, 1);
345 if (remaining >= 0 && len) {
346 remaining -= len;
347 lua_pushinteger(L, remaining);
348 lua_replace(L, 3);
349 }
350 lua_pushvalue(L, 2);
351 lua_callk(L, 0, 0, ctx, moonbr_io_read_cont);
352 }
353 if (ctx == 1) {
354 lua_pushvalue(L, 5);
355 } else {
356 luaL_Buffer buf;
357 lua_Integer i, chunkcount;
358 chunkcount = lua_rawlen(L, 5);
359 luaL_buffinit(L, &buf);
360 for (i=1; i<=chunkcount && i>0; i++) {
361 lua_rawgeti(L, 5, i);
362 luaL_addvalue(&buf);
363 }
364 luaL_pushresult(&buf);
365 }
366 lua_pushvalue(L, -2);
367 return 2;
368 }
370 static int moonbr_io_read_call(lua_State *L) {
371 lua_settop(L, 4);
372 lua_pushnil(L);
373 #if LUA_VERSION_NUM >= 503
374 return moonbr_io_read_cont(L, 0, 0);
375 #else
376 return moonbr_io_read_cont(L);
377 #endif
378 }
380 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
382 #if LUA_VERSION_NUM >= 503
383 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
384 #else
385 static int moonbr_io_drain_cont(lua_State *L) {
386 #endif
387 lua_Integer remaining, len;
388 size_t totallen = 0;
389 #if !(LUA_VERSION_NUM >= 503)
390 int ctx = 0;
391 lua_getctx(L, &ctx);
392 #endif
393 remaining = lua_tointeger(L, 3);
394 while (1) {
395 lua_pushcfunction(L, moonbr_io_drain_nb);
396 lua_pushvalue(L, 1);
397 lua_pushvalue(L, 3);
398 lua_pushvalue(L, 4);
399 lua_call(L, 3, 2);
400 if (lua_isnil(L, -2)) return 2;
401 lua_insert(L, -2);
402 len = lua_tointeger(L, -1);
403 lua_pop(L, 1);
404 totallen += len;
405 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
406 lua_pop(L, 1);
407 if (remaining >= 0 && len) {
408 remaining -= len;
409 lua_pushinteger(L, remaining);
410 lua_replace(L, 3);
411 }
412 lua_pushvalue(L, 2);
413 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
414 }
415 lua_pushinteger(L, totallen);
416 lua_pushvalue(L, -2);
417 return 2;
418 }
420 static int moonbr_io_drain_call(lua_State *L) {
421 #if LUA_VERSION_NUM >= 503
422 return moonbr_io_drain_cont(L, 0, 0);
423 #else
424 return moonbr_io_drain_cont(L);
425 #endif
426 }
428 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
430 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
431 moonbr_io_handle_t *handle;
432 int i, top;
433 const char *str;
434 size_t strlen;
435 ssize_t written;
436 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
437 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
438 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
439 if (handle->writeerr) {
440 lua_pushnil(L);
441 lua_pushliteral(L, "Previous write error");
442 return 2;
443 }
444 handle->writeerr = 1;
445 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
446 top = lua_gettop(L);
447 lua_getuservalue(L, 1);
448 lua_getfield(L, -1, "writequeue");
449 for (i=2; i<=top; i++) {
450 luaL_checklstring(L, i, &strlen);
451 lua_pushvalue(L, i);
452 lua_rawseti(L, -2, handle->writeqin++);
453 handle->writeleft += strlen;
454 }
455 if (flush) handle->flushedleft = handle->writeleft;
456 while (handle->writeqout != handle->writeqin) {
457 lua_rawgeti(L, -1, handle->writeqout);
458 str = lua_tolstring(L, -1, &strlen);
459 while (handle->writeqoff < strlen) {
460 if (
461 strlen - handle->writeqoff <
462 MOONBR_IO_WRITEBUFLEN - handle->writebufin
463 ) {
464 memcpy(
465 handle->writebuf + handle->writebufin,
466 str + handle->writeqoff,
467 strlen - handle->writeqoff
468 );
469 handle->writebufin += strlen - handle->writeqoff;
470 break;
471 } else {
472 memcpy(
473 handle->writebuf + handle->writebufin,
474 str + handle->writeqoff,
475 MOONBR_IO_WRITEBUFLEN - handle->writebufin
476 );
477 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
478 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
479 moonbr_io_handle_set_nopush(L, handle, 1);
480 written = write(
481 handle->fd,
482 handle->writebuf + handle->writebufout,
483 MOONBR_IO_WRITEBUFLEN - handle->writebufout
484 );
485 if (written < 0) {
486 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
487 goto moonbr_io_write_impl_block;
488 } else if (errno != EINTR) {
489 moonbr_io_errmsg();
490 lua_pushnil(L);
491 lua_pushstring(L, errmsg);
492 return 2;
493 }
494 } else {
495 handle->writebufout += written;
496 handle->writeleft -= written;
497 if (handle->flushedleft) {
498 if (written >= handle->flushedleft) {
499 handle->flushedleft = 0;
500 moonbr_io_handle_set_nopush(L, handle, 0);
501 } else {
502 handle->flushedleft -= written;
503 }
504 }
505 }
506 }
507 handle->writebufin = 0;
508 handle->writebufout = 0;
509 }
510 }
511 handle->writeqoff = 0;
512 lua_pop(L, 1);
513 lua_pushnil(L);
514 lua_rawseti(L, -2, handle->writeqout++);
515 }
516 while (handle->flushedleft) {
517 moonbr_io_handle_set_nopush(L, handle, 1);
518 written = write(
519 handle->fd,
520 handle->writebuf + handle->writebufout,
521 handle->writebufin - handle->writebufout
522 );
523 if (written < 0) {
524 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
525 goto moonbr_io_write_impl_block;
526 } else if (errno != EINTR) {
527 moonbr_io_errmsg();
528 lua_pushnil(L);
529 lua_pushstring(L, errmsg);
530 return 2;
531 }
532 } else {
533 handle->writebufout += written;
534 handle->writeleft -= written;
535 if (handle->flushedleft) {
536 if (written >= handle->flushedleft) {
537 handle->flushedleft = 0;
538 moonbr_io_handle_set_nopush(L, handle, 0);
539 } else {
540 handle->flushedleft -= written;
541 }
542 }
543 }
544 }
545 if (handle->writebufout == handle->writebufin) {
546 handle->writebufin = 0;
547 handle->writebufout = 0;
548 }
549 if (nonblocking) lua_pushinteger(L, 0);
550 else lua_pushvalue(L, 1);
551 handle->writeerr = 0;
552 return 1;
553 moonbr_io_write_impl_block:
554 lua_pushinteger(L, handle->writeleft);
555 handle->writeerr = 0;
556 return 1;
557 }
559 static int moonbr_io_write(lua_State *L) {
560 return moonbr_io_write_impl(L, 0, 0);
561 }
563 static int moonbr_io_write_nb(lua_State *L) {
564 return moonbr_io_write_impl(L, 1, 0);
565 }
567 static int moonbr_io_flush(lua_State *L) {
568 return moonbr_io_write_impl(L, 0, 1);
569 }
571 static int moonbr_io_flush_nb(lua_State *L) {
572 return moonbr_io_write_impl(L, 1, 1);
573 }
575 #if LUA_VERSION_NUM >= 503
576 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
577 #else
578 static int moonbr_io_write_cont(lua_State *L) {
579 #endif
580 while (1) {
581 lua_pushcfunction(L, moonbr_io_write_nb);
582 lua_pushvalue(L, 1);
583 lua_call(L, 1, 2);
584 if (lua_isnil(L, -2)) return 2;
585 if (!lua_tointeger(L, -2)) {
586 lua_pushvalue(L, 1);
587 return 1;
588 }
589 lua_pop(L, 2);
590 lua_pushvalue(L, 2);
591 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
592 }
593 }
595 static int moonbr_io_write_call(lua_State *L) {
596 lua_pushcfunction(L, moonbr_io_write_nb);
597 lua_insert(L, 3);
598 lua_pushvalue(L, 1);
599 lua_insert(L, 4);
600 lua_call(L, lua_gettop(L) - 3, 2);
601 if (lua_isnil(L, -2)) return 2;
602 if (!lua_tointeger(L, -2)) {
603 lua_pushvalue(L, 1);
604 return 1;
605 }
606 #if LUA_VERSION_NUM >= 503
607 return moonbr_io_write_cont(L, 0, 0);
608 #else
609 return moonbr_io_write_cont(L);
610 #endif
611 }
613 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
615 static int moonbr_io_flush_call(lua_State *L) {
616 lua_pushcfunction(L, moonbr_io_flush_nb);
617 lua_insert(L, 3);
618 lua_pushvalue(L, 1);
619 lua_insert(L, 4);
620 lua_call(L, lua_gettop(L) - 3, 2);
621 if (lua_isnil(L, -2)) return 2;
622 if (!lua_tointeger(L, -2)) {
623 lua_pushvalue(L, 1);
624 return 1;
625 }
626 #if LUA_VERSION_NUM >= 503
627 return moonbr_io_write_cont(L, 0, 0);
628 #else
629 return moonbr_io_write_cont(L);
630 #endif
631 }
633 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
635 static int moonbr_io_finish(lua_State *L) {
636 moonbr_io_handle_t *handle;
637 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
638 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
639 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
640 if (handle->writeleft) {
641 lua_pushcfunction(L, moonbr_io_flush);
642 lua_pushvalue(L, 1);
643 if (lua_pcall(L, 1, 2, 0)) {
644 handle->finished = 1;
645 lua_error(L);
646 }
647 if (!lua_toboolean(L, -2)) {
648 handle->finished = 1;
649 return 2;
650 }
651 }
652 handle->finished = 1;
653 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
654 if (shutdown(handle->fd, SHUT_WR)) {
655 moonbr_io_errmsg();
656 lua_pushnil(L);
657 lua_pushstring(L, errmsg);
658 return 2;
659 }
660 } else {
661 if (close(handle->fd)) {
662 moonbr_io_errmsg();
663 handle->fd = -1;
664 lua_pushnil(L);
665 lua_pushstring(L, errmsg);
666 return 2;
667 }
668 handle->fd = -1; /* fake EOF on read */
669 }
670 lua_pushboolean(L, 1);
671 return 1;
672 }
674 static int moonbr_io_close_impl(lua_State *L, int reset) {
675 moonbr_io_handle_t *handle;
676 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
677 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
678 if (!reset) {
679 if (handle->writeleft) {
680 lua_pushcfunction(L, moonbr_io_flush);
681 lua_pushvalue(L, 1);
682 if (lua_pcall(L, 1, 2, 0)) {
683 handle->closed = 1;
684 close(handle->fd);
685 handle->fd = -1;
686 lua_error(L);
687 }
688 handle->closed = 1;
689 if (!lua_toboolean(L, -2)) {
690 close(handle->fd);
691 handle->fd = -1;
692 return 2;
693 }
694 } else {
695 handle->closed = 1;
696 moonbr_io_handle_set_linger(L, handle, -1);
697 }
698 } else {
699 handle->closed = 1;
700 }
701 if (handle->fd >= 0) {
702 if (close(handle->fd)) {
703 moonbr_io_errmsg();
704 handle->fd = -1;
705 lua_pushnil(L);
706 lua_pushstring(L, errmsg);
707 return 2;
708 }
709 handle->fd = -1;
710 }
711 lua_pushboolean(L, 1);
712 return 1;
714 }
716 static int moonbr_io_close(lua_State *L) {
717 return moonbr_io_close_impl(L, 0);
718 }
720 static int moonbr_io_reset(lua_State *L) {
721 return moonbr_io_close_impl(L, 1);
722 }
724 static int moonbr_io_handlegc(lua_State *L) {
725 moonbr_io_handle_t *handle;
726 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
727 if (handle->fd >= 0) {
728 lua_pushcfunction(L, moonbr_io_close);
729 lua_pushvalue(L, 1);
730 lua_pushinteger(L, 0);
731 lua_call(L, 2, 0);
732 }
733 return 0;
734 }
736 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
737 moonbr_io_handle_t *handle;
738 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
739 if (!handle->closed) {
740 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
741 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
742 lua_call(L, 1, 0);
743 }
744 }
746 static int moonbr_io_pushhandle_impl(lua_State *L) {
747 int *fd;
748 moonbr_io_handle_t *handle;
749 struct sockaddr addr;
750 socklen_t addrlen;
751 fd = lua_touserdata(L, 1);
752 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
753 handle->fd = -1; /* avoid closing incomplete handle */
754 addrlen = sizeof(addr);
755 if (getsockname(*fd, &addr, &addrlen)) {
756 if (errno != ENOTSOCK) {
757 moonbr_io_errmsg();
758 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
759 }
760 handle->issock = 0;
761 } else {
762 handle->issock = 1;
763 handle->addrfam = addr.sa_family;
764 }
765 handle->finished = 0;
766 handle->closed = 0;
767 handle->nonblocking = -1;
768 handle->nopush = -1;
769 handle->readerr = 0;
770 handle->readbufin = 0;
771 handle->readbufout = 0;
772 handle->writeerr = 0;
773 handle->writeleft = 0;
774 handle->flushedleft = 0;
775 handle->writeqin = 0;
776 handle->writeqout = 0;
777 handle->writeqoff = 0;
778 handle->writebufin = 0;
779 handle->writebufout = 0;
780 handle->fd = *fd; /* required for set_linger call */
781 moonbr_io_handle_set_linger(L, handle, 0);
782 handle->fd = -1; /* avoid closing incomplete handle */
783 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
784 lua_setmetatable(L, -2);
785 lua_newtable(L); // uservalue
786 lua_newtable(L);
787 lua_setfield(L, -2, "writequeue");
788 lua_newtable(L); // public
789 if (handle->addrfam == AF_INET6) {
790 struct sockaddr_in6 addr_in6;
791 char addrstrbuf[INET6_ADDRSTRLEN];
792 const char *addrstr;
793 addrlen = sizeof(addr_in6);
794 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
795 moonbr_io_errmsg();
796 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
797 }
798 if (addrlen > sizeof(addr_in6)) {
799 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
800 }
801 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
802 if (!addrstr) {
803 moonbr_io_errmsg();
804 luaL_error(L, "Could not format local IP address: %s", errmsg);
805 } else {
806 lua_pushstring(L, addrstr);
807 lua_setfield(L, -2, "local_ip6");
808 }
809 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
810 lua_setfield(L, -2, "local_tcpport");
811 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
812 moonbr_io_errmsg();
813 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
814 }
815 if (addrlen > sizeof(addr_in6)) {
816 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
817 }
818 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
819 if (!addrstr) {
820 moonbr_io_errmsg();
821 luaL_error(L, "Could not format remote IP address: %s", errmsg);
822 } else {
823 lua_pushstring(L, addrstr);
824 lua_setfield(L, -2, "remote_ip6");
825 }
826 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
827 lua_setfield(L, -2, "remote_tcpport");
828 } else if (handle->addrfam == AF_INET) {
829 struct sockaddr_in addr_in;
830 char addrstrbuf[INET_ADDRSTRLEN];
831 const char *addrstr;
832 addrlen = sizeof(addr_in);
833 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
834 moonbr_io_errmsg();
835 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
836 }
837 if (addrlen > sizeof(addr_in)) {
838 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
839 }
840 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
841 if (!addrstr) {
842 moonbr_io_errmsg();
843 luaL_error(L, "Could not format local IP address: %s", errmsg);
844 } else {
845 lua_pushstring(L, addrstr);
846 lua_setfield(L, -2, "local_ip4");
847 }
848 lua_pushinteger(L, ntohs(addr_in.sin_port));
849 lua_setfield(L, -2, "local_tcpport");
850 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
851 moonbr_io_errmsg();
852 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
853 }
854 if (addrlen > sizeof(addr_in)) {
855 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
856 }
857 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
858 if (!addrstr) {
859 moonbr_io_errmsg();
860 luaL_error(L, "Could not format remote IP address: %s", errmsg);
861 } else {
862 lua_pushstring(L, addrstr);
863 lua_setfield(L, -2, "remote_ip4");
864 }
865 lua_pushinteger(L, ntohs(addr_in.sin_port));
866 lua_setfield(L, -2, "remote_tcpport");
867 }
868 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
869 lua_setmetatable(L, -2);
870 lua_setfield(L, -2, "public");
871 lua_setuservalue(L, -2);
872 handle->fd = *fd;
873 *fd = -1; /* closing is now handled by garbage collection */
874 return 1;
875 }
877 void moonbr_io_pushhandle(lua_State *L, int fd) {
878 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
879 lua_pushlightuserdata(L, &fd);
880 if (lua_pcall(L, 1, 1, 0)) {
881 if (fd != -1) close(fd);
882 lua_error(L);
883 }
884 }
886 static int moonbr_io_handleindex(lua_State *L) {
887 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
888 luaL_checkany(L, 2);
889 lua_getuservalue(L, 1);
890 lua_getfield(L, -1, "public");
891 lua_pushvalue(L, 2);
892 lua_gettable(L, -2);
893 return 1;
894 }
896 static int moonbr_io_handlenewindex(lua_State *L) {
897 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
898 luaL_checkany(L, 2);
899 luaL_checkany(L, 3);
900 lua_getuservalue(L, 1);
901 lua_getfield(L, -1, "public");
902 lua_pushvalue(L, 2);
903 lua_pushvalue(L, 3);
904 lua_settable(L, -3);
905 return 0;
906 }
908 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
909 const char *path;
910 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
911 const int path_maxlen = sizeof(struct sockaddr_un) - (
912 (void *)sockaddr.sun_path - (void *)&sockaddr
913 ) - 1; /* one byte for termination */
914 int sock;
915 path = luaL_checkstring(L, 1);
916 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
917 strcpy(sockaddr.sun_path, path);
918 sock = socket(
919 PF_LOCAL,
920 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
921 0
922 );
923 if (sock < 0) {
924 moonbr_io_errmsg();
925 lua_pushnil(L);
926 lua_pushstring(L, errmsg);
927 return 2;
928 }
929 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
930 if (!nonblocking && errno == EINTR) {
931 moonbr_io_errmsg();
932 close(sock);
933 lua_pushnil(L);
934 lua_pushstring(L, errmsg);
935 return 2;
936 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
937 moonbr_io_errmsg();
938 lua_pushnil(L);
939 lua_pushstring(L, errmsg);
940 return 2;
941 }
942 }
943 moonbr_io_pushhandle(L, sock);
944 return 1;
945 }
947 static int moonbr_io_localconnect(lua_State *L) {
948 return moonbr_io_localconnect_impl(L, 0);
949 }
951 static int moonbr_io_localconnect_nb(lua_State *L) {
952 return moonbr_io_localconnect_impl(L, 1);
953 }
955 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
956 const char *host, *port;
957 struct addrinfo hints = { 0, };
958 struct addrinfo *res, *addrinfo;
959 int errcode;
960 int sock;
961 host = luaL_checkstring(L, 1);
962 port = luaL_checkstring(L, 2);
963 hints.ai_family = AF_UNSPEC;
964 hints.ai_socktype = SOCK_STREAM;
965 hints.ai_protocol = IPPROTO_TCP;
966 hints.ai_flags = AI_ADDRCONFIG;
967 errcode = getaddrinfo(host, port, &hints, &res);
968 if (errcode) {
969 freeaddrinfo(res);
970 if (errcode == EAI_SYSTEM) {
971 moonbr_io_errmsg();
972 lua_pushnil(L);
973 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
974 } else {
975 lua_pushnil(L);
976 lua_pushstring(L, gai_strerror(errcode));
977 }
978 return 2;
979 }
980 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
981 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
982 }
983 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
984 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
985 }
986 addrinfo = res;
987 moonbr_io_tcpconnect_found:
988 sock = socket(
989 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
990 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
991 addrinfo->ai_protocol
992 );
993 if (sock < 0) {
994 moonbr_io_errmsg();
995 freeaddrinfo(res);
996 lua_pushnil(L);
997 lua_pushstring(L, errmsg);
998 return 2;
999 }
1000 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1001 freeaddrinfo(res);
1002 if (!nonblocking && errno == EINTR) {
1003 moonbr_io_errmsg();
1004 close(sock);
1005 lua_pushnil(L);
1006 lua_pushstring(L, errmsg);
1007 return 2;
1008 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
1009 moonbr_io_errmsg();
1010 lua_pushnil(L);
1011 lua_pushstring(L, errmsg);
1012 return 2;
1014 } else {
1015 freeaddrinfo(res);
1017 moonbr_io_pushhandle(L, sock);
1018 return 1;
1021 static int moonbr_io_tcpconnect(lua_State *L) {
1022 return moonbr_io_tcpconnect_impl(L, 0);
1025 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1026 return moonbr_io_tcpconnect_impl(L, 1);
1029 static int moonbr_io_locallisten(lua_State *L) {
1030 moonbr_io_listener_t *listener;
1031 const char *path;
1032 struct stat sb;
1033 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1034 const int path_maxlen = sizeof(struct sockaddr_un) - (
1035 (void *)sockaddr.sun_path - (void *)&sockaddr
1036 ) - 1; /* one byte for termination */
1037 int sock;
1038 path = luaL_checkstring(L, 1);
1039 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1040 strcpy(sockaddr.sun_path, path);
1041 if (stat(path, &sb) == 0) {
1042 if (S_ISSOCK(sb.st_mode)) unlink(path);
1044 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1045 listener->fd = -1;
1046 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1047 sock = socket(
1048 PF_LOCAL,
1049 SOCK_STREAM | SOCK_CLOEXEC,
1051 );
1052 if (sock < 0) {
1053 moonbr_io_errmsg();
1054 lua_pushnil(L);
1055 lua_pushstring(L, errmsg);
1056 return 2;
1058 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1059 moonbr_io_errmsg();
1060 close(sock);
1061 lua_pushnil(L);
1062 lua_pushstring(L, errmsg);
1063 return 2;
1065 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1066 moonbr_io_errmsg();
1067 close(sock);
1068 lua_pushnil(L);
1069 lua_pushstring(L, errmsg);
1070 return 2;
1072 listener->fd = sock;
1073 listener->addrfam = AF_LOCAL;
1074 listener->nonblocking = -1;
1075 return 1;
1078 static int moonbr_io_tcplisten(lua_State *L) {
1079 moonbr_io_listener_t *listener;
1080 const char *host, *port;
1081 struct addrinfo hints = { 0, };
1082 struct addrinfo *res, *addrinfo;
1083 int errcode;
1084 int sock;
1085 host = luaL_optstring(L, 1, NULL);
1086 port = luaL_checkstring(L, 2);
1087 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1088 listener->fd = -1;
1089 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1090 hints.ai_family = AF_UNSPEC;
1091 hints.ai_socktype = SOCK_STREAM;
1092 hints.ai_protocol = IPPROTO_TCP;
1093 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1094 errcode = getaddrinfo(host, port, &hints, &res);
1095 if (errcode) {
1096 freeaddrinfo(res);
1097 if (errcode == EAI_SYSTEM) {
1098 moonbr_io_errmsg();
1099 lua_pushnil(L);
1100 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1101 } else {
1102 lua_pushnil(L);
1103 lua_pushstring(L, gai_strerror(errcode));
1105 return 2;
1107 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1108 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1110 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1111 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1113 addrinfo = res;
1114 moonbr_io_tcpconnect_found:
1115 listener->addrfam = addrinfo->ai_family;
1116 sock = socket(
1117 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1118 addrinfo->ai_socktype | SOCK_CLOEXEC,
1119 addrinfo->ai_protocol
1120 );
1121 if (sock < 0) {
1122 moonbr_io_errmsg();
1123 freeaddrinfo(res);
1124 lua_pushnil(L);
1125 lua_pushstring(L, errmsg);
1126 return 2;
1129 static const int reuseval = 1;
1130 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1131 moonbr_io_errmsg();
1132 freeaddrinfo(res);
1133 close(sock);
1134 lua_pushnil(L);
1135 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1136 return 2;
1139 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1140 moonbr_io_errmsg();
1141 freeaddrinfo(res);
1142 close(sock);
1143 lua_pushnil(L);
1144 lua_pushstring(L, errmsg);
1145 return 2;
1147 freeaddrinfo(res);
1148 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1149 moonbr_io_errmsg();
1150 close(sock);
1151 lua_pushnil(L);
1152 lua_pushstring(L, errmsg);
1153 return 2;
1155 listener->fd = sock;
1156 listener->nonblocking = -1;
1157 return 1;
1160 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1161 moonbr_io_listener_t *listener;
1162 int fd;
1163 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1164 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1165 if (listener->nonblocking != nonblocking) {
1166 int flags;
1167 flags = fcntl(listener->fd, F_GETFL, 0);
1168 if (flags == -1) {
1169 moonbr_io_errmsg();
1170 close(listener->fd);
1171 listener->fd = -1;
1172 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1174 if (nonblocking) flags |= O_NONBLOCK;
1175 else flags &= ~O_NONBLOCK;
1176 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1177 moonbr_io_errmsg();
1178 close(listener->fd);
1179 listener->fd = -1;
1180 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1182 listener->nonblocking = nonblocking;
1184 while (1) {
1185 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1186 if (fd < 0) {
1187 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1188 lua_pushboolean(L, 0);
1189 lua_pushliteral(L, "No incoming connection pending");
1190 return 2;
1191 } else if (errno != EINTR) {
1192 moonbr_io_errmsg();
1193 lua_pushnil(L);
1194 lua_pushstring(L, errmsg);
1195 return 2;
1197 } else {
1198 moonbr_io_pushhandle(L, fd);
1199 return 1;
1204 static int moonbr_io_accept(lua_State *L) {
1205 return moonbr_io_accept_impl(L, 0);
1208 static int moonbr_io_accept_nb(lua_State *L) {
1209 return moonbr_io_accept_impl(L, 1);
1212 static int moonbr_io_unlisten(lua_State *L) {
1213 moonbr_io_listener_t *listener;
1214 struct sockaddr_un addr;
1215 socklen_t addrlen;
1216 struct stat sb;
1217 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1218 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1219 addrlen = sizeof(addr);
1220 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1221 if (close(listener->fd)) {
1222 moonbr_io_errmsg();
1223 listener->fd = -1;
1224 if (addrlen && addrlen <= sizeof(addr)) {
1225 if (stat(addr.sun_path, &sb) == 0) {
1226 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1229 lua_pushnil(L);
1230 lua_pushstring(L, errmsg);
1231 return 2;
1233 listener->fd = -1;
1234 if (addrlen && addrlen <= sizeof(addr)) {
1235 if (stat(addr.sun_path, &sb) == 0) {
1236 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1239 lua_pushboolean(L, 1);
1240 return 1;
1243 static int moonbr_io_listenergc(lua_State *L) {
1244 moonbr_io_listener_t *listener;
1245 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1246 if (listener->fd >= 0) close(listener->fd);
1247 listener->fd = -1;
1248 return 0;
1251 static int moonbr_io_exec(lua_State *L) {
1252 char **argv;
1253 int i, argc;
1254 int sockin[2], sockout[2], sockerr[2];
1255 volatile int errorcond = 0;
1256 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN];
1257 moonbr_io_child_t *child;
1258 argc = lua_gettop(L);
1259 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
1260 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
1261 argv[argc] = NULL;
1262 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
1263 child->pid = 0;
1264 lua_newtable(L);
1265 lua_setuservalue(L, -2);
1266 luaL_getmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
1267 lua_setmetatable(L, -2);
1268 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
1269 moonbr_io_errmsg();
1270 lua_pushnil(L);
1271 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1272 return 2;
1274 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
1275 moonbr_io_errmsg();
1276 close(sockin[0]);
1277 close(sockin[1]);
1278 lua_pushnil(L);
1279 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1280 return 2;
1282 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
1283 moonbr_io_errmsg();
1284 close(sockin[0]);
1285 close(sockin[1]);
1286 close(sockout[0]);
1287 close(sockout[1]);
1288 lua_pushnil(L);
1289 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
1290 return 2;
1292 child->pid = vfork();
1293 if (child->pid == -1) {
1294 moonbr_io_errmsg();
1295 close(sockin[0]);
1296 close(sockin[1]);
1297 close(sockout[0]);
1298 close(sockout[1]);
1299 close(sockerr[0]);
1300 close(sockerr[1]);
1301 lua_pushnil(L);
1302 lua_pushfstring(L, "Could not fork: %s", errmsg);
1303 return 2;
1305 if (!child->pid) {
1306 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
1307 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
1308 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
1309 closefrom(4);
1310 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1311 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1312 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
1313 if (execvp(argv[0], argv)) {
1314 errorcond = 2;
1315 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1316 _exit(0);
1318 moonbr_io_exec_error1:
1319 errorcond = 1;
1320 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
1321 _exit(0);
1323 close(sockin[1]);
1324 close(sockout[1]);
1325 close(sockerr[1]);
1326 if (errorcond) {
1327 int status;
1328 close(sockin[0]);
1329 close(sockout[0]);
1330 close(sockerr[0]);
1331 while (waitpid(child->pid, &status, 0) == -1) {
1332 if (errno != EINTR) {
1333 moonbr_io_errmsg();
1334 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
1337 child->pid = 0;
1338 lua_pushnil(L);
1339 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
1340 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
1341 return 2;
1343 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1344 lua_pushlightuserdata(L, &sockin[0]);
1345 if (lua_pcall(L, 1, 1, 0)) {
1346 if (sockin[0] != -1) close(sockin[0]);
1347 close(sockout[0]);
1348 close(sockerr[0]);
1349 goto moonbr_io_exec_error2;
1351 lua_setfield(L, -2, "stdin");
1352 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1353 lua_pushlightuserdata(L, &sockout[0]);
1354 if (lua_pcall(L, 1, 1, 0)) {
1355 if (sockout[0] != -1) close(sockout[0]);
1356 close(sockerr[0]);
1357 goto moonbr_io_exec_error2;
1359 lua_setfield(L, -2, "stdout");
1360 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
1361 lua_pushlightuserdata(L, &sockerr[0]);
1362 if (lua_pcall(L, 1, 1, 0)) {
1363 if (sockerr[0] != -1) close(sockerr[0]);
1364 goto moonbr_io_exec_error2;
1366 lua_setfield(L, -2, "stderr");
1367 return 1;
1368 moonbr_io_exec_error2:
1370 int status;
1371 while (waitpid(child->pid, &status, 0) == -1) {
1372 if (errno != EINTR) {
1373 moonbr_io_errmsg();
1374 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
1378 child->pid = 0;
1379 return lua_error(L);
1382 static int moonbr_io_childindex(lua_State *L) {
1383 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1384 luaL_checkany(L, 2);
1385 lua_getuservalue(L, 1);
1386 lua_pushvalue(L, 2);
1387 lua_gettable(L, -2);
1388 if (lua_isnil(L, -1)) {
1389 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
1390 lua_pushvalue(L, 2);
1391 lua_gettable(L, -2);
1393 return 1;
1396 static int moonbr_io_childnewindex(lua_State *L) {
1397 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1398 luaL_checkany(L, 2);
1399 luaL_checkany(L, 3);
1400 lua_getuservalue(L, 1);
1401 lua_pushvalue(L, 2);
1402 lua_pushvalue(L, 3);
1403 lua_settable(L, -3);
1404 return 0;
1407 static int moonbr_io_childgc(lua_State *L) {
1408 moonbr_io_child_t *child;
1409 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1410 if (child->pid) {
1411 int status;
1412 if (kill(child->pid, SIGKILL)) {
1413 moonbr_io_errmsg();
1414 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
1416 while (waitpid(child->pid, &status, 0) == -1) {
1417 if (errno != EINTR) {
1418 moonbr_io_errmsg();
1419 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
1423 return 0;
1426 static int moonbr_io_kill(lua_State *L) {
1427 moonbr_io_child_t *child;
1428 int sig;
1429 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1430 sig = luaL_optinteger(L, 2, SIGTERM);
1431 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
1432 if (kill(child->pid, sig)) {
1433 moonbr_io_errmsg();
1434 luaL_error(L, "Error in kill call: %s", errmsg);
1436 lua_settop(L, 1);
1437 return 1;
1440 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
1441 moonbr_io_child_t *child;
1442 pid_t waitedpid;
1443 int status;
1444 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
1445 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
1446 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
1447 if (errno != EINTR) {
1448 moonbr_io_errmsg();
1449 luaL_error(L, "Error in waitpid call: %s", errmsg);
1452 if (!waitedpid) {
1453 lua_pushnil(L);
1454 } else {
1455 child->pid = 0;
1456 if (WIFEXITED(status)) {
1457 lua_pushinteger(L, WEXITSTATUS(status));
1458 } else if (WIFSIGNALED(status)) {
1459 lua_pushinteger(L, -WTERMSIG(status));
1460 } else {
1461 luaL_error(L, "Unexpected status value returned by waitpid call");
1464 return 1;
1467 static int moonbr_io_wait(lua_State *L) {
1468 return moonbr_io_wait_impl(L, 0);
1471 static int moonbr_io_wait_nb(lua_State *L) {
1472 return moonbr_io_wait_impl(L, 1);
1475 #if LUA_VERSION_NUM >= 503
1476 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
1477 #else
1478 static int moonbr_io_wait_cont(lua_State *L) {
1479 #endif
1480 #if !(LUA_VERSION_NUM >= 503)
1481 int ctx = 0;
1482 lua_getctx(L, &ctx);
1483 #endif
1484 while (1) {
1485 lua_pushcfunction(L, moonbr_io_wait_nb);
1486 lua_pushvalue(L, 1);
1487 lua_call(L, 1, 1);
1488 if (!lua_isnil(L, -1)) break;
1489 lua_pushvalue(L, 2);
1490 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
1492 return 1;
1495 static int moonbr_io_wait_call(lua_State *L) {
1496 lua_settop(L, 2);
1497 #if LUA_VERSION_NUM >= 503
1498 return moonbr_io_wait_cont(L, 0, 0);
1499 #else
1500 return moonbr_io_wait_cont(L);
1501 #endif
1504 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
1506 static int moonbr_io_poll(lua_State *L) {
1507 moonbr_io_handle_t *handle;
1508 moonbr_io_listener_t *listener;
1509 int fd, isnum;
1510 int nfds = 0;
1511 fd_set readfds, writefds, exceptfds;
1512 struct timeval timeout = {0, };
1513 int status;
1514 FD_ZERO(&readfds);
1515 FD_ZERO(&writefds);
1516 FD_ZERO(&exceptfds);
1517 if (!lua_isnoneornil(L, 1)) {
1518 luaL_checktype(L, 1, LUA_TTABLE);
1519 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1520 if (lua_toboolean(L, -1)) {
1521 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1522 if (handle) {
1523 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1524 fd = handle->fd;
1525 if (
1526 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1527 handle->readbufin != handle->readbufout /* data pending in buffer */
1528 ) {
1529 lua_pushboolean(L, 1);
1530 return 1;
1532 } else {
1533 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1534 if (listener) {
1535 fd = listener->fd;
1536 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1537 } else {
1538 fd = lua_tointegerx(L, -2, &isnum);
1539 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1542 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1543 FD_SET(fd, &readfds);
1544 if (fd+1 > nfds) nfds = fd+1;
1548 if (!lua_isnoneornil(L, 2)) {
1549 luaL_checktype(L, 2, LUA_TTABLE);
1550 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1551 if (lua_toboolean(L, -1)) {
1552 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1553 if (handle) {
1554 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1555 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1556 fd = handle->fd;
1557 } else {
1558 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1559 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1560 fd = lua_tointegerx(L, -2, &isnum);
1561 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1563 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1564 FD_SET(fd, &writefds);
1565 if (fd+1 > nfds) nfds = fd+1;
1569 if (!lua_isnoneornil(L, 3)) {
1570 lua_Number n;
1571 n = lua_tonumberx(L, 3, &isnum);
1572 if (isnum && n<0) {
1573 lua_pushboolean(L, 0);
1574 lua_pushliteral(L, "Negative timeout");
1575 return 2;
1576 } else if (isnum && n>=0 && n<100000000) {
1577 timeout.tv_sec = n;
1578 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1579 } else {
1580 luaL_argcheck(L, 0, 3, "not a valid timeout");
1582 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1583 } else {
1584 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1586 if (status == -1) {
1587 if (errno == EINTR) {
1588 lua_pushnil(L);
1589 lua_pushliteral(L, "Signal received while polling file descriptors");
1590 return 2;
1591 } else {
1592 moonbr_io_errmsg();
1593 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1595 } else if (status == 0) {
1596 lua_pushboolean(L, 0);
1597 lua_pushliteral(L, "Timeout while polling file descriptors");
1598 return 2;
1599 } else {
1600 lua_pushboolean(L, 1);
1601 return 1;
1605 static int moonbr_io_timeref(lua_State *L) {
1606 lua_Number sub;
1607 struct timespec tp;
1608 sub = luaL_optnumber(L, 1, 0);
1609 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1610 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1612 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1613 return 1;
1616 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1617 {"read", moonbr_io_read},
1618 {"read_nb", moonbr_io_read_nb},
1619 {"read_call", moonbr_io_read_call},
1620 {"read_yield", moonbr_io_read_yield},
1621 {"drain", moonbr_io_drain},
1622 {"drain_nb", moonbr_io_drain_nb},
1623 {"drain_call", moonbr_io_drain_call},
1624 {"drain_yield", moonbr_io_drain_yield},
1625 {"write", moonbr_io_write},
1626 {"write_nb", moonbr_io_write_nb},
1627 {"write_call", moonbr_io_write_call},
1628 {"write_yield", moonbr_io_write_yield},
1629 {"flush", moonbr_io_flush},
1630 {"flush_nb", moonbr_io_flush_nb},
1631 {"flush_call", moonbr_io_flush_call},
1632 {"flush_yield", moonbr_io_flush_yield},
1633 {"finish", moonbr_io_finish},
1634 {"close", moonbr_io_close},
1635 {"reset", moonbr_io_reset},
1636 {NULL, NULL}
1637 };
1639 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1640 {"__index", moonbr_io_handleindex},
1641 {"__newindex", moonbr_io_handlenewindex},
1642 {"__gc", moonbr_io_handlegc},
1643 {NULL, NULL}
1644 };
1646 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1647 {"accept", moonbr_io_accept},
1648 {"accept_nb", moonbr_io_accept_nb},
1649 {"close", moonbr_io_unlisten},
1650 {NULL, NULL}
1651 };
1653 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1654 {"__gc", moonbr_io_listenergc},
1655 {NULL, NULL}
1656 };
1658 static const struct luaL_Reg moonbr_io_child_methods[] = {
1659 {"kill", moonbr_io_kill},
1660 {"wait", moonbr_io_wait},
1661 {"wait_nb", moonbr_io_wait_nb},
1662 {"wait_call", moonbr_io_wait_call},
1663 {"wait_yield", moonbr_io_wait_yield},
1664 {NULL, NULL}
1665 };
1667 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
1668 {"__index", moonbr_io_childindex},
1669 {"__newindex", moonbr_io_childnewindex},
1670 {"__gc", moonbr_io_childgc},
1671 {NULL, NULL}
1672 };
1674 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1675 {"localconnect", moonbr_io_localconnect},
1676 {"localconnect_nb", moonbr_io_localconnect_nb},
1677 {"tcpconnect", moonbr_io_tcpconnect},
1678 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1679 {"locallisten", moonbr_io_locallisten},
1680 {"tcplisten", moonbr_io_tcplisten},
1681 {"exec", moonbr_io_exec},
1682 {"poll", moonbr_io_poll},
1683 {"timeref", moonbr_io_timeref},
1684 {NULL, NULL}
1685 };
1687 int luaopen_moonbridge_io(lua_State *L) {
1689 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1691 lua_newtable(L); // module
1693 lua_newtable(L); // public metatable
1694 lua_newtable(L); // handle methods
1695 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1696 lua_pushvalue(L, -1);
1697 lua_setfield(L, -4, "handle_pt");
1698 lua_setfield(L, -2, "__index");
1699 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1701 lua_newtable(L); // handle metatable
1702 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1703 lua_pushvalue(L, -1);
1704 lua_setfield(L, -3, "handle_mt");
1705 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1707 lua_newtable(L); // listener metatable
1708 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1709 lua_newtable(L); // listener methods
1710 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1711 lua_pushvalue(L, -1);
1712 lua_setfield(L, -4, "listener_pt");
1713 lua_setfield(L, -2, "__index");
1714 lua_pushvalue(L, -1);
1715 lua_setfield(L, -3, "listener_mt");
1716 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1718 lua_newtable(L); // child methods
1719 luaL_setfuncs(L, moonbr_io_child_methods, 0);
1720 lua_pushvalue(L, -1);
1721 lua_setfield(L, -3, "child_pt");
1722 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
1723 lua_newtable(L); // child metatable
1724 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
1725 lua_pushvalue(L, -1);
1726 lua_setfield(L, -3, "child_mt");
1727 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
1729 moonbr_io_pushhandle(L, 0);
1730 lua_setfield(L, -2, "stdin");
1731 moonbr_io_pushhandle(L, 1);
1732 lua_setfield(L, -2, "stdout");
1733 moonbr_io_pushhandle(L, 2);
1734 lua_setfield(L, -2, "stderr");
1736 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1737 return 1;

Impressum / About Us