moonbridge

view moonbridge_io.c @ 143:41da87a681d6

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

Impressum / About Us