moonbridge

view moonbridge_io.c @ 211:a3d569d3e85d

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

Impressum / About Us