moonbridge

view moonbridge_io.c @ 208:77dc29ce7948

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

Impressum / About Us