moonbridge

view moonbridge_io.c @ 116:2ab19e15aa6b

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

Impressum / About Us