moonbridge

view moonbridge_io.c @ 133:891cdc4b43eb

Revised flushing behavior of write_nb(...) again
author jbe
date Thu Apr 16 20:48:11 2015 +0200 (2015-04-16)
parents 293e666a41e0
children 11269ec33cd7
line source
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdint.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <sys/socket.h>
8 #include <sys/un.h>
9 #include <sys/select.h>
10 #include <fcntl.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #include <arpa/inet.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <netdb.h>
17 #include <signal.h>
18 #include <time.h>
20 #include <lua.h>
21 #include <lauxlib.h>
22 #include <lualib.h>
24 #define MOONBR_IO_MAXSTRERRORLEN 80
25 #define MOONBR_IO_READBUFLEN 4096
26 #define MOONBR_IO_WRITEBUFLEN 4096
28 #define MOONBR_IO_LISTEN_BACKLOG 1024
30 #define moonbr_io_errmsg() \
31 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
32 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
34 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
35 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
36 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
38 typedef struct {
39 int fd;
40 int issock;
41 sa_family_t addrfam;
42 int finished;
43 int closed;
44 int nonblocking;
45 int nopush;
46 int readerr;
47 int readbufin;
48 int readbufout;
49 int writeerr;
50 size_t writeleft;
51 size_t flushedleft;
52 #if LUA_VERSION_NUM >= 503
53 lua_Integer writeqin;
54 lua_Integer writeqout;
55 #else
56 int writeqin;
57 int writeqout;
58 #endif
59 size_t writeqoff;
60 int writebufin;
61 int writebufout;
62 char readbuf[MOONBR_IO_READBUFLEN];
63 char writebuf[MOONBR_IO_WRITEBUFLEN];
64 } moonbr_io_handle_t;
66 typedef struct {
67 int fd;
68 sa_family_t addrfam;
69 int nonblocking;
70 } moonbr_io_listener_t;
72 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
73 int flags;
74 if (handle->nonblocking == nonblocking) return;
75 flags = fcntl(handle->fd, F_GETFL, 0);
76 if (flags == -1) {
77 moonbr_io_errmsg();
78 close(handle->fd);
79 handle->fd = -1;
80 handle->closed = 1;
81 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
82 }
83 if (nonblocking) flags |= O_NONBLOCK;
84 else flags &= ~O_NONBLOCK;
85 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
86 moonbr_io_errmsg();
87 close(handle->fd);
88 handle->fd = -1;
89 handle->closed = 1;
90 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
91 }
92 handle->nonblocking = nonblocking;
93 }
95 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
96 struct linger lingerval = { 0, };
97 if (!handle->issock) return;
98 if (timeout >= 0) {
99 lingerval.l_onoff = 1;
100 lingerval.l_linger = timeout;
101 }
102 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
103 moonbr_io_errmsg();
104 close(handle->fd);
105 handle->fd = -1;
106 handle->closed = 1;
107 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
108 }
109 }
111 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
112 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
113 if (
114 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
115 handle->nopush == nopush
116 ) return;
117 #if defined(TCP_NOPUSH)
118 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
119 #elif defined(TCP_CORK)
120 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
121 #endif
122 moonbr_io_errmsg();
123 close(handle->fd);
124 handle->fd = -1;
125 handle->closed = 1;
126 #if defined(TCP_NOPUSH)
127 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
128 #elif defined(TCP_CORK)
129 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
130 #endif
131 }
132 handle->nopush = nopush;
133 #else
134 #warning Neither TCP_NOPUSH nor TCP_CORK is available
135 #endif
136 }
138 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
139 moonbr_io_handle_t *handle;
140 lua_Integer maxread;
141 const char *terminatorstr;
142 size_t terminatorlen;
143 char terminator;
144 luaL_Buffer luabuf;
145 size_t luabufcnt = 0;
146 int remaining;
147 char *terminatorpos;
148 ssize_t bytesread;
149 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
150 maxread = luaL_optinteger(L, 2, 0);
151 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
152 if (terminatorlen) {
153 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
154 terminator = terminatorstr[0];
155 }
156 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
157 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
158 if (handle->readerr) {
159 lua_pushnil(L);
160 lua_pushliteral(L, "Previous read error");
161 return 2;
162 }
163 handle->readerr = 1;
164 if (handle->fd < 0) goto moonbr_io_read_impl_eof; /* fake EOF to simulate shutdown */
165 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
166 if (!drain) luaL_buffinit(L, &luabuf);
167 while (1) {
168 remaining = -1;
169 if (
170 maxread > 0 &&
171 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
172 ) {
173 remaining = maxread - luabufcnt;
174 } else if (terminatorlen) {
175 terminatorpos = memchr(
176 handle->readbuf + handle->readbufout,
177 terminator,
178 handle->readbufin - handle->readbufout
179 );
180 if (terminatorpos) remaining = 1 + (
181 terminatorpos - (handle->readbuf + handle->readbufout)
182 );
183 }
184 if (remaining >= 0) {
185 if (!drain) {
186 luaL_addlstring(
187 &luabuf,
188 handle->readbuf + handle->readbufout,
189 remaining
190 );
191 luaL_pushresult(&luabuf);
192 } else {
193 luaL_pushresult(&luabuf);
194 lua_pop(L, 1);
195 lua_pushinteger(L, luabufcnt + remaining);
196 }
197 handle->readbufout += remaining;
198 if (handle->readbufout == handle->readbufin) {
199 handle->readbufin = 0;
200 handle->readbufout =0;
201 }
202 handle->readerr = 0;
203 return 1;
204 }
205 if (!drain) luaL_addlstring(
206 &luabuf,
207 handle->readbuf + handle->readbufout,
208 handle->readbufin - handle->readbufout
209 );
210 luabufcnt += handle->readbufin - handle->readbufout;
211 do {
212 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
213 } while (bytesread < 0 && (errno == EINTR));
214 if (
215 bytesread == 0 || (
216 nonblocking &&
217 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
218 )
219 ) {
220 handle->readbufin = 0;
221 handle->readbufout = 0;
222 if (!drain) {
223 luaL_pushresult(&luabuf);
224 if (!luabufcnt && bytesread == 0) {
225 lua_pop(L, 1);
226 moonbr_io_read_impl_eof:
227 lua_pushboolean(L, 0);
228 lua_pushliteral(L, "End of file");
229 handle->readerr = 0;
230 return 2;
231 }
232 } else {
233 if (!luabufcnt && bytesread == 0) lua_pushboolean(L, 1);
234 else lua_pushboolean(L, luabufcnt);
235 }
236 handle->readerr = 0;
237 return 1;
238 }
239 if (bytesread < 0) {
240 moonbr_io_errmsg();
241 lua_pushnil(L);
242 lua_pushstring(L, errmsg);
243 return 2;
244 }
245 handle->readbufin = bytesread;
246 handle->readbufout = 0;
247 }
248 }
250 static int moonbr_io_read(lua_State *L) {
251 return moonbr_io_read_impl(L, 0, 0);
252 }
254 static int moonbr_io_read_nb(lua_State *L) {
255 return moonbr_io_read_impl(L, 1, 0);
256 }
258 static int moonbr_io_drain(lua_State *L) {
259 return moonbr_io_read_impl(L, 0, 1);
260 }
262 static int moonbr_io_drain_nb(lua_State *L) {
263 return moonbr_io_read_impl(L, 1, 1);
264 }
266 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
267 moonbr_io_handle_t *handle;
268 int i, top;
269 const char *str;
270 size_t strlen;
271 ssize_t written;
272 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
273 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
274 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
275 if (handle->writeerr) {
276 lua_pushnil(L);
277 lua_pushliteral(L, "Previous write error");
278 return 2;
279 }
280 handle->writeerr = 1;
281 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
282 top = lua_gettop(L);
283 lua_getuservalue(L, 1);
284 lua_getfield(L, -1, "writequeue");
285 for (i=2; i<=top; i++) {
286 luaL_checklstring(L, i, &strlen);
287 lua_pushvalue(L, i);
288 lua_rawseti(L, -2, handle->writeqin++);
289 handle->writeleft += strlen;
290 }
291 if (flush) handle->flushedleft = handle->writeleft;
292 while (handle->writeqout != handle->writeqin) {
293 lua_rawgeti(L, -1, handle->writeqout);
294 str = lua_tolstring(L, -1, &strlen);
295 while (handle->writeqoff < strlen) {
296 if (
297 strlen - handle->writeqoff <
298 MOONBR_IO_WRITEBUFLEN - handle->writebufin
299 ) {
300 memcpy(
301 handle->writebuf + handle->writebufin,
302 str + handle->writeqoff,
303 strlen - handle->writeqoff
304 );
305 handle->writebufin += strlen - handle->writeqoff;
306 break;
307 } else {
308 memcpy(
309 handle->writebuf + handle->writebufin,
310 str + handle->writeqoff,
311 MOONBR_IO_WRITEBUFLEN - handle->writebufin
312 );
313 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
314 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
315 moonbr_io_handle_set_nopush(L, handle, 1);
316 written = write(
317 handle->fd,
318 handle->writebuf + handle->writebufout,
319 MOONBR_IO_WRITEBUFLEN - handle->writebufout
320 );
321 if (written < 0) {
322 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
323 goto moonbr_io_write_impl_block;
324 } else if (errno != EINTR) {
325 moonbr_io_errmsg();
326 lua_pushnil(L);
327 lua_pushstring(L, errmsg);
328 return 2;
329 }
330 } else {
331 handle->writebufout += written;
332 handle->writeleft -= written;
333 if (handle->flushedleft) {
334 if (written >= handle->flushedleft) {
335 handle->flushedleft = 0;
336 moonbr_io_handle_set_nopush(L, handle, 0);
337 } else {
338 handle->flushedleft -= written;
339 }
340 }
341 }
342 }
343 handle->writebufin = 0;
344 handle->writebufout = 0;
345 }
346 }
347 handle->writeqoff = 0;
348 lua_pop(L, 1);
349 lua_pushnil(L);
350 lua_rawseti(L, -2, handle->writeqout++);
351 }
352 while (handle->flushedleft) {
353 moonbr_io_handle_set_nopush(L, handle, 1);
354 written = write(
355 handle->fd,
356 handle->writebuf + handle->writebufout,
357 handle->writebufin - handle->writebufout
358 );
359 if (written < 0) {
360 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
361 goto moonbr_io_write_impl_block;
362 } else if (errno != EINTR) {
363 moonbr_io_errmsg();
364 lua_pushnil(L);
365 lua_pushstring(L, errmsg);
366 return 2;
367 }
368 } else {
369 handle->writebufout += written;
370 handle->writeleft -= written;
371 if (handle->flushedleft) {
372 if (written >= handle->flushedleft) {
373 handle->flushedleft = 0;
374 moonbr_io_handle_set_nopush(L, handle, 0);
375 } else {
376 handle->flushedleft -= written;
377 }
378 }
379 }
380 }
381 if (handle->writebufout == handle->writebufin) {
382 handle->writebufin = 0;
383 handle->writebufout = 0;
384 }
385 if (nonblocking) lua_pushinteger(L, 0);
386 else lua_pushvalue(L, 1);
387 handle->writeerr = 0;
388 return 1;
389 moonbr_io_write_impl_block:
390 lua_pushinteger(L, handle->writeleft);
391 handle->writeerr = 0;
392 return 1;
393 }
395 static int moonbr_io_write(lua_State *L) {
396 return moonbr_io_write_impl(L, 0, 0);
397 }
399 static int moonbr_io_write_nb(lua_State *L) {
400 return moonbr_io_write_impl(L, 1, 0);
401 }
403 static int moonbr_io_flush(lua_State *L) {
404 return moonbr_io_write_impl(L, 0, 1);
405 }
407 static int moonbr_io_flush_nb(lua_State *L) {
408 return moonbr_io_write_impl(L, 1, 1);
409 }
411 static int moonbr_io_finish(lua_State *L) {
412 moonbr_io_handle_t *handle;
413 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
414 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
415 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
416 if (handle->writeleft) {
417 lua_pushcfunction(L, moonbr_io_flush);
418 lua_pushvalue(L, 1);
419 if (lua_pcall(L, 1, 2, 0)) {
420 handle->finished = 1;
421 lua_error(L);
422 }
423 if (!lua_toboolean(L, -2)) {
424 handle->finished = 1;
425 return 2;
426 }
427 }
428 handle->finished = 1;
429 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
430 if (shutdown(handle->fd, SHUT_WR)) {
431 moonbr_io_errmsg();
432 lua_pushnil(L);
433 lua_pushstring(L, errmsg);
434 return 2;
435 }
436 } else {
437 if (close(handle->fd)) {
438 moonbr_io_errmsg();
439 handle->fd = -1;
440 lua_pushnil(L);
441 lua_pushstring(L, errmsg);
442 return 2;
443 }
444 handle->fd = -1; /* fake EOF on read */
445 }
446 lua_pushboolean(L, 1);
447 return 1;
448 }
450 static int moonbr_io_close_impl(lua_State *L, int reset) {
451 moonbr_io_handle_t *handle;
452 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
453 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
454 if (!reset) {
455 if (handle->writeleft) {
456 lua_pushcfunction(L, moonbr_io_flush);
457 lua_pushvalue(L, 1);
458 if (lua_pcall(L, 1, 2, 0)) {
459 handle->closed = 1;
460 close(handle->fd);
461 handle->fd = -1;
462 lua_error(L);
463 }
464 handle->closed = 1;
465 if (!lua_toboolean(L, -2)) {
466 close(handle->fd);
467 handle->fd = -1;
468 return 2;
469 }
470 } else {
471 handle->closed = 1;
472 moonbr_io_handle_set_linger(L, handle, -1);
473 }
474 } else {
475 handle->closed = 1;
476 }
477 if (handle->fd >= 0) {
478 if (close(handle->fd)) {
479 moonbr_io_errmsg();
480 handle->fd = -1;
481 lua_pushnil(L);
482 lua_pushstring(L, errmsg);
483 return 2;
484 }
485 handle->fd = -1;
486 }
487 lua_pushboolean(L, 1);
488 return 1;
490 }
492 static int moonbr_io_close(lua_State *L) {
493 return moonbr_io_close_impl(L, 0);
494 }
496 static int moonbr_io_reset(lua_State *L) {
497 return moonbr_io_close_impl(L, 1);
498 }
500 static int moonbr_io_handlegc(lua_State *L) {
501 moonbr_io_handle_t *handle;
502 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
503 if (handle->fd >= 0) {
504 lua_pushcfunction(L, moonbr_io_close);
505 lua_pushvalue(L, 1);
506 lua_pushinteger(L, 0);
507 lua_call(L, 2, 0);
508 }
509 return 0;
510 }
512 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
513 moonbr_io_handle_t *handle;
514 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
515 if (!handle->closed) {
516 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
517 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
518 lua_call(L, 1, 0);
519 }
520 }
522 void moonbr_io_pushhandle(lua_State *L, int fd) {
523 moonbr_io_handle_t *handle;
524 struct sockaddr addr;
525 socklen_t addrlen;
526 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
527 handle->fd = fd;
528 addrlen = sizeof(addr);
529 if (getsockname(fd, &addr, &addrlen)) {
530 if (errno != ENOTSOCK) {
531 moonbr_io_errmsg();
532 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
533 }
534 handle->issock = 0;
535 } else {
536 handle->issock = 1;
537 handle->addrfam = addr.sa_family;
538 }
539 handle->finished = 0;
540 handle->closed = 0;
541 handle->nonblocking = -1;
542 handle->nopush = -1;
543 handle->readerr = 0;
544 handle->readbufin = 0;
545 handle->readbufout = 0;
546 handle->writeerr = 0;
547 handle->writeleft = 0;
548 handle->flushedleft = 0;
549 handle->writeqin = 0;
550 handle->writeqout = 0;
551 handle->writeqoff = 0;
552 handle->writebufin = 0;
553 handle->writebufout = 0;
554 moonbr_io_handle_set_linger(L, handle, 0);
555 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
556 lua_setmetatable(L, -2);
557 lua_newtable(L); // uservalue
558 lua_newtable(L);
559 lua_setfield(L, -2, "writequeue");
560 lua_newtable(L); // public
561 if (handle->addrfam == AF_INET6) {
562 struct sockaddr_in6 addr_in6;
563 char addrstrbuf[INET6_ADDRSTRLEN];
564 const char *addrstr;
565 addrlen = sizeof(addr_in6);
566 if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
567 moonbr_io_errmsg();
568 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
569 }
570 if (addrlen > sizeof(addr_in6)) {
571 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
572 }
573 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
574 if (!addrstr) {
575 moonbr_io_errmsg();
576 luaL_error(L, "Could not format local IP address: %s", errmsg);
577 } else {
578 lua_pushstring(L, addrstr);
579 lua_setfield(L, -2, "local_ip6");
580 }
581 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
582 lua_setfield(L, -2, "local_tcpport");
583 if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) {
584 moonbr_io_errmsg();
585 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
586 }
587 if (addrlen > sizeof(addr_in6)) {
588 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
589 }
590 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
591 if (!addrstr) {
592 moonbr_io_errmsg();
593 luaL_error(L, "Could not format remote IP address: %s", errmsg);
594 } else {
595 lua_pushstring(L, addrstr);
596 lua_setfield(L, -2, "remote_ip6");
597 }
598 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
599 lua_setfield(L, -2, "remote_tcpport");
600 } else if (handle->addrfam == AF_INET) {
601 struct sockaddr_in addr_in;
602 char addrstrbuf[INET_ADDRSTRLEN];
603 const char *addrstr;
604 addrlen = sizeof(addr_in);
605 if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) {
606 moonbr_io_errmsg();
607 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
608 }
609 if (addrlen > sizeof(addr_in)) {
610 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
611 }
612 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
613 if (!addrstr) {
614 moonbr_io_errmsg();
615 luaL_error(L, "Could not format local IP address: %s", errmsg);
616 } else {
617 lua_pushstring(L, addrstr);
618 lua_setfield(L, -2, "local_ip4");
619 }
620 lua_pushinteger(L, ntohs(addr_in.sin_port));
621 lua_setfield(L, -2, "local_tcpport");
622 if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) {
623 moonbr_io_errmsg();
624 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
625 }
626 if (addrlen > sizeof(addr_in)) {
627 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
628 }
629 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
630 if (!addrstr) {
631 moonbr_io_errmsg();
632 luaL_error(L, "Could not format remote IP address: %s", errmsg);
633 } else {
634 lua_pushstring(L, addrstr);
635 lua_setfield(L, -2, "remote_ip4");
636 }
637 lua_pushinteger(L, ntohs(addr_in.sin_port));
638 lua_setfield(L, -2, "remote_tcpport");
639 }
640 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
641 lua_setmetatable(L, -2);
642 lua_setfield(L, -2, "public");
643 lua_setuservalue(L, -2);
644 }
646 static int moonbr_io_handleindex(lua_State *L) {
647 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
648 lua_getuservalue(L, 1);
649 lua_getfield(L, -1, "public");
650 lua_pushvalue(L, 2);
651 lua_gettable(L, -2);
652 return 1;
653 }
655 static int moonbr_io_handlenewindex(lua_State *L) {
656 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
657 lua_getuservalue(L, 1);
658 lua_getfield(L, -1, "public");
659 lua_pushvalue(L, 2);
660 lua_pushvalue(L, 3);
661 lua_settable(L, -3);
662 return 0;
663 }
665 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
666 const char *path;
667 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
668 const int path_maxlen = sizeof(struct sockaddr_un) - (
669 (void *)sockaddr.sun_path - (void *)&sockaddr
670 ) - 1; /* one byte for termination */
671 int sock;
672 path = luaL_checkstring(L, 1);
673 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
674 strcpy(sockaddr.sun_path, path);
675 sock = socket(
676 PF_LOCAL,
677 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
678 0
679 );
680 if (sock < 0) {
681 moonbr_io_errmsg();
682 lua_pushnil(L);
683 lua_pushstring(L, errmsg);
684 return 2;
685 }
686 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
687 if (!nonblocking && errno == EINTR) {
688 moonbr_io_errmsg();
689 close(sock);
690 lua_pushnil(L);
691 lua_pushstring(L, errmsg);
692 return 2;
693 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
694 moonbr_io_errmsg();
695 lua_pushnil(L);
696 lua_pushstring(L, errmsg);
697 return 2;
698 }
699 }
700 moonbr_io_pushhandle(L, sock);
701 return 1;
702 }
704 static int moonbr_io_localconnect(lua_State *L) {
705 return moonbr_io_localconnect_impl(L, 0);
706 }
708 static int moonbr_io_localconnect_nb(lua_State *L) {
709 return moonbr_io_localconnect_impl(L, 1);
710 }
712 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
713 const char *host, *port;
714 struct addrinfo hints = { 0, };
715 struct addrinfo *res, *addrinfo;
716 int errcode;
717 int sock;
718 host = luaL_checkstring(L, 1);
719 port = luaL_checkstring(L, 2);
720 hints.ai_family = AF_UNSPEC;
721 hints.ai_socktype = SOCK_STREAM;
722 hints.ai_protocol = IPPROTO_TCP;
723 hints.ai_flags = AI_ADDRCONFIG;
724 errcode = getaddrinfo(host, port, &hints, &res);
725 if (errcode) {
726 freeaddrinfo(res);
727 if (errcode == EAI_SYSTEM) {
728 moonbr_io_errmsg();
729 lua_pushnil(L);
730 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
731 } else {
732 lua_pushnil(L);
733 lua_pushstring(L, gai_strerror(errcode));
734 }
735 return 2;
736 }
737 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
738 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found;
739 }
740 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
741 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found;
742 }
743 addrinfo = res;
744 moonbr_io_tcpconnect_found:
745 sock = socket(
746 addrinfo->ai_family,
747 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
748 addrinfo->ai_protocol
749 );
750 if (sock < 0) {
751 moonbr_io_errmsg();
752 freeaddrinfo(res);
753 lua_pushnil(L);
754 lua_pushstring(L, errmsg);
755 return 2;
756 }
757 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
758 freeaddrinfo(res);
759 if (!nonblocking && errno == EINTR) {
760 moonbr_io_errmsg();
761 close(sock);
762 lua_pushnil(L);
763 lua_pushstring(L, errmsg);
764 return 2;
765 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
766 moonbr_io_errmsg();
767 lua_pushnil(L);
768 lua_pushstring(L, errmsg);
769 return 2;
770 }
771 } else {
772 freeaddrinfo(res);
773 }
774 moonbr_io_pushhandle(L, sock);
775 return 1;
776 }
778 static int moonbr_io_tcpconnect(lua_State *L) {
779 return moonbr_io_tcpconnect_impl(L, 0);
780 }
782 static int moonbr_io_tcpconnect_nb(lua_State *L) {
783 return moonbr_io_tcpconnect_impl(L, 1);
784 }
786 static int moonbr_io_locallisten(lua_State *L) {
787 moonbr_io_listener_t *listener;
788 const char *path;
789 struct stat sb;
790 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
791 const int path_maxlen = sizeof(struct sockaddr_un) - (
792 (void *)sockaddr.sun_path - (void *)&sockaddr
793 ) - 1; /* one byte for termination */
794 int sock;
795 path = luaL_checkstring(L, 1);
796 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
797 strcpy(sockaddr.sun_path, path);
798 if (stat(path, &sb) == 0) {
799 if (S_ISSOCK(sb.st_mode)) unlink(path);
800 }
801 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
802 listener->fd = -1;
803 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
804 sock = socket(
805 PF_LOCAL,
806 SOCK_STREAM | SOCK_CLOEXEC,
807 0
808 );
809 if (sock < 0) {
810 moonbr_io_errmsg();
811 lua_pushnil(L);
812 lua_pushstring(L, errmsg);
813 return 2;
814 }
815 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
816 moonbr_io_errmsg();
817 close(sock);
818 lua_pushnil(L);
819 lua_pushstring(L, errmsg);
820 return 2;
821 }
822 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
823 moonbr_io_errmsg();
824 close(sock);
825 lua_pushnil(L);
826 lua_pushstring(L, errmsg);
827 return 2;
828 }
829 listener->fd = sock;
830 listener->addrfam = AF_LOCAL;
831 listener->nonblocking = -1;
832 return 1;
833 }
835 static int moonbr_io_tcplisten(lua_State *L) {
836 moonbr_io_listener_t *listener;
837 const char *host, *port;
838 struct addrinfo hints = { 0, };
839 struct addrinfo *res, *addrinfo;
840 int errcode;
841 int sock;
842 host = luaL_optstring(L, 1, NULL);
843 port = luaL_checkstring(L, 2);
844 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
845 listener->fd = -1;
846 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
847 hints.ai_family = AF_UNSPEC;
848 hints.ai_socktype = SOCK_STREAM;
849 hints.ai_protocol = IPPROTO_TCP;
850 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
851 errcode = getaddrinfo(host, port, &hints, &res);
852 if (errcode) {
853 freeaddrinfo(res);
854 if (errcode == EAI_SYSTEM) {
855 moonbr_io_errmsg();
856 lua_pushnil(L);
857 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
858 } else {
859 lua_pushnil(L);
860 lua_pushstring(L, gai_strerror(errcode));
861 }
862 return 2;
863 }
864 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
865 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found;
866 }
867 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
868 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found;
869 }
870 addrinfo = res;
871 moonbr_io_tcpconnect_found:
872 listener->addrfam = addrinfo->ai_family;
873 sock = socket(
874 addrinfo->ai_family,
875 addrinfo->ai_socktype | SOCK_CLOEXEC,
876 addrinfo->ai_protocol
877 );
878 if (sock < 0) {
879 moonbr_io_errmsg();
880 freeaddrinfo(res);
881 lua_pushnil(L);
882 lua_pushstring(L, errmsg);
883 return 2;
884 }
885 {
886 static const int reuseval = 1;
887 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
888 moonbr_io_errmsg();
889 freeaddrinfo(res);
890 close(sock);
891 lua_pushnil(L);
892 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
893 return 2;
894 }
895 }
896 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
897 moonbr_io_errmsg();
898 freeaddrinfo(res);
899 close(sock);
900 lua_pushnil(L);
901 lua_pushstring(L, errmsg);
902 return 2;
903 }
904 freeaddrinfo(res);
905 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
906 moonbr_io_errmsg();
907 close(sock);
908 lua_pushnil(L);
909 lua_pushstring(L, errmsg);
910 return 2;
911 }
912 listener->fd = sock;
913 listener->nonblocking = -1;
914 return 1;
915 }
917 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
918 moonbr_io_listener_t *listener;
919 int fd;
920 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
921 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
922 if (listener->nonblocking != nonblocking) {
923 int flags;
924 flags = fcntl(listener->fd, F_GETFL, 0);
925 if (flags == -1) {
926 moonbr_io_errmsg();
927 close(listener->fd);
928 listener->fd = -1;
929 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
930 }
931 if (nonblocking) flags |= O_NONBLOCK;
932 else flags &= ~O_NONBLOCK;
933 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
934 moonbr_io_errmsg();
935 close(listener->fd);
936 listener->fd = -1;
937 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
938 }
939 listener->nonblocking = nonblocking;
940 }
941 while (1) {
942 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
943 if (fd < 0) {
944 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
945 lua_pushboolean(L, 0);
946 lua_pushliteral(L, "No incoming connection pending");
947 return 2;
948 } else if (errno != EINTR) {
949 moonbr_io_errmsg();
950 lua_pushnil(L);
951 lua_pushstring(L, errmsg);
952 return 2;
953 }
954 } else {
955 moonbr_io_pushhandle(L, fd);
956 return 1;
957 }
958 }
959 }
961 static int moonbr_io_accept(lua_State *L) {
962 return moonbr_io_accept_impl(L, 0);
963 }
965 static int moonbr_io_accept_nb(lua_State *L) {
966 return moonbr_io_accept_impl(L, 1);
967 }
969 static int moonbr_io_unlisten(lua_State *L) {
970 moonbr_io_listener_t *listener;
971 struct sockaddr_un addr;
972 socklen_t addrlen;
973 struct stat sb;
974 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
975 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
976 addrlen = sizeof(addr);
977 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
978 if (close(listener->fd)) {
979 moonbr_io_errmsg();
980 listener->fd = -1;
981 if (addrlen && addrlen <= sizeof(addr)) {
982 if (stat(addr.sun_path, &sb) == 0) {
983 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
984 }
985 }
986 lua_pushnil(L);
987 lua_pushstring(L, errmsg);
988 return 2;
989 }
990 listener->fd = -1;
991 if (addrlen && addrlen <= sizeof(addr)) {
992 if (stat(addr.sun_path, &sb) == 0) {
993 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
994 }
995 }
996 lua_pushboolean(L, 1);
997 return 1;
998 }
1000 static int moonbr_io_listenergc(lua_State *L) {
1001 moonbr_io_listener_t *listener;
1002 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
1003 if (listener->fd >= 0) close(listener->fd);
1004 listener->fd = -1;
1005 return 0;
1008 static int moonbr_io_poll(lua_State *L) {
1009 moonbr_io_handle_t *handle;
1010 moonbr_io_listener_t *listener;
1011 int fd, isnum;
1012 int nfds = 0;
1013 fd_set readfds, writefds, exceptfds;
1014 struct timeval timeout = {0, };
1015 int status;
1016 FD_ZERO(&readfds);
1017 FD_ZERO(&writefds);
1018 FD_ZERO(&exceptfds);
1019 if (!lua_isnoneornil(L, 1)) {
1020 luaL_checktype(L, 1, LUA_TTABLE);
1021 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
1022 if (lua_toboolean(L, -1)) {
1023 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1024 if (handle) {
1025 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1026 fd = handle->fd;
1027 if (
1028 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
1029 handle->readbufin != handle->readbufout /* data pending in buffer */
1030 ) {
1031 lua_pushboolean(L, 1);
1032 return 1;
1034 } else {
1035 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1036 if (listener) {
1037 fd = listener->fd;
1038 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
1039 } else {
1040 fd = lua_tointegerx(L, -2, &isnum);
1041 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
1044 FD_SET(fd, &readfds);
1045 if (fd+1 > nfds) nfds = fd+1;
1049 if (!lua_isnoneornil(L, 2)) {
1050 luaL_checktype(L, 2, LUA_TTABLE);
1051 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
1052 if (lua_toboolean(L, -1)) {
1053 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
1054 if (handle) {
1055 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
1056 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
1057 fd = handle->fd;
1058 } else {
1059 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
1060 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1061 fd = lua_tointegerx(L, -2, &isnum);
1062 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1064 FD_SET(fd, &writefds);
1065 if (fd+1 > nfds) nfds = fd+1;
1069 if (!lua_isnoneornil(L, 3)) {
1070 lua_Number n;
1071 n = lua_tonumberx(L, 3, &isnum);
1072 if (isnum && n>=0 && n<100000000) {
1073 timeout.tv_sec = n;
1074 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1075 } else {
1076 luaL_argcheck(L, 0, 3, "not a valid timeout");
1078 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1079 } else {
1080 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1082 if (status == -1) {
1083 if (errno == EINTR) {
1084 lua_pushboolean(L, 0);
1085 lua_pushliteral(L, "Signal received while polling file descriptors");
1086 return 2;
1087 } else {
1088 moonbr_io_errmsg();
1089 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1091 } else if (status == 0) {
1092 lua_pushboolean(L, 0);
1093 lua_pushliteral(L, "Timeout while polling file descriptors");
1094 return 2;
1095 } else {
1096 lua_pushboolean(L, 1);
1097 return 1;
1101 static int moonbr_io_timeref(lua_State *L) {
1102 lua_Number sub;
1103 struct timespec tp;
1104 sub = luaL_optnumber(L, 1, 0);
1105 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1106 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1108 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1109 return 1;
1112 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1113 {"read", moonbr_io_read},
1114 {"read_nb", moonbr_io_read_nb},
1115 {"drain", moonbr_io_drain},
1116 {"drain_nb", moonbr_io_drain_nb},
1117 {"write", moonbr_io_write},
1118 {"write_nb", moonbr_io_write_nb},
1119 {"flush", moonbr_io_flush},
1120 {"flush_nb", moonbr_io_flush_nb},
1121 {"finish", moonbr_io_finish},
1122 {"close", moonbr_io_close},
1123 {"reset", moonbr_io_reset},
1124 {NULL, NULL}
1125 };
1127 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1128 {"__index", moonbr_io_handleindex},
1129 {"__newindex", moonbr_io_handlenewindex},
1130 {"__gc", moonbr_io_handlegc},
1131 {NULL, NULL}
1132 };
1134 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1135 {"accept", moonbr_io_accept},
1136 {"accept_nb", moonbr_io_accept_nb},
1137 {"close", moonbr_io_unlisten},
1138 {NULL, NULL}
1139 };
1141 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1142 {"__gc", moonbr_io_listenergc},
1143 {NULL, NULL}
1144 };
1146 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1147 {"localconnect", moonbr_io_localconnect},
1148 {"localconnect_nb", moonbr_io_localconnect_nb},
1149 {"tcpconnect", moonbr_io_tcpconnect},
1150 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1151 {"locallisten", moonbr_io_locallisten},
1152 {"tcplisten", moonbr_io_tcplisten},
1153 {"poll", moonbr_io_poll},
1154 {"timeref", moonbr_io_timeref},
1155 {NULL, NULL}
1156 };
1158 int luaopen_moonbridge_io(lua_State *L) {
1160 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1162 lua_newtable(L); // module
1164 lua_newtable(L); // public metatable
1165 lua_newtable(L); // handle methods
1166 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1167 lua_pushvalue(L, -1);
1168 lua_setfield(L, -4, "prototype_handle");
1169 lua_setfield(L, -2, "__index");
1170 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1172 lua_newtable(L); // handle metatable
1173 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1174 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1176 lua_newtable(L); // listener metatable
1177 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1178 lua_newtable(L); // listener methods
1179 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1180 lua_pushvalue(L, -1);
1181 lua_setfield(L, -4, "prototype_listener");
1182 lua_setfield(L, -2, "__index");
1183 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1185 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1186 return 1;

Impressum / About Us