moonbridge

view moonbridge_io.c @ 145:bd88dfa4f294

Yielding write and flush methods for I/O
author jbe
date Sat May 02 16:25:33 2015 +0200 (2015-05-02)
parents e7fac0918f9c
children 6dfe5b424b18
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 #define MOONBR_IO_MAXSTRERRORLEN 80
27 #define MOONBR_IO_READBUFLEN 4096
28 #define MOONBR_IO_WRITEBUFLEN 4096
30 #define MOONBR_IO_LISTEN_BACKLOG 1024
32 #define moonbr_io_errmsg() \
33 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
34 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
36 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
37 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
38 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
40 typedef struct {
41 int fd;
42 int issock;
43 sa_family_t addrfam;
44 int finished;
45 int closed;
46 int nonblocking;
47 int nopush;
48 int readerr;
49 int readbufin;
50 int readbufout;
51 int writeerr;
52 size_t writeleft;
53 size_t flushedleft;
54 #if LUA_VERSION_NUM >= 503
55 lua_Integer writeqin;
56 lua_Integer writeqout;
57 #else
58 int writeqin;
59 int writeqout;
60 #endif
61 size_t writeqoff;
62 int writebufin;
63 int writebufout;
64 char readbuf[MOONBR_IO_READBUFLEN];
65 char writebuf[MOONBR_IO_WRITEBUFLEN];
66 } moonbr_io_handle_t;
68 typedef struct {
69 int fd;
70 sa_family_t addrfam;
71 int nonblocking;
72 } moonbr_io_listener_t;
74 static int moonbr_io_yield(lua_State *L) {
75 return lua_yield(L, 0);
76 }
78 #if LUA_VERSION_NUM >= 503
79 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
80 #else
81 static int moonbr_io_cont_returnall(lua_State *L) {
82 #endif
83 return lua_gettop(L);
84 }
86 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
87 static int yieldfunc(lua_State *L) { \
88 int args; \
89 lua_pushcfunction(L, callfunc); \
90 lua_insert(L, 1); \
91 args = lua_gettop(L); \
92 lua_pushcfunction(L, moonbr_io_yield); \
93 lua_insert(L, 3); \
94 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
95 return lua_gettop(L); \
96 }
98 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
99 int flags;
100 if (handle->nonblocking == nonblocking) return;
101 flags = fcntl(handle->fd, F_GETFL, 0);
102 if (flags == -1) {
103 moonbr_io_errmsg();
104 close(handle->fd);
105 handle->fd = -1;
106 handle->closed = 1;
107 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
108 }
109 if (nonblocking) flags |= O_NONBLOCK;
110 else flags &= ~O_NONBLOCK;
111 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
112 moonbr_io_errmsg();
113 close(handle->fd);
114 handle->fd = -1;
115 handle->closed = 1;
116 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
117 }
118 handle->nonblocking = nonblocking;
119 }
121 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
122 struct linger lingerval = { 0, };
123 if (!handle->issock) return;
124 if (timeout >= 0) {
125 lingerval.l_onoff = 1;
126 lingerval.l_linger = timeout;
127 }
128 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
129 moonbr_io_errmsg();
130 close(handle->fd);
131 handle->fd = -1;
132 handle->closed = 1;
133 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
134 }
135 }
137 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
138 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
139 if (
140 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
141 handle->nopush == nopush
142 ) return;
143 #if defined(TCP_NOPUSH)
144 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
145 #elif defined(TCP_CORK)
146 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
147 #endif
148 moonbr_io_errmsg();
149 close(handle->fd);
150 handle->fd = -1;
151 handle->closed = 1;
152 #if defined(TCP_NOPUSH)
153 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
154 #elif defined(TCP_CORK)
155 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
156 #endif
157 }
158 handle->nopush = nopush;
159 #else
160 #warning Neither TCP_NOPUSH nor TCP_CORK is available
161 #endif
162 }
164 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
165 moonbr_io_handle_t *handle;
166 lua_Integer maxread;
167 const char *terminatorstr;
168 size_t terminatorlen;
169 char terminator = 0; /* initialize to avoid compiler warning */
170 luaL_Buffer luabuf;
171 size_t luabufcnt = 0;
172 int remaining;
173 char *terminatorpos;
174 ssize_t bytesread;
175 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
176 maxread = luaL_optinteger(L, 2, 0);
177 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
178 if (terminatorlen) {
179 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
180 terminator = terminatorstr[0];
181 }
182 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
183 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
184 if (handle->readerr) {
185 lua_pushnil(L);
186 lua_pushliteral(L, "Previous read error");
187 return 2;
188 }
189 if (handle->fd < 0) {
190 /* fake EOF to simulate shutdown */
191 if (!drain) lua_pushliteral(L, "");
192 else lua_pushinteger(L, 0);
193 lua_pushliteral(L, "eof");
194 return 2;
195 }
196 handle->readerr = 1;
197 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
198 if (!drain) luaL_buffinit(L, &luabuf);
199 while (1) {
200 remaining = -1;
201 terminatorpos = NULL;
202 if (
203 maxread > 0 &&
204 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
205 ) {
206 remaining = (size_t)maxread - luabufcnt;
207 terminatorpos = memchr(
208 handle->readbuf + handle->readbufout,
209 terminator,
210 remaining
211 );
212 } else if (terminatorlen) {
213 terminatorpos = memchr(
214 handle->readbuf + handle->readbufout,
215 terminator,
216 handle->readbufin - handle->readbufout
217 );
218 }
219 if (terminatorpos) remaining = 1 + (
220 terminatorpos - (handle->readbuf + handle->readbufout)
221 );
222 if (remaining >= 0) {
223 if (!drain) {
224 luaL_addlstring(
225 &luabuf,
226 handle->readbuf + handle->readbufout,
227 remaining
228 );
229 luaL_pushresult(&luabuf);
230 } else {
231 lua_pushinteger(L, luabufcnt + remaining);
232 }
233 if (terminatorpos) lua_pushliteral(L, "term");
234 else lua_pushliteral(L, "maxlen");
235 handle->readbufout += remaining;
236 if (handle->readbufout == handle->readbufin) {
237 handle->readbufin = 0;
238 handle->readbufout = 0;
239 }
240 handle->readerr = 0;
241 return 2;
242 }
243 if (!drain) luaL_addlstring(
244 &luabuf,
245 handle->readbuf + handle->readbufout,
246 handle->readbufin - handle->readbufout
247 );
248 luabufcnt += handle->readbufin - handle->readbufout;
249 handle->readbufout = 0;
250 do {
251 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
252 } while (bytesread < 0 && (errno == EINTR));
253 if (
254 bytesread == 0 || (
255 nonblocking &&
256 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
257 )
258 ) {
259 handle->readbufin = 0;
260 if (!drain) luaL_pushresult(&luabuf);
261 else lua_pushinteger(L, luabufcnt);
262 if (bytesread == 0) lua_pushliteral(L, "eof");
263 else lua_pushliteral(L, "block");
264 handle->readerr = 0;
265 return 2;
266 }
267 if (bytesread < 0) {
268 moonbr_io_errmsg();
269 lua_pushnil(L);
270 lua_pushstring(L, errmsg);
271 return 2;
272 }
273 handle->readbufin = bytesread;
274 }
275 }
277 static int moonbr_io_read(lua_State *L) {
278 return moonbr_io_read_impl(L, 0, 0);
279 }
281 static int moonbr_io_read_nb(lua_State *L) {
282 return moonbr_io_read_impl(L, 1, 0);
283 }
285 static int moonbr_io_drain(lua_State *L) {
286 return moonbr_io_read_impl(L, 0, 1);
287 }
289 static int moonbr_io_drain_nb(lua_State *L) {
290 return moonbr_io_read_impl(L, 1, 1);
291 }
293 #if LUA_VERSION_NUM >= 503
294 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
295 #else
296 static int moonbr_io_read_cont(lua_State *L) {
297 #endif
298 lua_Integer remaining;
299 size_t len;
300 #if !(LUA_VERSION_NUM >= 503)
301 int ctx = 0;
302 lua_getctx(L, &ctx);
303 #endif
304 remaining = lua_tointeger(L, 3);
305 while (1) {
306 lua_pushcfunction(L, moonbr_io_read_nb);
307 lua_pushvalue(L, 1);
308 lua_pushvalue(L, 3);
309 lua_pushvalue(L, 4);
310 lua_call(L, 3, 2);
311 if (lua_isnil(L, -2)) return 2;
312 lua_insert(L, -2);
313 len = lua_rawlen(L, -1);
314 if (ctx == 0) {
315 lua_replace(L, 5);
316 ctx = 1;
317 } else if (ctx == 1) {
318 lua_pushvalue(L, 5);
319 lua_newtable(L);
320 lua_replace(L, 5);
321 lua_rawseti(L, 5, 2);
322 lua_rawseti(L, 5, 1);
323 ctx = 2;
324 } else {
325 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
326 }
327 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
328 lua_pop(L, 1);
329 if (remaining >= 0 && len) {
330 remaining -= len;
331 lua_pushinteger(L, remaining);
332 lua_replace(L, 3);
333 }
334 lua_pushvalue(L, 2);
335 lua_pushvalue(L, 1);
336 lua_pushliteral(L, "r");
337 lua_callk(L, 2, 0, ctx, moonbr_io_read_cont);
338 }
339 if (ctx == 1) {
340 lua_pushvalue(L, 5);
341 } else {
342 luaL_Buffer buf;
343 lua_Integer i, chunkcount;
344 chunkcount = lua_rawlen(L, 5);
345 luaL_buffinit(L, &buf);
346 for (i=1; i<=chunkcount && i>0; i++) {
347 lua_rawgeti(L, 5, i);
348 luaL_addvalue(&buf);
349 }
350 luaL_pushresult(&buf);
351 }
352 lua_pushvalue(L, -2);
353 return 2;
354 }
356 static int moonbr_io_read_call(lua_State *L) {
357 lua_settop(L, 4);
358 lua_pushnil(L);
359 #if LUA_VERSION_NUM >= 503
360 return moonbr_io_read_cont(L, 0, 0);
361 #else
362 return moonbr_io_read_cont(L);
363 #endif
364 }
366 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
368 #if LUA_VERSION_NUM >= 503
369 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
370 #else
371 static int moonbr_io_drain_cont(lua_State *L) {
372 #endif
373 lua_Integer remaining, len;
374 size_t totallen = 0;
375 #if !(LUA_VERSION_NUM >= 503)
376 int ctx = 0;
377 lua_getctx(L, &ctx);
378 #endif
379 remaining = lua_tointeger(L, 3);
380 while (1) {
381 lua_pushcfunction(L, moonbr_io_drain_nb);
382 lua_pushvalue(L, 1);
383 lua_pushvalue(L, 3);
384 lua_pushvalue(L, 4);
385 lua_call(L, 3, 2);
386 if (lua_isnil(L, -2)) return 2;
387 lua_insert(L, -2);
388 len = lua_tointeger(L, -1);
389 lua_pop(L, 1);
390 totallen += len;
391 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
392 lua_pop(L, 1);
393 if (remaining >= 0 && len) {
394 remaining -= len;
395 lua_pushinteger(L, remaining);
396 lua_replace(L, 3);
397 }
398 lua_pushvalue(L, 2);
399 lua_pushvalue(L, 1);
400 lua_pushliteral(L, "r");
401 lua_callk(L, 2, 0, ctx, moonbr_io_drain_cont);
402 }
403 lua_pushinteger(L, totallen);
404 lua_pushvalue(L, -2);
405 return 2;
406 }
408 static int moonbr_io_drain_call(lua_State *L) {
409 #if LUA_VERSION_NUM >= 503
410 return moonbr_io_drain_cont(L, 0, 0);
411 #else
412 return moonbr_io_drain_cont(L);
413 #endif
414 }
416 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
418 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
419 moonbr_io_handle_t *handle;
420 int i, top;
421 const char *str;
422 size_t strlen;
423 ssize_t written;
424 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
425 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
426 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
427 if (handle->writeerr) {
428 lua_pushnil(L);
429 lua_pushliteral(L, "Previous write error");
430 return 2;
431 }
432 handle->writeerr = 1;
433 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
434 top = lua_gettop(L);
435 lua_getuservalue(L, 1);
436 lua_getfield(L, -1, "writequeue");
437 for (i=2; i<=top; i++) {
438 luaL_checklstring(L, i, &strlen);
439 lua_pushvalue(L, i);
440 lua_rawseti(L, -2, handle->writeqin++);
441 handle->writeleft += strlen;
442 }
443 if (flush) handle->flushedleft = handle->writeleft;
444 while (handle->writeqout != handle->writeqin) {
445 lua_rawgeti(L, -1, handle->writeqout);
446 str = lua_tolstring(L, -1, &strlen);
447 while (handle->writeqoff < strlen) {
448 if (
449 strlen - handle->writeqoff <
450 MOONBR_IO_WRITEBUFLEN - handle->writebufin
451 ) {
452 memcpy(
453 handle->writebuf + handle->writebufin,
454 str + handle->writeqoff,
455 strlen - handle->writeqoff
456 );
457 handle->writebufin += strlen - handle->writeqoff;
458 break;
459 } else {
460 memcpy(
461 handle->writebuf + handle->writebufin,
462 str + handle->writeqoff,
463 MOONBR_IO_WRITEBUFLEN - handle->writebufin
464 );
465 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
466 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
467 moonbr_io_handle_set_nopush(L, handle, 1);
468 written = write(
469 handle->fd,
470 handle->writebuf + handle->writebufout,
471 MOONBR_IO_WRITEBUFLEN - handle->writebufout
472 );
473 if (written < 0) {
474 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
475 goto moonbr_io_write_impl_block;
476 } else if (errno != EINTR) {
477 moonbr_io_errmsg();
478 lua_pushnil(L);
479 lua_pushstring(L, errmsg);
480 return 2;
481 }
482 } else {
483 handle->writebufout += written;
484 handle->writeleft -= written;
485 if (handle->flushedleft) {
486 if (written >= handle->flushedleft) {
487 handle->flushedleft = 0;
488 moonbr_io_handle_set_nopush(L, handle, 0);
489 } else {
490 handle->flushedleft -= written;
491 }
492 }
493 }
494 }
495 handle->writebufin = 0;
496 handle->writebufout = 0;
497 }
498 }
499 handle->writeqoff = 0;
500 lua_pop(L, 1);
501 lua_pushnil(L);
502 lua_rawseti(L, -2, handle->writeqout++);
503 }
504 while (handle->flushedleft) {
505 moonbr_io_handle_set_nopush(L, handle, 1);
506 written = write(
507 handle->fd,
508 handle->writebuf + handle->writebufout,
509 handle->writebufin - handle->writebufout
510 );
511 if (written < 0) {
512 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
513 goto moonbr_io_write_impl_block;
514 } else if (errno != EINTR) {
515 moonbr_io_errmsg();
516 lua_pushnil(L);
517 lua_pushstring(L, errmsg);
518 return 2;
519 }
520 } else {
521 handle->writebufout += written;
522 handle->writeleft -= written;
523 if (handle->flushedleft) {
524 if (written >= handle->flushedleft) {
525 handle->flushedleft = 0;
526 moonbr_io_handle_set_nopush(L, handle, 0);
527 } else {
528 handle->flushedleft -= written;
529 }
530 }
531 }
532 }
533 if (handle->writebufout == handle->writebufin) {
534 handle->writebufin = 0;
535 handle->writebufout = 0;
536 }
537 if (nonblocking) lua_pushinteger(L, 0);
538 else lua_pushvalue(L, 1);
539 handle->writeerr = 0;
540 return 1;
541 moonbr_io_write_impl_block:
542 lua_pushinteger(L, handle->writeleft);
543 handle->writeerr = 0;
544 return 1;
545 }
547 static int moonbr_io_write(lua_State *L) {
548 return moonbr_io_write_impl(L, 0, 0);
549 }
551 static int moonbr_io_write_nb(lua_State *L) {
552 return moonbr_io_write_impl(L, 1, 0);
553 }
555 static int moonbr_io_flush(lua_State *L) {
556 return moonbr_io_write_impl(L, 0, 1);
557 }
559 static int moonbr_io_flush_nb(lua_State *L) {
560 return moonbr_io_write_impl(L, 1, 1);
561 }
563 #if LUA_VERSION_NUM >= 503
564 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
565 #else
566 static int moonbr_io_write_cont(lua_State *L) {
567 #endif
568 while (1) {
569 lua_pushcfunction(L, moonbr_io_write_nb);
570 lua_pushvalue(L, 1);
571 lua_call(L, 1, 2);
572 if (lua_isnil(L, -2)) return 2;
573 if (!lua_tointeger(L, -2)) {
574 lua_pushvalue(L, 1);
575 return 1;
576 }
577 lua_pop(L, 2);
578 lua_pushvalue(L, 2);
579 lua_pushvalue(L, 1);
580 lua_pushliteral(L, "w");
581 lua_callk(L, 2, 0, 0, moonbr_io_write_cont);
582 }
583 }
585 static int moonbr_io_write_call(lua_State *L) {
586 lua_pushcfunction(L, moonbr_io_write_nb);
587 lua_insert(L, 3);
588 lua_pushvalue(L, 1);
589 lua_insert(L, 4);
590 lua_call(L, lua_gettop(L) - 3, 2);
591 if (lua_isnil(L, -2)) return 2;
592 if (!lua_tointeger(L, -2)) {
593 lua_pushvalue(L, 1);
594 return 1;
595 }
596 #if LUA_VERSION_NUM >= 503
597 return moonbr_io_write_cont(L, 0, 0);
598 #else
599 return moonbr_io_write_cont(L);
600 #endif
601 }
603 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
605 static int moonbr_io_flush_call(lua_State *L) {
606 lua_pushcfunction(L, moonbr_io_flush_nb);
607 lua_insert(L, 3);
608 lua_pushvalue(L, 1);
609 lua_insert(L, 4);
610 lua_call(L, lua_gettop(L) - 3, 2);
611 if (lua_isnil(L, -2)) return 2;
612 if (!lua_tointeger(L, -2)) {
613 lua_pushvalue(L, 1);
614 return 1;
615 }
616 #if LUA_VERSION_NUM >= 503
617 return moonbr_io_write_cont(L, 0, 0);
618 #else
619 return moonbr_io_write_cont(L);
620 #endif
621 }
623 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
625 static int moonbr_io_finish(lua_State *L) {
626 moonbr_io_handle_t *handle;
627 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
628 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
629 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
630 if (handle->writeleft) {
631 lua_pushcfunction(L, moonbr_io_flush);
632 lua_pushvalue(L, 1);
633 if (lua_pcall(L, 1, 2, 0)) {
634 handle->finished = 1;
635 lua_error(L);
636 }
637 if (!lua_toboolean(L, -2)) {
638 handle->finished = 1;
639 return 2;
640 }
641 }
642 handle->finished = 1;
643 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
644 if (shutdown(handle->fd, SHUT_WR)) {
645 moonbr_io_errmsg();
646 lua_pushnil(L);
647 lua_pushstring(L, errmsg);
648 return 2;
649 }
650 } else {
651 if (close(handle->fd)) {
652 moonbr_io_errmsg();
653 handle->fd = -1;
654 lua_pushnil(L);
655 lua_pushstring(L, errmsg);
656 return 2;
657 }
658 handle->fd = -1; /* fake EOF on read */
659 }
660 lua_pushboolean(L, 1);
661 return 1;
662 }
664 static int moonbr_io_close_impl(lua_State *L, int reset) {
665 moonbr_io_handle_t *handle;
666 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
667 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
668 if (!reset) {
669 if (handle->writeleft) {
670 lua_pushcfunction(L, moonbr_io_flush);
671 lua_pushvalue(L, 1);
672 if (lua_pcall(L, 1, 2, 0)) {
673 handle->closed = 1;
674 close(handle->fd);
675 handle->fd = -1;
676 lua_error(L);
677 }
678 handle->closed = 1;
679 if (!lua_toboolean(L, -2)) {
680 close(handle->fd);
681 handle->fd = -1;
682 return 2;
683 }
684 } else {
685 handle->closed = 1;
686 moonbr_io_handle_set_linger(L, handle, -1);
687 }
688 } else {
689 handle->closed = 1;
690 }
691 if (handle->fd >= 0) {
692 if (close(handle->fd)) {
693 moonbr_io_errmsg();
694 handle->fd = -1;
695 lua_pushnil(L);
696 lua_pushstring(L, errmsg);
697 return 2;
698 }
699 handle->fd = -1;
700 }
701 lua_pushboolean(L, 1);
702 return 1;
704 }
706 static int moonbr_io_close(lua_State *L) {
707 return moonbr_io_close_impl(L, 0);
708 }
710 static int moonbr_io_reset(lua_State *L) {
711 return moonbr_io_close_impl(L, 1);
712 }
714 static int moonbr_io_handlegc(lua_State *L) {
715 moonbr_io_handle_t *handle;
716 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
717 if (handle->fd >= 0) {
718 lua_pushcfunction(L, moonbr_io_close);
719 lua_pushvalue(L, 1);
720 lua_pushinteger(L, 0);
721 lua_call(L, 2, 0);
722 }
723 return 0;
724 }
726 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
727 moonbr_io_handle_t *handle;
728 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
729 if (!handle->closed) {
730 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
731 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
732 lua_call(L, 1, 0);
733 }
734 }
736 void moonbr_io_pushhandle(lua_State *L, int fd) {
737 moonbr_io_handle_t *handle;
738 struct sockaddr addr;
739 socklen_t addrlen;
740 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
741 handle->fd = fd;
742 addrlen = sizeof(addr);
743 if (getsockname(fd, &addr, &addrlen)) {
744 if (errno != ENOTSOCK) {
745 moonbr_io_errmsg();
746 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
747 }
748 handle->issock = 0;
749 } else {
750 handle->issock = 1;
751 handle->addrfam = addr.sa_family;
752 }
753 handle->finished = 0;
754 handle->closed = 0;
755 handle->nonblocking = -1;
756 handle->nopush = -1;
757 handle->readerr = 0;
758 handle->readbufin = 0;
759 handle->readbufout = 0;
760 handle->writeerr = 0;
761 handle->writeleft = 0;
762 handle->flushedleft = 0;
763 handle->writeqin = 0;
764 handle->writeqout = 0;
765 handle->writeqoff = 0;
766 handle->writebufin = 0;
767 handle->writebufout = 0;
768 moonbr_io_handle_set_linger(L, handle, 0);
769 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
770 lua_setmetatable(L, -2);
771 lua_newtable(L); // uservalue
772 lua_newtable(L);
773 lua_setfield(L, -2, "writequeue");
774 lua_newtable(L); // public
775 if (handle->addrfam == AF_INET6) {
776 struct sockaddr_in6 addr_in6;
777 char addrstrbuf[INET6_ADDRSTRLEN];
778 const char *addrstr;
779 addrlen = sizeof(addr_in6);
780 if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
781 moonbr_io_errmsg();
782 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
783 }
784 if (addrlen > sizeof(addr_in6)) {
785 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
786 }
787 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
788 if (!addrstr) {
789 moonbr_io_errmsg();
790 luaL_error(L, "Could not format local IP address: %s", errmsg);
791 } else {
792 lua_pushstring(L, addrstr);
793 lua_setfield(L, -2, "local_ip6");
794 }
795 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
796 lua_setfield(L, -2, "local_tcpport");
797 if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
798 moonbr_io_errmsg();
799 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
800 }
801 if (addrlen > sizeof(addr_in6)) {
802 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
803 }
804 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
805 if (!addrstr) {
806 moonbr_io_errmsg();
807 luaL_error(L, "Could not format remote IP address: %s", errmsg);
808 } else {
809 lua_pushstring(L, addrstr);
810 lua_setfield(L, -2, "remote_ip6");
811 }
812 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
813 lua_setfield(L, -2, "remote_tcpport");
814 } else if (handle->addrfam == AF_INET) {
815 struct sockaddr_in addr_in;
816 char addrstrbuf[INET_ADDRSTRLEN];
817 const char *addrstr;
818 addrlen = sizeof(addr_in);
819 if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) {
820 moonbr_io_errmsg();
821 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
822 }
823 if (addrlen > sizeof(addr_in)) {
824 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
825 }
826 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
827 if (!addrstr) {
828 moonbr_io_errmsg();
829 luaL_error(L, "Could not format local IP address: %s", errmsg);
830 } else {
831 lua_pushstring(L, addrstr);
832 lua_setfield(L, -2, "local_ip4");
833 }
834 lua_pushinteger(L, ntohs(addr_in.sin_port));
835 lua_setfield(L, -2, "local_tcpport");
836 if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) {
837 moonbr_io_errmsg();
838 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
839 }
840 if (addrlen > sizeof(addr_in)) {
841 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
842 }
843 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
844 if (!addrstr) {
845 moonbr_io_errmsg();
846 luaL_error(L, "Could not format remote IP address: %s", errmsg);
847 } else {
848 lua_pushstring(L, addrstr);
849 lua_setfield(L, -2, "remote_ip4");
850 }
851 lua_pushinteger(L, ntohs(addr_in.sin_port));
852 lua_setfield(L, -2, "remote_tcpport");
853 }
854 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
855 lua_setmetatable(L, -2);
856 lua_setfield(L, -2, "public");
857 lua_setuservalue(L, -2);
858 }
860 static int moonbr_io_handleindex(lua_State *L) {
861 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
862 lua_getuservalue(L, 1);
863 lua_getfield(L, -1, "public");
864 lua_pushvalue(L, 2);
865 lua_gettable(L, -2);
866 return 1;
867 }
869 static int moonbr_io_handlenewindex(lua_State *L) {
870 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
871 lua_getuservalue(L, 1);
872 lua_getfield(L, -1, "public");
873 lua_pushvalue(L, 2);
874 lua_pushvalue(L, 3);
875 lua_settable(L, -3);
876 return 0;
877 }
879 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
880 const char *path;
881 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
882 const int path_maxlen = sizeof(struct sockaddr_un) - (
883 (void *)sockaddr.sun_path - (void *)&sockaddr
884 ) - 1; /* one byte for termination */
885 int sock;
886 path = luaL_checkstring(L, 1);
887 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
888 strcpy(sockaddr.sun_path, path);
889 sock = socket(
890 PF_LOCAL,
891 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
892 0
893 );
894 if (sock < 0) {
895 moonbr_io_errmsg();
896 lua_pushnil(L);
897 lua_pushstring(L, errmsg);
898 return 2;
899 }
900 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
901 if (!nonblocking && errno == EINTR) {
902 moonbr_io_errmsg();
903 close(sock);
904 lua_pushnil(L);
905 lua_pushstring(L, errmsg);
906 return 2;
907 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
908 moonbr_io_errmsg();
909 lua_pushnil(L);
910 lua_pushstring(L, errmsg);
911 return 2;
912 }
913 }
914 moonbr_io_pushhandle(L, sock);
915 return 1;
916 }
918 static int moonbr_io_localconnect(lua_State *L) {
919 return moonbr_io_localconnect_impl(L, 0);
920 }
922 static int moonbr_io_localconnect_nb(lua_State *L) {
923 return moonbr_io_localconnect_impl(L, 1);
924 }
926 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
927 const char *host, *port;
928 struct addrinfo hints = { 0, };
929 struct addrinfo *res, *addrinfo;
930 int errcode;
931 int sock;
932 host = luaL_checkstring(L, 1);
933 port = luaL_checkstring(L, 2);
934 hints.ai_family = AF_UNSPEC;
935 hints.ai_socktype = SOCK_STREAM;
936 hints.ai_protocol = IPPROTO_TCP;
937 hints.ai_flags = AI_ADDRCONFIG;
938 errcode = getaddrinfo(host, port, &hints, &res);
939 if (errcode) {
940 freeaddrinfo(res);
941 if (errcode == EAI_SYSTEM) {
942 moonbr_io_errmsg();
943 lua_pushnil(L);
944 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
945 } else {
946 lua_pushnil(L);
947 lua_pushstring(L, gai_strerror(errcode));
948 }
949 return 2;
950 }
951 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
952 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
953 }
954 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
955 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
956 }
957 addrinfo = res;
958 moonbr_io_tcpconnect_found:
959 sock = socket(
960 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
961 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
962 addrinfo->ai_protocol
963 );
964 if (sock < 0) {
965 moonbr_io_errmsg();
966 freeaddrinfo(res);
967 lua_pushnil(L);
968 lua_pushstring(L, errmsg);
969 return 2;
970 }
971 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
972 freeaddrinfo(res);
973 if (!nonblocking && errno == EINTR) {
974 moonbr_io_errmsg();
975 close(sock);
976 lua_pushnil(L);
977 lua_pushstring(L, errmsg);
978 return 2;
979 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
980 moonbr_io_errmsg();
981 lua_pushnil(L);
982 lua_pushstring(L, errmsg);
983 return 2;
984 }
985 } else {
986 freeaddrinfo(res);
987 }
988 moonbr_io_pushhandle(L, sock);
989 return 1;
990 }
992 static int moonbr_io_tcpconnect(lua_State *L) {
993 return moonbr_io_tcpconnect_impl(L, 0);
994 }
996 static int moonbr_io_tcpconnect_nb(lua_State *L) {
997 return moonbr_io_tcpconnect_impl(L, 1);
998 }
1000 static int moonbr_io_locallisten(lua_State *L) {
1001 moonbr_io_listener_t *listener;
1002 const char *path;
1003 struct stat sb;
1004 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
1005 const int path_maxlen = sizeof(struct sockaddr_un) - (
1006 (void *)sockaddr.sun_path - (void *)&sockaddr
1007 ) - 1; /* one byte for termination */
1008 int sock;
1009 path = luaL_checkstring(L, 1);
1010 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
1011 strcpy(sockaddr.sun_path, path);
1012 if (stat(path, &sb) == 0) {
1013 if (S_ISSOCK(sb.st_mode)) unlink(path);
1015 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1016 listener->fd = -1;
1017 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1018 sock = socket(
1019 PF_LOCAL,
1020 SOCK_STREAM | SOCK_CLOEXEC,
1022 );
1023 if (sock < 0) {
1024 moonbr_io_errmsg();
1025 lua_pushnil(L);
1026 lua_pushstring(L, errmsg);
1027 return 2;
1029 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
1030 moonbr_io_errmsg();
1031 close(sock);
1032 lua_pushnil(L);
1033 lua_pushstring(L, errmsg);
1034 return 2;
1036 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1037 moonbr_io_errmsg();
1038 close(sock);
1039 lua_pushnil(L);
1040 lua_pushstring(L, errmsg);
1041 return 2;
1043 listener->fd = sock;
1044 listener->addrfam = AF_LOCAL;
1045 listener->nonblocking = -1;
1046 return 1;
1049 static int moonbr_io_tcplisten(lua_State *L) {
1050 moonbr_io_listener_t *listener;
1051 const char *host, *port;
1052 struct addrinfo hints = { 0, };
1053 struct addrinfo *res, *addrinfo;
1054 int errcode;
1055 int sock;
1056 host = luaL_optstring(L, 1, NULL);
1057 port = luaL_checkstring(L, 2);
1058 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
1059 listener->fd = -1;
1060 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
1061 hints.ai_family = AF_UNSPEC;
1062 hints.ai_socktype = SOCK_STREAM;
1063 hints.ai_protocol = IPPROTO_TCP;
1064 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1065 errcode = getaddrinfo(host, port, &hints, &res);
1066 if (errcode) {
1067 freeaddrinfo(res);
1068 if (errcode == EAI_SYSTEM) {
1069 moonbr_io_errmsg();
1070 lua_pushnil(L);
1071 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
1072 } else {
1073 lua_pushnil(L);
1074 lua_pushstring(L, gai_strerror(errcode));
1076 return 2;
1078 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1079 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
1081 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
1082 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
1084 addrinfo = res;
1085 moonbr_io_tcpconnect_found:
1086 listener->addrfam = addrinfo->ai_family;
1087 sock = socket(
1088 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
1089 addrinfo->ai_socktype | SOCK_CLOEXEC,
1090 addrinfo->ai_protocol
1091 );
1092 if (sock < 0) {
1093 moonbr_io_errmsg();
1094 freeaddrinfo(res);
1095 lua_pushnil(L);
1096 lua_pushstring(L, errmsg);
1097 return 2;
1100 static const int reuseval = 1;
1101 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
1102 moonbr_io_errmsg();
1103 freeaddrinfo(res);
1104 close(sock);
1105 lua_pushnil(L);
1106 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
1107 return 2;
1110 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
1111 moonbr_io_errmsg();
1112 freeaddrinfo(res);
1113 close(sock);
1114 lua_pushnil(L);
1115 lua_pushstring(L, errmsg);
1116 return 2;
1118 freeaddrinfo(res);
1119 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
1120 moonbr_io_errmsg();
1121 close(sock);
1122 lua_pushnil(L);
1123 lua_pushstring(L, errmsg);
1124 return 2;
1126 listener->fd = sock;
1127 listener->nonblocking = -1;
1128 return 1;
1131 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
1132 moonbr_io_listener_t *listener;
1133 int fd;
1134 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1135 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
1136 if (listener->nonblocking != nonblocking) {
1137 int flags;
1138 flags = fcntl(listener->fd, F_GETFL, 0);
1139 if (flags == -1) {
1140 moonbr_io_errmsg();
1141 close(listener->fd);
1142 listener->fd = -1;
1143 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
1145 if (nonblocking) flags |= O_NONBLOCK;
1146 else flags &= ~O_NONBLOCK;
1147 if (fcntl(listener->fd, F_SETFL, 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 listener->nonblocking = nonblocking;
1155 while (1) {
1156 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
1157 if (fd < 0) {
1158 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1159 lua_pushboolean(L, 0);
1160 lua_pushliteral(L, "No incoming connection pending");
1161 return 2;
1162 } else if (errno != EINTR) {
1163 moonbr_io_errmsg();
1164 lua_pushnil(L);
1165 lua_pushstring(L, errmsg);
1166 return 2;
1168 } else {
1169 moonbr_io_pushhandle(L, fd);
1170 return 1;
1175 static int moonbr_io_accept(lua_State *L) {
1176 return moonbr_io_accept_impl(L, 0);
1179 static int moonbr_io_accept_nb(lua_State *L) {
1180 return moonbr_io_accept_impl(L, 1);
1183 static int moonbr_io_unlisten(lua_State *L) {
1184 moonbr_io_listener_t *listener;
1185 struct sockaddr_un addr;
1186 socklen_t addrlen;
1187 struct stat sb;
1188 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1189 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
1190 addrlen = sizeof(addr);
1191 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
1192 if (close(listener->fd)) {
1193 moonbr_io_errmsg();
1194 listener->fd = -1;
1195 if (addrlen && addrlen <= sizeof(addr)) {
1196 if (stat(addr.sun_path, &sb) == 0) {
1197 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1200 lua_pushnil(L);
1201 lua_pushstring(L, errmsg);
1202 return 2;
1204 listener->fd = -1;
1205 if (addrlen && addrlen <= sizeof(addr)) {
1206 if (stat(addr.sun_path, &sb) == 0) {
1207 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
1210 lua_pushboolean(L, 1);
1211 return 1;
1214 static int moonbr_io_listenergc(lua_State *L) {
1215 moonbr_io_listener_t *listener;
1216 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1217 if (listener->fd >= 0) close(listener->fd);
1218 listener->fd = -1;
1219 return 0;
1222 static int moonbr_io_poll(lua_State *L) {
1223 moonbr_io_handle_t *handle;
1224 moonbr_io_listener_t *listener;
1225 int fd, isnum;
1226 int nfds = 0;
1227 fd_set readfds, writefds, exceptfds;
1228 struct timeval timeout = {0, };
1229 int status;
1230 FD_ZERO(&readfds);
1231 FD_ZERO(&writefds);
1232 FD_ZERO(&exceptfds);
1233 if (!lua_isnoneornil(L, 1)) {
1234 luaL_checktype(L, 1, LUA_TTABLE);
1235 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1236 if (lua_toboolean(L, -1)) {
1237 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1238 if (handle) {
1239 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1240 fd = handle->fd;
1241 if (
1242 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1243 handle->readbufin != handle->readbufout /* data pending in buffer */
1244 ) {
1245 lua_pushboolean(L, 1);
1246 return 1;
1248 } else {
1249 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1250 if (listener) {
1251 fd = listener->fd;
1252 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1253 } else {
1254 fd = lua_tointegerx(L, -2, &isnum);
1255 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1258 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1259 FD_SET(fd, &readfds);
1260 if (fd+1 > nfds) nfds = fd+1;
1264 if (!lua_isnoneornil(L, 2)) {
1265 luaL_checktype(L, 2, LUA_TTABLE);
1266 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1267 if (lua_toboolean(L, -1)) {
1268 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1269 if (handle) {
1270 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1271 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1272 fd = handle->fd;
1273 } else {
1274 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1275 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1276 fd = lua_tointegerx(L, -2, &isnum);
1277 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1279 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
1280 FD_SET(fd, &writefds);
1281 if (fd+1 > nfds) nfds = fd+1;
1285 if (!lua_isnoneornil(L, 3)) {
1286 lua_Number n;
1287 n = lua_tonumberx(L, 3, &isnum);
1288 if (isnum && n>=0 && n<100000000) {
1289 timeout.tv_sec = n;
1290 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1291 } else {
1292 luaL_argcheck(L, 0, 3, "not a valid timeout");
1294 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1295 } else {
1296 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1298 if (status == -1) {
1299 if (errno == EINTR) {
1300 lua_pushboolean(L, 0);
1301 lua_pushliteral(L, "Signal received while polling file descriptors");
1302 return 2;
1303 } else {
1304 moonbr_io_errmsg();
1305 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1307 } else if (status == 0) {
1308 lua_pushboolean(L, 0);
1309 lua_pushliteral(L, "Timeout while polling file descriptors");
1310 return 2;
1311 } else {
1312 lua_pushboolean(L, 1);
1313 return 1;
1317 static int moonbr_io_timeref(lua_State *L) {
1318 lua_Number sub;
1319 struct timespec tp;
1320 sub = luaL_optnumber(L, 1, 0);
1321 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1322 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1324 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1325 return 1;
1328 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1329 {"read", moonbr_io_read},
1330 {"read_nb", moonbr_io_read_nb},
1331 {"read_call", moonbr_io_read_call},
1332 {"read_yield", moonbr_io_read_yield},
1333 {"drain", moonbr_io_drain},
1334 {"drain_nb", moonbr_io_drain_nb},
1335 {"drain_call", moonbr_io_drain_call},
1336 {"drain_yield", moonbr_io_drain_yield},
1337 {"write", moonbr_io_write},
1338 {"write_nb", moonbr_io_write_nb},
1339 {"write_call", moonbr_io_write_call},
1340 {"write_yield", moonbr_io_write_yield},
1341 {"flush", moonbr_io_flush},
1342 {"flush_nb", moonbr_io_flush_nb},
1343 {"flush_call", moonbr_io_flush_call},
1344 {"flush_yield", moonbr_io_flush_yield},
1345 {"finish", moonbr_io_finish},
1346 {"close", moonbr_io_close},
1347 {"reset", moonbr_io_reset},
1348 {NULL, NULL}
1349 };
1351 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1352 {"__index", moonbr_io_handleindex},
1353 {"__newindex", moonbr_io_handlenewindex},
1354 {"__gc", moonbr_io_handlegc},
1355 {NULL, NULL}
1356 };
1358 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1359 {"accept", moonbr_io_accept},
1360 {"accept_nb", moonbr_io_accept_nb},
1361 {"close", moonbr_io_unlisten},
1362 {NULL, NULL}
1363 };
1365 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1366 {"__gc", moonbr_io_listenergc},
1367 {NULL, NULL}
1368 };
1370 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1371 {"localconnect", moonbr_io_localconnect},
1372 {"localconnect_nb", moonbr_io_localconnect_nb},
1373 {"tcpconnect", moonbr_io_tcpconnect},
1374 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1375 {"locallisten", moonbr_io_locallisten},
1376 {"tcplisten", moonbr_io_tcplisten},
1377 {"poll", moonbr_io_poll},
1378 {"timeref", moonbr_io_timeref},
1379 {NULL, NULL}
1380 };
1382 int luaopen_moonbridge_io(lua_State *L) {
1384 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1386 lua_newtable(L); // module
1388 lua_newtable(L); // public metatable
1389 lua_newtable(L); // handle methods
1390 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1391 lua_pushvalue(L, -1);
1392 lua_setfield(L, -4, "prototype_handle");
1393 lua_setfield(L, -2, "__index");
1394 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1396 lua_newtable(L); // handle metatable
1397 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1398 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1400 lua_newtable(L); // listener metatable
1401 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1402 lua_newtable(L); // listener methods
1403 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1404 lua_pushvalue(L, -1);
1405 lua_setfield(L, -4, "prototype_listener");
1406 lua_setfield(L, -2, "__index");
1407 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1409 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1410 return 1;

Impressum / About Us