moonbridge

view moonbridge_io.c @ 114:0eba766e9be2

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

Impressum / About Us