moonbridge
view moonbridge_io.c @ 117:d8469c1039e6
Bugfixes regarding treatment of memory allocation errors and closing file descriptors
| author | jbe |
|---|---|
| date | Fri Apr 10 02:40:43 2015 +0200 (2015-04-10) |
| parents | 2ab19e15aa6b |
| children | 118e320a7812 |
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 listener->fd = -1;
773 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
774 sock = socket(
775 PF_LOCAL,
776 SOCK_STREAM | SOCK_CLOEXEC,
777 0
778 );
779 if (sock < 0) {
780 moonbr_io_errmsg();
781 lua_pushnil(L);
782 lua_pushstring(L, errmsg);
783 return 2;
784 }
785 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
786 moonbr_io_errmsg();
787 close(sock);
788 lua_pushnil(L);
789 lua_pushstring(L, errmsg);
790 return 2;
791 }
792 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
793 moonbr_io_errmsg();
794 close(sock);
795 lua_pushnil(L);
796 lua_pushstring(L, errmsg);
797 return 2;
798 }
799 listener->fd = sock;
800 listener->nonblocking = -1;
801 return 1;
802 }
804 static int moonbr_io_tcplisten(lua_State *L) {
805 moonbr_io_listener_t *listener;
806 const char *host, *port;
807 struct addrinfo hints = { 0, };
808 struct addrinfo *res, *addrinfo;
809 int errcode;
810 int sock;
811 host = luaL_optstring(L, 1, NULL);
812 port = luaL_checkstring(L, 2);
813 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
814 listener->fd = -1;
815 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
816 hints.ai_family = AF_UNSPEC;
817 hints.ai_socktype = SOCK_STREAM;
818 hints.ai_protocol = IPPROTO_TCP;
819 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
820 errcode = getaddrinfo(host, port, &hints, &res);
821 if (errcode) {
822 freeaddrinfo(res);
823 if (errcode == EAI_SYSTEM) {
824 moonbr_io_errmsg();
825 lua_pushnil(L);
826 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
827 } else {
828 lua_pushnil(L);
829 lua_pushstring(L, gai_strerror(errcode));
830 }
831 return 2;
832 }
833 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
834 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found;
835 }
836 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
837 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found;
838 }
839 addrinfo = res;
840 moonbr_io_tcpconnect_found:
841 sock = socket(
842 addrinfo->ai_family,
843 addrinfo->ai_socktype | SOCK_CLOEXEC,
844 addrinfo->ai_protocol
845 );
846 if (sock < 0) {
847 moonbr_io_errmsg();
848 freeaddrinfo(res);
849 lua_pushnil(L);
850 lua_pushstring(L, errmsg);
851 return 2;
852 }
853 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
854 moonbr_io_errmsg();
855 freeaddrinfo(res);
856 close(sock);
857 lua_pushnil(L);
858 lua_pushstring(L, errmsg);
859 return 2;
860 }
861 freeaddrinfo(res);
862 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
863 moonbr_io_errmsg();
864 close(sock);
865 lua_pushnil(L);
866 lua_pushstring(L, errmsg);
867 return 2;
868 }
869 listener->fd = sock;
870 listener->nonblocking = -1;
871 return 1;
872 }
874 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
875 moonbr_io_listener_t *listener;
876 int fd;
877 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
878 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
879 if (listener->nonblocking != nonblocking) {
880 int flags;
881 flags = fcntl(listener->fd, F_GETFL, 0);
882 if (flags == -1) {
883 moonbr_io_errmsg();
884 close(listener->fd);
885 listener->fd = -1;
886 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
887 }
888 if (nonblocking) flags |= O_NONBLOCK;
889 else flags &= ~O_NONBLOCK;
890 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
891 moonbr_io_errmsg();
892 close(listener->fd);
893 listener->fd = -1;
894 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
895 }
896 listener->nonblocking = nonblocking;
897 }
898 while (1) {
899 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
900 if (fd < 0) {
901 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
902 lua_pushboolean(L, 0);
903 lua_pushliteral(L, "No incoming connection pending");
904 return 2;
905 } else if (errno != EINTR) {
906 moonbr_io_errmsg();
907 lua_pushnil(L);
908 lua_pushstring(L, errmsg);
909 return 2;
910 }
911 } else {
912 moonbr_io_pushhandle(L, fd);
913 return 1;
914 }
915 }
916 }
918 static int moonbr_io_accept(lua_State *L) {
919 return moonbr_io_accept_impl(L, 0);
920 }
922 static int moonbr_io_accept_nb(lua_State *L) {
923 return moonbr_io_accept_impl(L, 1);
924 }
926 static int moonbr_io_unlisten(lua_State *L) {
927 moonbr_io_listener_t *listener;
928 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
929 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
930 if (close(listener->fd)) {
931 moonbr_io_errmsg();
932 listener->fd = -1;
933 lua_pushnil(L);
934 lua_pushstring(L, errmsg);
935 return 2;
936 }
937 listener->fd = -1;
938 lua_pushboolean(L, 1);
939 return 1;
940 }
942 static int moonbr_io_listenergc(lua_State *L) {
943 moonbr_io_listener_t *listener;
944 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
945 if (listener->fd >= 0) close(listener->fd);
946 listener->fd = -1;
947 return 0;
948 }
950 static int moonbr_io_poll(lua_State *L) {
951 moonbr_io_handle_t *handle;
952 moonbr_io_listener_t *listener;
953 int fd, isnum;
954 int nfds = 0;
955 fd_set readfds, writefds, exceptfds;
956 struct timeval timeout = {0, };
957 int status;
958 FD_ZERO(&readfds);
959 FD_ZERO(&writefds);
960 FD_ZERO(&exceptfds);
961 if (!lua_isnoneornil(L, 1)) {
962 luaL_checktype(L, 1, LUA_TTABLE);
963 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
964 if (lua_toboolean(L, -1)) {
965 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
966 if (handle) {
967 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
968 fd = handle->fd;
969 if (fd < 0) { /* fake EOF to simulate shutdown */
970 lua_pushboolean(L, 1);
971 return 1;
972 }
973 } else {
974 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
975 if (listener) {
976 fd = listener->fd;
977 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
978 } else {
979 fd = lua_tointegerx(L, -2, &isnum);
980 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
981 }
982 }
983 FD_SET(fd, &readfds);
984 if (fd+1 > nfds) nfds = fd+1;
985 }
986 }
987 }
988 if (!lua_isnoneornil(L, 2)) {
989 luaL_checktype(L, 2, LUA_TTABLE);
990 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
991 if (lua_toboolean(L, -1)) {
992 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
993 if (handle) {
994 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
995 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
996 fd = handle->fd;
997 } else {
998 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
999 if (listener) luaL_error(L, "Attempt to write-poll a listener");
1000 fd = lua_tointegerx(L, -2, &isnum);
1001 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
1002 }
1003 FD_SET(fd, &writefds);
1004 if (fd+1 > nfds) nfds = fd+1;
1005 }
1006 }
1007 }
1008 if (!lua_isnoneornil(L, 3)) {
1009 lua_Number n;
1010 n = lua_tonumberx(L, 3, &isnum);
1011 if (isnum && n>=0 && n<100000000) {
1012 timeout.tv_sec = n;
1013 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
1014 } else {
1015 luaL_argcheck(L, 0, 3, "not a valid timeout");
1016 }
1017 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
1018 } else {
1019 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
1020 }
1021 if (status == -1) {
1022 if (errno == EINTR) {
1023 lua_pushboolean(L, 0);
1024 lua_pushliteral(L, "Signal received while polling file descriptors");
1025 return 2;
1026 } else {
1027 moonbr_io_errmsg();
1028 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
1029 }
1030 } else if (status == 0) {
1031 lua_pushboolean(L, 0);
1032 lua_pushliteral(L, "Timeout while polling file descriptors");
1033 return 2;
1034 } else {
1035 lua_pushboolean(L, 1);
1036 return 1;
1037 }
1038 }
1040 static int moonbr_io_timeref(lua_State *L) {
1041 lua_Number sub;
1042 struct timespec tp;
1043 sub = luaL_optnumber(L, 1, 0);
1044 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
1045 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
1046 }
1047 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
1048 return 1;
1049 }
1051 static const struct luaL_Reg moonbr_io_handle_methods[] = {
1052 {"read", moonbr_io_read},
1053 {"read_nb", moonbr_io_read_nb},
1054 {"drain", moonbr_io_drain},
1055 {"drain_nb", moonbr_io_drain_nb},
1056 {"write", moonbr_io_write},
1057 {"write_nb", moonbr_io_write_nb},
1058 {"flush", moonbr_io_flush},
1059 {"flush_nb", moonbr_io_flush_nb},
1060 {"finish", moonbr_io_finish},
1061 {"close", moonbr_io_close},
1062 {"reset", moonbr_io_reset},
1063 {NULL, NULL}
1064 };
1066 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
1067 {"__index", moonbr_io_handleindex},
1068 {"__newindex", moonbr_io_handlenewindex},
1069 {"__gc", moonbr_io_handlegc},
1070 {NULL, NULL}
1071 };
1073 static const struct luaL_Reg moonbr_io_listener_methods[] = {
1074 {"accept", moonbr_io_accept},
1075 {"accept_nb", moonbr_io_accept_nb},
1076 {"close", moonbr_io_unlisten},
1077 {NULL, NULL}
1078 };
1080 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
1081 {"__gc", moonbr_io_listenergc},
1082 {NULL, NULL}
1083 };
1085 static const struct luaL_Reg moonbr_io_module_funcs[] = {
1086 {"localconnect", moonbr_io_localconnect},
1087 {"localconnect_nb", moonbr_io_localconnect_nb},
1088 {"tcpconnect", moonbr_io_tcpconnect},
1089 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
1090 {"locallisten", moonbr_io_locallisten},
1091 {"tcplisten", moonbr_io_tcplisten},
1092 {"poll", moonbr_io_poll},
1093 {"timeref", moonbr_io_timeref},
1094 {NULL, NULL}
1095 };
1097 int luaopen_moonbridge_io(lua_State *L) {
1099 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
1101 lua_newtable(L); // module
1103 lua_newtable(L); // public metatable
1104 lua_newtable(L); // handle methods
1105 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
1106 lua_pushvalue(L, -1);
1107 lua_setfield(L, -4, "prototype_handle");
1108 lua_setfield(L, -2, "__index");
1109 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
1111 lua_newtable(L); // handle metatable
1112 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
1113 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
1115 lua_newtable(L); // listener metatable
1116 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
1117 lua_newtable(L); // listener methods
1118 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
1119 lua_pushvalue(L, -1);
1120 lua_setfield(L, -4, "prototype_listener");
1121 lua_setfield(L, -2, "__index");
1122 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
1124 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
1125 return 1;
1127 }
