moonbridge

view moonbridge_io.c @ 109:a14e0eb8598b

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

Impressum / About Us