moonbridge

annotate moonbridge_io.c @ 108:110493d29f90

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

Impressum / About Us