moonbridge

view moonbridge_io.c @ 150:b0e2fbf9d5a8

Fixed trival mistake in reference.txt
author jbe
date Fri May 08 03:22:15 2015 +0200 (2015-05-08)
parents c820130f55d7
children 2a5bd37034c6
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>
22 #include <lua.h>
23 #include <lauxlib.h>
24 #include <lualib.h>
26 #include <assert.h>
28 #define MOONBR_IO_MAXSTRERRORLEN 80
29 #define MOONBR_IO_READBUFLEN 4096
30 #define MOONBR_IO_WRITEBUFLEN 4096
32 #define MOONBR_IO_LISTEN_BACKLOG 1024
34 #define moonbr_io_errmsg() \
35 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
36 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
38 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
39 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
40 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
42 char moonbr_io_block_udata = 0;
43 char moonbr_io_multiblock_udata = 0;
45 typedef struct {
46 int fd;
47 int issock;
48 sa_family_t addrfam;
49 int finished;
50 int closed;
51 int nonblocking;
52 int nopush;
53 int readerr;
54 int readbufin;
55 int readbufout;
56 int writeerr;
57 size_t writeleft;
58 size_t flushedleft;
59 #if LUA_VERSION_NUM >= 503
60 lua_Integer writeqin;
61 lua_Integer writeqout;
62 #else
63 int writeqin;
64 int writeqout;
65 #endif
66 size_t writeqoff;
67 int writebufin;
68 int writebufout;
69 char readbuf[MOONBR_IO_READBUFLEN];
70 char writebuf[MOONBR_IO_WRITEBUFLEN];
71 } moonbr_io_handle_t;
73 typedef struct {
74 int fd;
75 sa_family_t addrfam;
76 int nonblocking;
77 } moonbr_io_listener_t;
79 static int moonbr_io_yield(lua_State *L) {
80 return lua_yield(L, lua_gettop(L));
81 }
83 #if LUA_VERSION_NUM >= 503
84 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
85 #else
86 static int moonbr_io_cont_returnall(lua_State *L) {
87 #endif
88 return lua_gettop(L);
89 }
91 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
92 static int yieldfunc(lua_State *L) { \
93 int args; \
94 lua_pushcfunction(L, callfunc); \
95 lua_insert(L, 1); \
96 args = lua_gettop(L); \
97 lua_pushcfunction(L, moonbr_io_yield); \
98 lua_insert(L, 3); \
99 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
100 return lua_gettop(L); \
101 }
103 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
104 int flags;
105 if (handle->nonblocking == nonblocking) return;
106 flags = fcntl(handle->fd, F_GETFL, 0);
107 if (flags == -1) {
108 moonbr_io_errmsg();
109 close(handle->fd);
110 handle->fd = -1;
111 handle->closed = 1;
112 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
113 }
114 if (nonblocking) flags |= O_NONBLOCK;
115 else flags &= ~O_NONBLOCK;
116 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
117 moonbr_io_errmsg();
118 close(handle->fd);
119 handle->fd = -1;
120 handle->closed = 1;
121 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
122 }
123 handle->nonblocking = nonblocking;
124 }
126 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
127 struct linger lingerval = { 0, };
128 if (!handle->issock) return;
129 if (timeout >= 0) {
130 lingerval.l_onoff = 1;
131 lingerval.l_linger = timeout;
132 }
133 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
134 moonbr_io_errmsg();
135 close(handle->fd);
136 handle->fd = -1;
137 handle->closed = 1;
138 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
139 }
140 }
142 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
143 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
144 if (
145 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
146 handle->nopush == nopush
147 ) return;
148 #if defined(TCP_NOPUSH)
149 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
150 #elif defined(TCP_CORK)
151 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
152 #endif
153 moonbr_io_errmsg();
154 close(handle->fd);
155 handle->fd = -1;
156 handle->closed = 1;
157 #if defined(TCP_NOPUSH)
158 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
159 #elif defined(TCP_CORK)
160 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
161 #endif
162 }
163 handle->nopush = nopush;
164 #else
165 #warning Neither TCP_NOPUSH nor TCP_CORK is available
166 #endif
167 }
169 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
170 moonbr_io_handle_t *handle;
171 lua_Integer maxread;
172 const char *terminatorstr;
173 size_t terminatorlen;
174 char terminator = 0; /* initialize to avoid compiler warning */
175 luaL_Buffer luabuf;
176 size_t luabufcnt = 0;
177 int remaining;
178 char *terminatorpos;
179 ssize_t bytesread;
180 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
181 maxread = luaL_optinteger(L, 2, 0);
182 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
183 if (terminatorlen) {
184 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
185 terminator = terminatorstr[0];
186 }
187 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
188 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
189 if (handle->readerr) {
190 lua_pushnil(L);
191 lua_pushliteral(L, "Previous read error");
192 return 2;
193 }
194 if (handle->fd < 0) {
195 /* fake EOF to simulate shutdown */
196 if (!drain) lua_pushliteral(L, "");
197 else lua_pushinteger(L, 0);
198 lua_pushliteral(L, "eof");
199 return 2;
200 }
201 handle->readerr = 1;
202 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
203 if (!drain) luaL_buffinit(L, &luabuf);
204 while (1) {
205 remaining = -1;
206 terminatorpos = NULL;
207 if (
208 maxread > 0 &&
209 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
210 ) {
211 remaining = (size_t)maxread - luabufcnt;
212 terminatorpos = memchr(
213 handle->readbuf + handle->readbufout,
214 terminator,
215 remaining
216 );
217 } else if (terminatorlen) {
218 terminatorpos = memchr(
219 handle->readbuf + handle->readbufout,
220 terminator,
221 handle->readbufin - handle->readbufout
222 );
223 }
224 if (terminatorpos) remaining = 1 + (
225 terminatorpos - (handle->readbuf + handle->readbufout)
226 );
227 if (remaining >= 0) {
228 if (!drain) {
229 luaL_addlstring(
230 &luabuf,
231 handle->readbuf + handle->readbufout,
232 remaining
233 );
234 luaL_pushresult(&luabuf);
235 } else {
236 lua_pushinteger(L, luabufcnt + remaining);
237 }
238 if (terminatorpos) lua_pushliteral(L, "term");
239 else lua_pushliteral(L, "maxlen");
240 handle->readbufout += remaining;
241 if (handle->readbufout == handle->readbufin) {
242 handle->readbufin = 0;
243 handle->readbufout = 0;
244 }
245 handle->readerr = 0;
246 return 2;
247 }
248 if (!drain) luaL_addlstring(
249 &luabuf,
250 handle->readbuf + handle->readbufout,
251 handle->readbufin - handle->readbufout
252 );
253 luabufcnt += handle->readbufin - handle->readbufout;
254 handle->readbufout = 0;
255 do {
256 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
257 } while (bytesread < 0 && (errno == EINTR));
258 if (
259 bytesread == 0 || (
260 nonblocking &&
261 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
262 )
263 ) {
264 handle->readbufin = 0;
265 if (!drain) luaL_pushresult(&luabuf);
266 else lua_pushinteger(L, luabufcnt);
267 if (bytesread == 0) lua_pushliteral(L, "eof");
268 else lua_pushliteral(L, "block");
269 handle->readerr = 0;
270 return 2;
271 }
272 if (bytesread < 0) {
273 moonbr_io_errmsg();
274 lua_pushnil(L);
275 lua_pushstring(L, errmsg);
276 return 2;
277 }
278 handle->readbufin = bytesread;
279 }
280 }
282 static int moonbr_io_read(lua_State *L) {
283 return moonbr_io_read_impl(L, 0, 0);
284 }
286 static int moonbr_io_read_nb(lua_State *L) {
287 return moonbr_io_read_impl(L, 1, 0);
288 }
290 static int moonbr_io_drain(lua_State *L) {
291 return moonbr_io_read_impl(L, 0, 1);
292 }
294 static int moonbr_io_drain_nb(lua_State *L) {
295 return moonbr_io_read_impl(L, 1, 1);
296 }
298 #if LUA_VERSION_NUM >= 503
299 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
300 #else
301 static int moonbr_io_read_cont(lua_State *L) {
302 #endif
303 lua_Integer remaining;
304 size_t len;
305 #if !(LUA_VERSION_NUM >= 503)
306 int ctx = 0;
307 lua_getctx(L, &ctx);
308 #endif
309 remaining = lua_tointeger(L, 3);
310 while (1) {
311 lua_pushcfunction(L, moonbr_io_read_nb);
312 lua_pushvalue(L, 1);
313 lua_pushvalue(L, 3);
314 lua_pushvalue(L, 4);
315 lua_call(L, 3, 2);
316 if (lua_isnil(L, -2)) return 2;
317 lua_insert(L, -2);
318 len = lua_rawlen(L, -1);
319 if (ctx == 0) {
320 lua_replace(L, 5);
321 ctx = 1;
322 } else if (ctx == 1) {
323 lua_pushvalue(L, 5);
324 lua_newtable(L);
325 lua_replace(L, 5);
326 lua_rawseti(L, 5, 2);
327 lua_rawseti(L, 5, 1);
328 ctx = 2;
329 } else {
330 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
331 }
332 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
333 lua_pop(L, 1);
334 if (remaining >= 0 && len) {
335 remaining -= len;
336 lua_pushinteger(L, remaining);
337 lua_replace(L, 3);
338 }
339 lua_pushvalue(L, 2);
340 lua_pushlightuserdata(L, &moonbr_io_block_udata);
341 lua_pushvalue(L, 1);
342 lua_pushliteral(L, "r");
343 lua_callk(L, 3, 0, ctx, moonbr_io_read_cont);
344 }
345 if (ctx == 1) {
346 lua_pushvalue(L, 5);
347 } else {
348 luaL_Buffer buf;
349 lua_Integer i, chunkcount;
350 chunkcount = lua_rawlen(L, 5);
351 luaL_buffinit(L, &buf);
352 for (i=1; i<=chunkcount && i>0; i++) {
353 lua_rawgeti(L, 5, i);
354 luaL_addvalue(&buf);
355 }
356 luaL_pushresult(&buf);
357 }
358 lua_pushvalue(L, -2);
359 return 2;
360 }
362 static int moonbr_io_read_call(lua_State *L) {
363 lua_settop(L, 4);
364 lua_pushnil(L);
365 #if LUA_VERSION_NUM >= 503
366 return moonbr_io_read_cont(L, 0, 0);
367 #else
368 return moonbr_io_read_cont(L);
369 #endif
370 }
372 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
374 #if LUA_VERSION_NUM >= 503
375 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
376 #else
377 static int moonbr_io_drain_cont(lua_State *L) {
378 #endif
379 lua_Integer remaining, len;
380 size_t totallen = 0;
381 #if !(LUA_VERSION_NUM >= 503)
382 int ctx = 0;
383 lua_getctx(L, &ctx);
384 #endif
385 remaining = lua_tointeger(L, 3);
386 while (1) {
387 lua_pushcfunction(L, moonbr_io_drain_nb);
388 lua_pushvalue(L, 1);
389 lua_pushvalue(L, 3);
390 lua_pushvalue(L, 4);
391 lua_call(L, 3, 2);
392 if (lua_isnil(L, -2)) return 2;
393 lua_insert(L, -2);
394 len = lua_tointeger(L, -1);
395 lua_pop(L, 1);
396 totallen += len;
397 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
398 lua_pop(L, 1);
399 if (remaining >= 0 && len) {
400 remaining -= len;
401 lua_pushinteger(L, remaining);
402 lua_replace(L, 3);
403 }
404 lua_pushvalue(L, 2);
405 lua_pushlightuserdata(L, &moonbr_io_block_udata);
406 lua_pushvalue(L, 1);
407 lua_pushliteral(L, "r");
408 lua_callk(L, 3, 0, ctx, moonbr_io_drain_cont);
409 }
410 lua_pushinteger(L, totallen);
411 lua_pushvalue(L, -2);
412 return 2;
413 }
415 static int moonbr_io_drain_call(lua_State *L) {
416 #if LUA_VERSION_NUM >= 503
417 return moonbr_io_drain_cont(L, 0, 0);
418 #else
419 return moonbr_io_drain_cont(L);
420 #endif
421 }
423 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
425 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
426 moonbr_io_handle_t *handle;
427 int i, top;
428 const char *str;
429 size_t strlen;
430 ssize_t written;
431 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
432 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
433 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
434 if (handle->writeerr) {
435 lua_pushnil(L);
436 lua_pushliteral(L, "Previous write error");
437 return 2;
438 }
439 handle->writeerr = 1;
440 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
441 top = lua_gettop(L);
442 lua_getuservalue(L, 1);
443 lua_getfield(L, -1, "writequeue");
444 for (i=2; i<=top; i++) {
445 luaL_checklstring(L, i, &strlen);
446 lua_pushvalue(L, i);
447 lua_rawseti(L, -2, handle->writeqin++);
448 handle->writeleft += strlen;
449 }
450 if (flush) handle->flushedleft = handle->writeleft;
451 while (handle->writeqout != handle->writeqin) {
452 lua_rawgeti(L, -1, handle->writeqout);
453 str = lua_tolstring(L, -1, &strlen);
454 while (handle->writeqoff < strlen) {
455 if (
456 strlen - handle->writeqoff <
457 MOONBR_IO_WRITEBUFLEN - handle->writebufin
458 ) {
459 memcpy(
460 handle->writebuf + handle->writebufin,
461 str + handle->writeqoff,
462 strlen - handle->writeqoff
463 );
464 handle->writebufin += strlen - handle->writeqoff;
465 break;
466 } else {
467 memcpy(
468 handle->writebuf + handle->writebufin,
469 str + handle->writeqoff,
470 MOONBR_IO_WRITEBUFLEN - handle->writebufin
471 );
472 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
473 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
474 moonbr_io_handle_set_nopush(L, handle, 1);
475 written = write(
476 handle->fd,
477 handle->writebuf + handle->writebufout,
478 MOONBR_IO_WRITEBUFLEN - handle->writebufout
479 );
480 if (written < 0) {
481 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
482 goto moonbr_io_write_impl_block;
483 } else if (errno != EINTR) {
484 moonbr_io_errmsg();
485 lua_pushnil(L);
486 lua_pushstring(L, errmsg);
487 return 2;
488 }
489 } else {
490 handle->writebufout += written;
491 handle->writeleft -= written;
492 if (handle->flushedleft) {
493 if (written >= handle->flushedleft) {
494 handle->flushedleft = 0;
495 moonbr_io_handle_set_nopush(L, handle, 0);
496 } else {
497 handle->flushedleft -= written;
498 }
499 }
500 }
501 }
502 handle->writebufin = 0;
503 handle->writebufout = 0;
504 }
505 }
506 handle->writeqoff = 0;
507 lua_pop(L, 1);
508 lua_pushnil(L);
509 lua_rawseti(L, -2, handle->writeqout++);
510 }
511 while (handle->flushedleft) {
512 moonbr_io_handle_set_nopush(L, handle, 1);
513 written = write(
514 handle->fd,
515 handle->writebuf + handle->writebufout,
516 handle->writebufin - handle->writebufout
517 );
518 if (written < 0) {
519 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
520 goto moonbr_io_write_impl_block;
521 } else if (errno != EINTR) {
522 moonbr_io_errmsg();
523 lua_pushnil(L);
524 lua_pushstring(L, errmsg);
525 return 2;
526 }
527 } else {
528 handle->writebufout += written;
529 handle->writeleft -= written;
530 if (handle->flushedleft) {
531 if (written >= handle->flushedleft) {
532 handle->flushedleft = 0;
533 moonbr_io_handle_set_nopush(L, handle, 0);
534 } else {
535 handle->flushedleft -= written;
536 }
537 }
538 }
539 }
540 if (handle->writebufout == handle->writebufin) {
541 handle->writebufin = 0;
542 handle->writebufout = 0;
543 }
544 if (nonblocking) lua_pushinteger(L, 0);
545 else lua_pushvalue(L, 1);
546 handle->writeerr = 0;
547 return 1;
548 moonbr_io_write_impl_block:
549 lua_pushinteger(L, handle->writeleft);
550 handle->writeerr = 0;
551 return 1;
552 }
554 static int moonbr_io_write(lua_State *L) {
555 return moonbr_io_write_impl(L, 0, 0);
556 }
558 static int moonbr_io_write_nb(lua_State *L) {
559 return moonbr_io_write_impl(L, 1, 0);
560 }
562 static int moonbr_io_flush(lua_State *L) {
563 return moonbr_io_write_impl(L, 0, 1);
564 }
566 static int moonbr_io_flush_nb(lua_State *L) {
567 return moonbr_io_write_impl(L, 1, 1);
568 }
570 #if LUA_VERSION_NUM >= 503
571 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
572 #else
573 static int moonbr_io_write_cont(lua_State *L) {
574 #endif
575 while (1) {
576 lua_pushcfunction(L, moonbr_io_write_nb);
577 lua_pushvalue(L, 1);
578 lua_call(L, 1, 2);
579 if (lua_isnil(L, -2)) return 2;
580 if (!lua_tointeger(L, -2)) {
581 lua_pushvalue(L, 1);
582 return 1;
583 }
584 lua_pop(L, 2);
585 lua_pushvalue(L, 2);
586 lua_pushlightuserdata(L, &moonbr_io_block_udata);
587 lua_pushvalue(L, 1);
588 lua_pushliteral(L, "w");
589 lua_callk(L, 3, 0, 0, moonbr_io_write_cont);
590 }
591 }
593 static int moonbr_io_write_call(lua_State *L) {
594 lua_pushcfunction(L, moonbr_io_write_nb);
595 lua_insert(L, 3);
596 lua_pushvalue(L, 1);
597 lua_insert(L, 4);
598 lua_call(L, lua_gettop(L) - 3, 2);
599 if (lua_isnil(L, -2)) return 2;
600 if (!lua_tointeger(L, -2)) {
601 lua_pushvalue(L, 1);
602 return 1;
603 }
604 #if LUA_VERSION_NUM >= 503
605 return moonbr_io_write_cont(L, 0, 0);
606 #else
607 return moonbr_io_write_cont(L);
608 #endif
609 }
611 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
613 static int moonbr_io_flush_call(lua_State *L) {
614 lua_pushcfunction(L, moonbr_io_flush_nb);
615 lua_insert(L, 3);
616 lua_pushvalue(L, 1);
617 lua_insert(L, 4);
618 lua_call(L, lua_gettop(L) - 3, 2);
619 if (lua_isnil(L, -2)) return 2;
620 if (!lua_tointeger(L, -2)) {
621 lua_pushvalue(L, 1);
622 return 1;
623 }
624 #if LUA_VERSION_NUM >= 503
625 return moonbr_io_write_cont(L, 0, 0);
626 #else
627 return moonbr_io_write_cont(L);
628 #endif
629 }
631 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
633 static int moonbr_io_finish(lua_State *L) {
634 moonbr_io_handle_t *handle;
635 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
636 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
637 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
638 if (handle->writeleft) {
639 lua_pushcfunction(L, moonbr_io_flush);
640 lua_pushvalue(L, 1);
641 if (lua_pcall(L, 1, 2, 0)) {
642 handle->finished = 1;
643 lua_error(L);
644 }
645 if (!lua_toboolean(L, -2)) {
646 handle->finished = 1;
647 return 2;
648 }
649 }
650 handle->finished = 1;
651 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
652 if (shutdown(handle->fd, SHUT_WR)) {
653 moonbr_io_errmsg();
654 lua_pushnil(L);
655 lua_pushstring(L, errmsg);
656 return 2;
657 }
658 } else {
659 if (close(handle->fd)) {
660 moonbr_io_errmsg();
661 handle->fd = -1;
662 lua_pushnil(L);
663 lua_pushstring(L, errmsg);
664 return 2;
665 }
666 handle->fd = -1; /* fake EOF on read */
667 }
668 lua_pushboolean(L, 1);
669 return 1;
670 }
672 static int moonbr_io_close_impl(lua_State *L, int reset) {
673 moonbr_io_handle_t *handle;
674 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
675 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
676 if (!reset) {
677 if (handle->writeleft) {
678 lua_pushcfunction(L, moonbr_io_flush);
679 lua_pushvalue(L, 1);
680 if (lua_pcall(L, 1, 2, 0)) {
681 handle->closed = 1;
682 close(handle->fd);
683 handle->fd = -1;
684 lua_error(L);
685 }
686 handle->closed = 1;
687 if (!lua_toboolean(L, -2)) {
688 close(handle->fd);
689 handle->fd = -1;
690 return 2;
691 }
692 } else {
693 handle->closed = 1;
694 moonbr_io_handle_set_linger(L, handle, -1);
695 }
696 } else {
697 handle->closed = 1;
698 }
699 if (handle->fd >= 0) {
700 if (close(handle->fd)) {
701 moonbr_io_errmsg();
702 handle->fd = -1;
703 lua_pushnil(L);
704 lua_pushstring(L, errmsg);
705 return 2;
706 }
707 handle->fd = -1;
708 }
709 lua_pushboolean(L, 1);
710 return 1;
712 }
714 static int moonbr_io_close(lua_State *L) {
715 return moonbr_io_close_impl(L, 0);
716 }
718 static int moonbr_io_reset(lua_State *L) {
719 return moonbr_io_close_impl(L, 1);
720 }
722 static int moonbr_io_handlegc(lua_State *L) {
723 moonbr_io_handle_t *handle;
724 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
725 if (handle->fd >= 0) {
726 lua_pushcfunction(L, moonbr_io_close);
727 lua_pushvalue(L, 1);
728 lua_pushinteger(L, 0);
729 lua_call(L, 2, 0);
730 }
731 return 0;
732 }
734 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
735 moonbr_io_handle_t *handle;
736 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
737 if (!handle->closed) {
738 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
739 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
740 lua_call(L, 1, 0);
741 }
742 }
744 void moonbr_io_pushhandle(lua_State *L, int fd) {
745 moonbr_io_handle_t *handle;
746 struct sockaddr addr;
747 socklen_t addrlen;
748 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
749 handle->fd = fd;
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 moonbr_io_handle_set_linger(L, handle, 0);
777 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
778 lua_setmetatable(L, -2);
779 lua_newtable(L); // uservalue
780 lua_newtable(L);
781 lua_setfield(L, -2, "writequeue");
782 lua_newtable(L); // public
783 if (handle->addrfam == AF_INET6) {
784 struct sockaddr_in6 addr_in6;
785 char addrstrbuf[INET6_ADDRSTRLEN];
786 const char *addrstr;
787 addrlen = sizeof(addr_in6);
788 if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
789 moonbr_io_errmsg();
790 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
791 }
792 if (addrlen > sizeof(addr_in6)) {
793 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
794 }
795 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
796 if (!addrstr) {
797 moonbr_io_errmsg();
798 luaL_error(L, "Could not format local IP address: %s", errmsg);
799 } else {
800 lua_pushstring(L, addrstr);
801 lua_setfield(L, -2, "local_ip6");
802 }
803 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
804 lua_setfield(L, -2, "local_tcpport");
805 if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
806 moonbr_io_errmsg();
807 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
808 }
809 if (addrlen > sizeof(addr_in6)) {
810 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
811 }
812 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
813 if (!addrstr) {
814 moonbr_io_errmsg();
815 luaL_error(L, "Could not format remote IP address: %s", errmsg);
816 } else {
817 lua_pushstring(L, addrstr);
818 lua_setfield(L, -2, "remote_ip6");
819 }
820 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
821 lua_setfield(L, -2, "remote_tcpport");
822 } else if (handle->addrfam == AF_INET) {
823 struct sockaddr_in addr_in;
824 char addrstrbuf[INET_ADDRSTRLEN];
825 const char *addrstr;
826 addrlen = sizeof(addr_in);
827 if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) {
828 moonbr_io_errmsg();
829 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
830 }
831 if (addrlen > sizeof(addr_in)) {
832 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
833 }
834 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
835 if (!addrstr) {
836 moonbr_io_errmsg();
837 luaL_error(L, "Could not format local IP address: %s", errmsg);
838 } else {
839 lua_pushstring(L, addrstr);
840 lua_setfield(L, -2, "local_ip4");
841 }
842 lua_pushinteger(L, ntohs(addr_in.sin_port));
843 lua_setfield(L, -2, "local_tcpport");
844 if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) {
845 moonbr_io_errmsg();
846 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
847 }
848 if (addrlen > sizeof(addr_in)) {
849 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
850 }
851 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
852 if (!addrstr) {
853 moonbr_io_errmsg();
854 luaL_error(L, "Could not format remote IP address: %s", errmsg);
855 } else {
856 lua_pushstring(L, addrstr);
857 lua_setfield(L, -2, "remote_ip4");
858 }
859 lua_pushinteger(L, ntohs(addr_in.sin_port));
860 lua_setfield(L, -2, "remote_tcpport");
861 }
862 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
863 lua_setmetatable(L, -2);
864 lua_setfield(L, -2, "public");
865 lua_setuservalue(L, -2);
866 }
868 static int moonbr_io_handleindex(lua_State *L) {
869 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
870 lua_getuservalue(L, 1);
871 lua_getfield(L, -1, "public");
872 lua_pushvalue(L, 2);
873 lua_gettable(L, -2);
874 return 1;
875 }
877 static int moonbr_io_handlenewindex(lua_State *L) {
878 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
879 lua_getuservalue(L, 1);
880 lua_getfield(L, -1, "public");
881 lua_pushvalue(L, 2);
882 lua_pushvalue(L, 3);
883 lua_settable(L, -3);
884 return 0;
885 }
887 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
888 const char *path;
889 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
890 const int path_maxlen = sizeof(struct sockaddr_un) - (
891 (void *)sockaddr.sun_path - (void *)&sockaddr
892 ) - 1; /* one byte for termination */
893 int sock;
894 path = luaL_checkstring(L, 1);
895 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
896 strcpy(sockaddr.sun_path, path);
897 sock = socket(
898 PF_LOCAL,
899 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
900 0
901 );
902 if (sock < 0) {
903 moonbr_io_errmsg();
904 lua_pushnil(L);
905 lua_pushstring(L, errmsg);
906 return 2;
907 }
908 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
909 if (!nonblocking && errno == EINTR) {
910 moonbr_io_errmsg();
911 close(sock);
912 lua_pushnil(L);
913 lua_pushstring(L, errmsg);
914 return 2;
915 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
916 moonbr_io_errmsg();
917 lua_pushnil(L);
918 lua_pushstring(L, errmsg);
919 return 2;
920 }
921 }
922 moonbr_io_pushhandle(L, sock);
923 return 1;
924 }
926 static int moonbr_io_localconnect(lua_State *L) {
927 return moonbr_io_localconnect_impl(L, 0);
928 }
930 static int moonbr_io_localconnect_nb(lua_State *L) {
931 return moonbr_io_localconnect_impl(L, 1);
932 }
934 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
935 const char *host, *port;
936 struct addrinfo hints = { 0, };
937 struct addrinfo *res, *addrinfo;
938 int errcode;
939 int sock;
940 host = luaL_checkstring(L, 1);
941 port = luaL_checkstring(L, 2);
942 hints.ai_family = AF_UNSPEC;
943 hints.ai_socktype = SOCK_STREAM;
944 hints.ai_protocol = IPPROTO_TCP;
945 hints.ai_flags = AI_ADDRCONFIG;
946 errcode = getaddrinfo(host, port, &hints, &res);
947 if (errcode) {
948 freeaddrinfo(res);
949 if (errcode == EAI_SYSTEM) {
950 moonbr_io_errmsg();
951 lua_pushnil(L);
952 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
953 } else {
954 lua_pushnil(L);
955 lua_pushstring(L, gai_strerror(errcode));
956 }
957 return 2;
958 }
959 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
960 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
961 }
962 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
963 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
964 }
965 addrinfo = res;
966 moonbr_io_tcpconnect_found:
967 sock = socket(
968 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
969 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
970 addrinfo->ai_protocol
971 );
972 if (sock < 0) {
973 moonbr_io_errmsg();
974 freeaddrinfo(res);
975 lua_pushnil(L);
976 lua_pushstring(L, errmsg);
977 return 2;
978 }
979 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
980 freeaddrinfo(res);
981 if (!nonblocking && errno == EINTR) {
982 moonbr_io_errmsg();
983 close(sock);
984 lua_pushnil(L);
985 lua_pushstring(L, errmsg);
986 return 2;
987 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
988 moonbr_io_errmsg();
989 lua_pushnil(L);
990 lua_pushstring(L, errmsg);
991 return 2;
992 }
993 } else {
994 freeaddrinfo(res);
995 }
996 moonbr_io_pushhandle(L, sock);
997 return 1;
998 }
1000 static int moonbr_io_tcpconnect(lua_State *L) {
1001 return moonbr_io_tcpconnect_impl(L, 0);
1004 static int moonbr_io_tcpconnect_nb(lua_State *L) {
1005 return moonbr_io_tcpconnect_impl(L, 1);
1008 static int moonbr_io_locallisten(lua_State *L) {
1009 moonbr_io_listener_t *listener;
1010 const char *path;
1011 struct stat sb;
1012 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1013 const int path_maxlen = sizeof(struct sockaddr_un) - (
1014 (void *)sockaddr.sun_path - (void *)&sockaddr
1015 ) - 1; /* one byte for termination */
1016 int sock;
1017 path = luaL_checkstring(L, 1);
1018 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1019 strcpy(sockaddr.sun_path, path);
1020 if (stat(path, &sb) == 0) {
1021 if (S_ISSOCK(sb.st_mode)) unlink(path);
1023 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1024 listener->fd = -1;
1025 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1026 sock = socket(
1027 PF_LOCAL,
1028 SOCK_STREAM | SOCK_CLOEXEC,
1030 );
1031 if (sock < 0) {
1032 moonbr_io_errmsg();
1033 lua_pushnil(L);
1034 lua_pushstring(L, errmsg);
1035 return 2;
1037 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1038 moonbr_io_errmsg();
1039 close(sock);
1040 lua_pushnil(L);
1041 lua_pushstring(L, errmsg);
1042 return 2;
1044 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1045 moonbr_io_errmsg();
1046 close(sock);
1047 lua_pushnil(L);
1048 lua_pushstring(L, errmsg);
1049 return 2;
1051 listener->fd = sock;
1052 listener->addrfam = AF_LOCAL;
1053 listener->nonblocking = -1;
1054 return 1;
1057 static int moonbr_io_tcplisten(lua_State *L) {
1058 moonbr_io_listener_t *listener;
1059 const char *host, *port;
1060 struct addrinfo hints = { 0, };
1061 struct addrinfo *res, *addrinfo;
1062 int errcode;
1063 int sock;
1064 host = luaL_optstring(L, 1, NULL);
1065 port = luaL_checkstring(L, 2);
1066 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1067 listener->fd = -1;
1068 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1069 hints.ai_family = AF_UNSPEC;
1070 hints.ai_socktype = SOCK_STREAM;
1071 hints.ai_protocol = IPPROTO_TCP;
1072 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1073 errcode = getaddrinfo(host, port, &hints, &res);
1074 if (errcode) {
1075 freeaddrinfo(res);
1076 if (errcode == EAI_SYSTEM) {
1077 moonbr_io_errmsg();
1078 lua_pushnil(L);
1079 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1080 } else {
1081 lua_pushnil(L);
1082 lua_pushstring(L, gai_strerror(errcode));
1084 return 2;
1086 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1087 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1089 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1090 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1092 addrinfo = res;
1093 moonbr_io_tcpconnect_found:
1094 listener->addrfam = addrinfo->ai_family;
1095 sock = socket(
1096 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1097 addrinfo->ai_socktype | SOCK_CLOEXEC,
1098 addrinfo->ai_protocol
1099 );
1100 if (sock < 0) {
1101 moonbr_io_errmsg();
1102 freeaddrinfo(res);
1103 lua_pushnil(L);
1104 lua_pushstring(L, errmsg);
1105 return 2;
1108 static const int reuseval = 1;
1109 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1110 moonbr_io_errmsg();
1111 freeaddrinfo(res);
1112 close(sock);
1113 lua_pushnil(L);
1114 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1115 return 2;
1118 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1119 moonbr_io_errmsg();
1120 freeaddrinfo(res);
1121 close(sock);
1122 lua_pushnil(L);
1123 lua_pushstring(L, errmsg);
1124 return 2;
1126 freeaddrinfo(res);
1127 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1128 moonbr_io_errmsg();
1129 close(sock);
1130 lua_pushnil(L);
1131 lua_pushstring(L, errmsg);
1132 return 2;
1134 listener->fd = sock;
1135 listener->nonblocking = -1;
1136 return 1;
1139 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1140 moonbr_io_listener_t *listener;
1141 int fd;
1142 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1143 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1144 if (listener->nonblocking != nonblocking) {
1145 int flags;
1146 flags = fcntl(listener->fd, F_GETFL, 0);
1147 if (flags == -1) {
1148 moonbr_io_errmsg();
1149 close(listener->fd);
1150 listener->fd = -1;
1151 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1153 if (nonblocking) flags |= O_NONBLOCK;
1154 else flags &= ~O_NONBLOCK;
1155 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
1156 moonbr_io_errmsg();
1157 close(listener->fd);
1158 listener->fd = -1;
1159 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1161 listener->nonblocking = nonblocking;
1163 while (1) {
1164 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1165 if (fd < 0) {
1166 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1167 lua_pushboolean(L, 0);
1168 lua_pushliteral(L, "No incoming connection pending");
1169 return 2;
1170 } else if (errno != EINTR) {
1171 moonbr_io_errmsg();
1172 lua_pushnil(L);
1173 lua_pushstring(L, errmsg);
1174 return 2;
1176 } else {
1177 moonbr_io_pushhandle(L, fd);
1178 return 1;
1183 static int moonbr_io_accept(lua_State *L) {
1184 return moonbr_io_accept_impl(L, 0);
1187 static int moonbr_io_accept_nb(lua_State *L) {
1188 return moonbr_io_accept_impl(L, 1);
1191 static int moonbr_io_unlisten(lua_State *L) {
1192 moonbr_io_listener_t *listener;
1193 struct sockaddr_un addr;
1194 socklen_t addrlen;
1195 struct stat sb;
1196 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1197 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1198 addrlen = sizeof(addr);
1199 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1200 if (close(listener->fd)) {
1201 moonbr_io_errmsg();
1202 listener->fd = -1;
1203 if (addrlen && addrlen <= sizeof(addr)) {
1204 if (stat(addr.sun_path, &sb) == 0) {
1205 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1208 lua_pushnil(L);
1209 lua_pushstring(L, errmsg);
1210 return 2;
1212 listener->fd = -1;
1213 if (addrlen && addrlen <= sizeof(addr)) {
1214 if (stat(addr.sun_path, &sb) == 0) {
1215 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1218 lua_pushboolean(L, 1);
1219 return 1;
1222 static int moonbr_io_listenergc(lua_State *L) {
1223 moonbr_io_listener_t *listener;
1224 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1225 if (listener->fd >= 0) close(listener->fd);
1226 listener->fd = -1;
1227 return 0;
1230 static int moonbr_io_poll(lua_State *L) {
1231 moonbr_io_handle_t *handle;
1232 moonbr_io_listener_t *listener;
1233 int fd, isnum;
1234 int nfds = 0;
1235 fd_set readfds, writefds, exceptfds;
1236 struct timeval timeout = {0, };
1237 int status;
1238 FD_ZERO(&readfds);
1239 FD_ZERO(&writefds);
1240 FD_ZERO(&exceptfds);
1241 if (!lua_isnoneornil(L, 1)) {
1242 luaL_checktype(L, 1, LUA_TTABLE);
1243 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1244 if (lua_toboolean(L, -1)) {
1245 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1246 if (handle) {
1247 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1248 fd = handle->fd;
1249 if (
1250 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1251 handle->readbufin != handle->readbufout /* data pending in buffer */
1252 ) {
1253 lua_pushboolean(L, 1);
1254 return 1;
1256 } else {
1257 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1258 if (listener) {
1259 fd = listener->fd;
1260 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1261 } else {
1262 fd = lua_tointegerx(L, -2, &isnum);
1263 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1266 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1267 FD_SET(fd, &readfds);
1268 if (fd+1 > nfds) nfds = fd+1;
1272 if (!lua_isnoneornil(L, 2)) {
1273 luaL_checktype(L, 2, LUA_TTABLE);
1274 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1275 if (lua_toboolean(L, -1)) {
1276 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1277 if (handle) {
1278 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1279 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1280 fd = handle->fd;
1281 } else {
1282 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1283 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1284 fd = lua_tointegerx(L, -2, &isnum);
1285 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1287 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1288 FD_SET(fd, &writefds);
1289 if (fd+1 > nfds) nfds = fd+1;
1293 if (!lua_isnoneornil(L, 3)) {
1294 lua_Number n;
1295 n = lua_tonumberx(L, 3, &isnum);
1296 if (isnum && n<0) {
1297 lua_pushboolean(L, 0);
1298 lua_pushliteral(L, "Negative timeout");
1299 return 2;
1300 } else if (isnum && n>=0 && n<100000000) {
1301 timeout.tv_sec = n;
1302 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1303 } else {
1304 luaL_argcheck(L, 0, 3, "not a valid timeout");
1306 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1307 } else {
1308 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1310 if (status == -1) {
1311 if (errno == EINTR) {
1312 lua_pushnil(L);
1313 lua_pushliteral(L, "Signal received while polling file descriptors");
1314 return 2;
1315 } else {
1316 moonbr_io_errmsg();
1317 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1319 } else if (status == 0) {
1320 lua_pushboolean(L, 0);
1321 lua_pushliteral(L, "Timeout while polling file descriptors");
1322 return 2;
1323 } else {
1324 lua_pushboolean(L, 1);
1325 return 1;
1329 static int moonbr_io_timeref(lua_State *L) {
1330 lua_Number sub;
1331 struct timespec tp;
1332 sub = luaL_optnumber(L, 1, 0);
1333 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1334 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1336 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1337 return 1;
1340 #define MOONBR_IO_RUN_STACKBASE 7
1342 #if LUA_VERSION_NUM >= 503
1343 static int moonbr_io_run_cont(lua_State *L, int status, lua_KContext ctx) {
1344 #else
1345 static int moonbr_io_run_cont(lua_State *L) {
1346 #endif
1347 #if !(LUA_VERSION_NUM >= 503)
1348 int ctx = 0;
1349 lua_getctx(L, &ctx);
1350 #endif
1351 while (1) {
1352 int work_to_do = 0;
1353 assert(lua_gettop(L) == 7);
1354 if (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) return 1;
1355 lua_pop(L, 1);
1356 if (ctx) {
1357 for (lua_pushnil(L); lua_next(L, 4); lua_pop(L, 1)) {
1358 lua_pushvalue(L, -2);
1359 lua_pushnil(L);
1360 lua_rawset(L, 4);
1362 for (lua_pushnil(L); lua_next(L, 5); lua_pop(L, 1)) {
1363 lua_pushvalue(L, -2);
1364 lua_pushnil(L);
1365 lua_rawset(L, 5);
1368 assert(lua_gettop(L) == 6);
1369 while (lua_next(L, 1)) {
1370 void *marker;
1371 assert(lua_gettop(L) == MOONBR_IO_RUN_STACKBASE);
1372 while (1) {
1373 lua_pushvalue(L, -2);
1374 lua_call(L, 0, LUA_MULTRET);
1375 if (!lua_checkstack(L, LUA_MINSTACK)) luaL_error(L, "Lua stack exhausted");
1376 marker = lua_touserdata(L, MOONBR_IO_RUN_STACKBASE+1);
1377 if (marker == &moonbr_io_block_udata) {
1378 const char *mode = lua_tostring(L, MOONBR_IO_RUN_STACKBASE+3);
1379 if (mode && !lua_isnoneornil(L, MOONBR_IO_RUN_STACKBASE+2)) {
1380 if (strchr(mode, 'r')) {
1381 lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE+2);
1382 lua_pushboolean(L, 1);
1383 lua_rawset(L, 4);
1385 if (strchr(mode, 'w')) {
1386 lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE+2);
1387 lua_pushboolean(L, 1);
1388 lua_rawset(L, 5);
1391 work_to_do = 1;
1392 break;
1393 } else if (marker == &moonbr_io_multiblock_udata) {
1394 if (lua_type(L, MOONBR_IO_RUN_STACKBASE+2) == LUA_TTABLE) {
1395 for (lua_pushnil(L); lua_next(L, MOONBR_IO_RUN_STACKBASE+2); lua_pop(L, 1)) {
1396 if (lua_toboolean(L, -1)) {
1397 lua_pushvalue(L, -2);
1398 lua_pushboolean(L, 1);
1399 lua_rawset(L, 4);
1403 if (lua_type(L, MOONBR_IO_RUN_STACKBASE+3) == LUA_TTABLE) {
1404 for (lua_pushnil(L); lua_next(L, MOONBR_IO_RUN_STACKBASE+3); lua_pop(L, 1)) {
1405 if (lua_toboolean(L, -1)) {
1406 lua_pushvalue(L, -2);
1407 lua_pushboolean(L, 1);
1408 lua_rawset(L, 5);
1412 work_to_do = 1;
1413 break;
1414 } else if (lua_isboolean(L, MOONBR_IO_RUN_STACKBASE)) {
1415 lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE-1);
1416 lua_pushnil(L);
1417 lua_rawset(L, 1);
1418 break;
1419 } else {
1420 lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE);
1421 lua_insert(L, MOONBR_IO_RUN_STACKBASE+1);
1422 lua_call(L, lua_gettop(L)-1-MOONBR_IO_RUN_STACKBASE, 1);
1423 if (lua_toboolean(L, -1)) {
1424 lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE-1);
1425 lua_pushnil(L);
1426 lua_rawset(L, 1);
1427 break;
1430 lua_settop(L, MOONBR_IO_RUN_STACKBASE);
1432 lua_settop(L, MOONBR_IO_RUN_STACKBASE-1);
1434 if (!work_to_do) {
1435 lua_pushboolean(L, 1);
1436 return 1;
1438 lua_pushnil(L);
1439 assert(lua_gettop(L) == 6);
1440 ctx = 1;
1441 if (lua_isfunction(L, 2)) {
1442 lua_pushvalue(L, 2);
1443 lua_pushlightuserdata(L, &moonbr_io_multiblock_udata);
1444 lua_pushvalue(L, 4);
1445 lua_pushvalue(L, 5);
1446 lua_callk(L, 3, 1, ctx, moonbr_io_run_cont);
1447 } else {
1448 lua_pushcfunction(L, moonbr_io_poll);
1449 lua_pushvalue(L, 4);
1450 lua_pushvalue(L, 5);
1451 if (lua_isnil(L, 2)) {
1452 lua_call(L, 2, 1);
1453 } else {
1454 lua_pushvalue(L, 2);
1455 lua_pushcfunction(L, moonbr_io_timeref);
1456 lua_pushvalue(L, 3);
1457 lua_call(L, 1, 1);
1458 lua_arith(L, LUA_OPSUB);
1459 lua_call(L, 3, 1);
1462 assert(lua_gettop(L) == 7);
1466 static int moonbr_io_run(lua_State *L) {
1467 lua_settop(L, 2);
1468 luaL_checktype(L, 1, LUA_TTABLE);
1469 if (lua_isnil(L, 2) || lua_isfunction(L, 2)) {
1470 lua_pushnil(L);
1471 } else if (!lua_isnil(L, 2)) {
1472 luaL_checknumber(L, 2);
1473 lua_pushcfunction(L, moonbr_io_timeref);
1474 lua_call(L, 0, 1);
1476 assert(lua_gettop(L) == 3);
1477 lua_newtable(L); /* read_fds at stack position 4 */
1478 lua_newtable(L); /* write_fds at stack position 5 */
1479 lua_pushnil(L); /* current thread */
1480 lua_pushnil(L);
1481 #if LUA_VERSION_NUM >= 503
1482 return moonbr_io_run_cont(L, 0, 0);
1483 #else
1484 return moonbr_io_run_cont(L);
1485 #endif
1488 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1489 {"read", moonbr_io_read},
1490 {"read_nb", moonbr_io_read_nb},
1491 {"read_call", moonbr_io_read_call},
1492 {"read_yield", moonbr_io_read_yield},
1493 {"drain", moonbr_io_drain},
1494 {"drain_nb", moonbr_io_drain_nb},
1495 {"drain_call", moonbr_io_drain_call},
1496 {"drain_yield", moonbr_io_drain_yield},
1497 {"write", moonbr_io_write},
1498 {"write_nb", moonbr_io_write_nb},
1499 {"write_call", moonbr_io_write_call},
1500 {"write_yield", moonbr_io_write_yield},
1501 {"flush", moonbr_io_flush},
1502 {"flush_nb", moonbr_io_flush_nb},
1503 {"flush_call", moonbr_io_flush_call},
1504 {"flush_yield", moonbr_io_flush_yield},
1505 {"finish", moonbr_io_finish},
1506 {"close", moonbr_io_close},
1507 {"reset", moonbr_io_reset},
1508 {NULL, NULL}
1509 };
1511 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1512 {"__index", moonbr_io_handleindex},
1513 {"__newindex", moonbr_io_handlenewindex},
1514 {"__gc", moonbr_io_handlegc},
1515 {NULL, NULL}
1516 };
1518 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1519 {"accept", moonbr_io_accept},
1520 {"accept_nb", moonbr_io_accept_nb},
1521 {"close", moonbr_io_unlisten},
1522 {NULL, NULL}
1523 };
1525 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1526 {"__gc", moonbr_io_listenergc},
1527 {NULL, NULL}
1528 };
1530 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1531 {"localconnect", moonbr_io_localconnect},
1532 {"localconnect_nb", moonbr_io_localconnect_nb},
1533 {"tcpconnect", moonbr_io_tcpconnect},
1534 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1535 {"locallisten", moonbr_io_locallisten},
1536 {"tcplisten", moonbr_io_tcplisten},
1537 {"poll", moonbr_io_poll},
1538 {"timeref", moonbr_io_timeref},
1539 {"run", moonbr_io_run},
1540 {NULL, NULL}
1541 };
1543 int luaopen_moonbridge_io(lua_State *L) {
1545 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1547 lua_newtable(L); // module
1549 lua_pushlightuserdata(L, &moonbr_io_block_udata);
1550 lua_setfield(L, -2, "block");
1551 lua_pushlightuserdata(L, &moonbr_io_multiblock_udata);
1552 lua_setfield(L, -2, "multiblock");
1554 lua_newtable(L); // public metatable
1555 lua_newtable(L); // handle methods
1556 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1557 lua_pushvalue(L, -1);
1558 lua_setfield(L, -4, "handle_pt");
1559 lua_setfield(L, -2, "__index");
1560 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1562 lua_newtable(L); // handle metatable
1563 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1564 lua_pushvalue(L, -1);
1565 lua_setfield(L, -3, "handle_mt");
1566 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1568 lua_newtable(L); // listener metatable
1569 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1570 lua_newtable(L); // listener methods
1571 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1572 lua_pushvalue(L, -1);
1573 lua_setfield(L, -4, "listener_pt");
1574 lua_setfield(L, -2, "__index");
1575 lua_pushvalue(L, -1);
1576 lua_setfield(L, -3, "listener_mt");
1577 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1579 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1580 return 1;

Impressum / About Us