moonbridge

view moonbridge_io.c @ 135:795bc86be569

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

Impressum / About Us