moonbridge

annotate moonbridge_io.c @ 106:8fce76ef321f

Added moonbridge_io.poll(...)
author jbe
date Wed Apr 08 20:38:18 2015 +0200 (2015-04-08)
parents 11d03470ef19
children 06d965df8a0c
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@98 12 #include <sys/types.h>
jbe@98 13 #include <netdb.h>
jbe@79 14
jbe@79 15 #include <lua.h>
jbe@79 16 #include <lauxlib.h>
jbe@79 17 #include <lualib.h>
jbe@79 18
jbe@80 19 #define MOONBR_IO_MAXSTRERRORLEN 80
jbe@85 20 #define MOONBR_IO_READBUFLEN 4096
jbe@80 21 #define MOONBR_IO_WRITEBUFLEN 4096
jbe@80 22
jbe@80 23 #define moonbr_io_errmsg() \
jbe@80 24 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
jbe@80 25 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
jbe@80 26
jbe@79 27 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
jbe@79 28 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
jbe@79 29
jbe@79 30 typedef struct {
jbe@79 31 int fd;
jbe@95 32 int isnetwork;
jbe@94 33 int finished;
jbe@94 34 int closed;
jbe@81 35 int nonblocking;
jbe@95 36 int nopush;
jbe@85 37 int readerr;
jbe@105 38 int readbufin;
jbe@105 39 int readbufout;
jbe@81 40 int writeerr;
jbe@83 41 size_t writeleft;
jbe@83 42 #if LUA_VERSION_NUM >= 503
jbe@83 43 lua_Integer writeqin;
jbe@83 44 lua_Integer writeqout;
jbe@83 45 #else
jbe@83 46 int writeqin;
jbe@83 47 int writeqout;
jbe@83 48 #endif
jbe@83 49 size_t writeqoff;
jbe@103 50 int writebufin;
jbe@103 51 int writebufout;
jbe@85 52 char readbuf[MOONBR_IO_READBUFLEN];
jbe@80 53 char writebuf[MOONBR_IO_WRITEBUFLEN];
jbe@79 54 } moonbr_io_handle_t;
jbe@79 55
jbe@81 56 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
jbe@95 57 int flags;
jbe@95 58 if (handle->nonblocking == nonblocking) return;
jbe@95 59 flags = fcntl(handle->fd, F_GETFL, 0);
jbe@95 60 if (flags == -1) {
jbe@95 61 moonbr_io_errmsg();
jbe@96 62 close(handle->fd);
jbe@96 63 handle->fd = -1;
jbe@96 64 handle->closed = 1;
jbe@95 65 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@81 66 }
jbe@95 67 if (nonblocking) flags |= O_NONBLOCK;
jbe@95 68 else flags &= ~O_NONBLOCK;
jbe@95 69 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
jbe@95 70 moonbr_io_errmsg();
jbe@96 71 close(handle->fd);
jbe@96 72 handle->fd = -1;
jbe@96 73 handle->closed = 1;
jbe@95 74 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@95 75 }
jbe@95 76 handle->nonblocking = nonblocking;
jbe@81 77 }
jbe@81 78
jbe@87 79 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
jbe@87 80 struct linger lingerval = { 0, };
jbe@95 81 if (!handle->isnetwork) return;
jbe@87 82 if (timeout >= 0) {
jbe@87 83 lingerval.l_onoff = 1;
jbe@87 84 lingerval.l_linger = timeout;
jbe@87 85 }
jbe@87 86 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
jbe@87 87 moonbr_io_errmsg();
jbe@96 88 close(handle->fd);
jbe@96 89 handle->fd = -1;
jbe@96 90 handle->closed = 1;
jbe@95 91 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
jbe@87 92 }
jbe@87 93 }
jbe@87 94
jbe@95 95 static void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
jbe@96 96 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
jbe@95 97 if (!handle->isnetwork || handle->nopush == nopush) return;
jbe@96 98 #if defined(TCP_NOPUSH)
jbe@96 99 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
jbe@104 100 #elif defined(TCP_CORK)
jbe@104 101 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
jbe@104 102 #endif
jbe@96 103 moonbr_io_errmsg();
jbe@96 104 close(handle->fd);
jbe@96 105 handle->fd = -1;
jbe@96 106 handle->closed = 1;
jbe@104 107 #if defined(TCP_NOPUSH)
jbe@96 108 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
jbe@96 109 #elif defined(TCP_CORK)
jbe@95 110 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
jbe@104 111 #endif
jbe@95 112 }
jbe@95 113 handle->nopush = nopush;
jbe@96 114 #else
jbe@96 115 #warning Neither TCP_NOPUSH nor TCP_CORK is available
jbe@96 116 #endif
jbe@95 117 }
jbe@95 118
jbe@86 119 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
jbe@85 120 moonbr_io_handle_t *handle;
jbe@85 121 lua_Integer maxread;
jbe@85 122 const char *terminatorstr;
jbe@85 123 size_t terminatorlen;
jbe@85 124 char terminator;
jbe@85 125 luaL_Buffer luabuf;
jbe@85 126 size_t luabufcnt = 0;
jbe@105 127 int remaining;
jbe@85 128 char *terminatorpos;
jbe@103 129 ssize_t bytesread;
jbe@85 130 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@85 131 maxread = luaL_optinteger(L, 2, 0);
jbe@85 132 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
jbe@85 133 if (terminatorlen) {
jbe@85 134 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
jbe@85 135 terminator = terminatorstr[0];
jbe@85 136 }
jbe@86 137 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
jbe@94 138 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
jbe@85 139 if (handle->readerr) {
jbe@85 140 lua_pushnil(L);
jbe@85 141 lua_pushliteral(L, "Previous read error");
jbe@85 142 return 2;
jbe@85 143 }
jbe@105 144 handle->readerr = 1;
jbe@104 145 if (handle->fd < 0) goto moonbr_io_read_impl_eof; /* fake EOF to simulate shutdown */
jbe@85 146 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
jbe@86 147 if (!drain) luaL_buffinit(L, &luabuf);
jbe@85 148 while (1) {
jbe@105 149 remaining = -1;
jbe@105 150 if (
jbe@105 151 maxread > 0 &&
jbe@105 152 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
jbe@105 153 ) {
jbe@105 154 remaining = maxread - luabufcnt;
jbe@85 155 } else if (terminatorlen) {
jbe@105 156 terminatorpos = memchr(
jbe@105 157 handle->readbuf + handle->readbufout,
jbe@105 158 terminator,
jbe@105 159 handle->readbufin - handle->readbufout
jbe@105 160 );
jbe@105 161 if (terminatorpos) remaining = 1 + (
jbe@105 162 terminatorpos - (handle->readbuf + handle->readbufout)
jbe@105 163 );
jbe@85 164 }
jbe@105 165 if (remaining >= 0) {
jbe@86 166 if (!drain) {
jbe@105 167 luaL_addlstring(
jbe@105 168 &luabuf,
jbe@105 169 handle->readbuf + handle->readbufout,
jbe@105 170 remaining
jbe@105 171 );
jbe@86 172 luaL_pushresult(&luabuf);
jbe@90 173 } else {
jbe@105 174 luaL_pushresult(&luabuf);
jbe@105 175 lua_pop(L, 1);
jbe@105 176 lua_pushinteger(L, luabufcnt + remaining);
jbe@86 177 }
jbe@105 178 handle->readbufout += remaining;
jbe@105 179 if (handle->readbufout == handle->readbufin) {
jbe@105 180 handle->readbufin = 0;
jbe@105 181 handle->readbufout =0;
jbe@105 182 }
jbe@104 183 handle->readerr = 0;
jbe@85 184 return 1;
jbe@85 185 }
jbe@105 186 if (!drain) luaL_addlstring(
jbe@105 187 &luabuf,
jbe@105 188 handle->readbuf + handle->readbufout,
jbe@105 189 handle->readbufin - handle->readbufout
jbe@105 190 );
jbe@105 191 luabufcnt += handle->readbufin - handle->readbufout;
jbe@85 192 do {
jbe@103 193 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
jbe@103 194 } while (bytesread < 0 && (errno == EINTR));
jbe@105 195 if (
jbe@105 196 bytesread == 0 || (
jbe@105 197 nonblocking &&
jbe@105 198 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
jbe@105 199 )
jbe@105 200 ) {
jbe@105 201 handle->readbufin = 0;
jbe@105 202 handle->readbufout = 0;
jbe@105 203 if (!drain) {
jbe@105 204 luaL_pushresult(&luabuf);
jbe@105 205 if (!luabufcnt && bytesread == 0) {
jbe@105 206 lua_pop(L, 1);
jbe@105 207 moonbr_io_read_impl_eof:
jbe@105 208 lua_pushboolean(L, 0);
jbe@105 209 lua_pushliteral(L, "End of file");
jbe@105 210 handle->readerr = 0;
jbe@105 211 return 2;
jbe@105 212 }
jbe@105 213 } else {
jbe@105 214 if (!luabufcnt && bytesread == 0) lua_pushboolean(L, 1);
jbe@105 215 else lua_pushboolean(L, luabufcnt);
jbe@105 216 }
jbe@105 217 handle->readerr = 0;
jbe@105 218 return 1;
jbe@105 219 }
jbe@103 220 if (bytesread < 0) {
jbe@85 221 moonbr_io_errmsg();
jbe@85 222 lua_pushnil(L);
jbe@85 223 lua_pushstring(L, errmsg);
jbe@85 224 return 2;
jbe@85 225 }
jbe@105 226 handle->readbufin = bytesread;
jbe@105 227 handle->readbufout = 0;
jbe@86 228 }
jbe@85 229 }
jbe@85 230
jbe@85 231 static int moonbr_io_read(lua_State *L) {
jbe@86 232 return moonbr_io_read_impl(L, 0, 0);
jbe@85 233 }
jbe@85 234
jbe@85 235 static int moonbr_io_read_nb(lua_State *L) {
jbe@86 236 return moonbr_io_read_impl(L, 1, 0);
jbe@86 237 }
jbe@86 238
jbe@86 239 static int moonbr_io_drain(lua_State *L) {
jbe@86 240 return moonbr_io_read_impl(L, 0, 1);
jbe@86 241 }
jbe@86 242
jbe@86 243 static int moonbr_io_drain_nb(lua_State *L) {
jbe@86 244 return moonbr_io_read_impl(L, 1, 1);
jbe@85 245 }
jbe@85 246
jbe@81 247 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
jbe@80 248 moonbr_io_handle_t *handle;
jbe@80 249 int i, top;
jbe@80 250 const char *str;
jbe@92 251 size_t strlen;
jbe@103 252 ssize_t written;
jbe@80 253 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 254 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
jbe@94 255 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
jbe@81 256 if (handle->writeerr) {
jbe@80 257 lua_pushnil(L);
jbe@80 258 lua_pushliteral(L, "Previous write error");
jbe@80 259 return 2;
jbe@80 260 }
jbe@103 261 handle->writeerr = 1;
jbe@81 262 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
jbe@84 263 top = lua_gettop(L);
jbe@81 264 lua_getuservalue(L, 1);
jbe@103 265 lua_getfield(L, -1, "writequeue");
jbe@84 266 for (i=2; i<=top; i++) {
jbe@84 267 luaL_checklstring(L, i, &strlen);
jbe@84 268 lua_pushvalue(L, i);
jbe@84 269 lua_rawseti(L, -2, handle->writeqin++);
jbe@84 270 handle->writeleft += strlen;
jbe@81 271 }
jbe@83 272 while (handle->writeqout != handle->writeqin) {
jbe@83 273 lua_rawgeti(L, -1, handle->writeqout);
jbe@81 274 str = lua_tolstring(L, -1, &strlen);
jbe@92 275 while (handle->writeqoff < strlen) {
jbe@103 276 if (
jbe@103 277 strlen - handle->writeqoff <=
jbe@103 278 MOONBR_IO_WRITEBUFLEN - handle->writebufin
jbe@103 279 ) {
jbe@103 280 memcpy(
jbe@103 281 handle->writebuf + handle->writebufin,
jbe@103 282 str + handle->writeqoff,
jbe@103 283 strlen - handle->writeqoff
jbe@103 284 );
jbe@103 285 handle->writebufin += strlen - handle->writeqoff;
jbe@80 286 break;
jbe@80 287 } else {
jbe@97 288 moonbr_io_handle_set_nopush(L, handle, 1);
jbe@103 289 memcpy(
jbe@103 290 handle->writebuf + handle->writebufin,
jbe@103 291 str + handle->writeqoff,
jbe@103 292 MOONBR_IO_WRITEBUFLEN - handle->writebufin
jbe@103 293 );
jbe@103 294 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
jbe@103 295 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
jbe@103 296 written = write(
jbe@103 297 handle->fd,
jbe@103 298 handle->writebuf + handle->writebufout,
jbe@103 299 MOONBR_IO_WRITEBUFLEN - handle->writebufout
jbe@103 300 );
jbe@103 301 if (written < 0) {
jbe@81 302 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@81 303 goto moonbr_io_write_impl_block;
jbe@81 304 } else if (errno != EINTR) {
jbe@80 305 moonbr_io_errmsg();
jbe@80 306 lua_pushnil(L);
jbe@80 307 lua_pushstring(L, errmsg);
jbe@80 308 return 2;
jbe@80 309 }
jbe@103 310 } else {
jbe@103 311 handle->writebufout += written;
jbe@103 312 handle->writeleft -= written;
jbe@80 313 }
jbe@80 314 }
jbe@103 315 handle->writebufin = 0;
jbe@103 316 handle->writebufout = 0;
jbe@80 317 }
jbe@80 318 }
jbe@81 319 handle->writeqoff = 0;
jbe@81 320 lua_pop(L, 1);
jbe@81 321 lua_pushnil(L);
jbe@83 322 lua_rawseti(L, -2, handle->writeqout++);
jbe@80 323 }
jbe@81 324 if (flush) {
jbe@97 325 moonbr_io_handle_set_nopush(L, handle, 0);
jbe@103 326 while (handle->writebufout < handle->writebufin) {
jbe@103 327 written = write(
jbe@103 328 handle->fd,
jbe@103 329 handle->writebuf + handle->writebufout,
jbe@103 330 handle->writebufin - handle->writebufout
jbe@103 331 );
jbe@103 332 if (written < 0) {
jbe@81 333 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@81 334 goto moonbr_io_write_impl_block;
jbe@81 335 } else if (errno != EINTR) {
jbe@81 336 moonbr_io_errmsg();
jbe@81 337 lua_pushnil(L);
jbe@81 338 lua_pushstring(L, errmsg);
jbe@81 339 return 2;
jbe@81 340 }
jbe@81 341 } else {
jbe@103 342 handle->writebufout += written;
jbe@103 343 handle->writeleft -= written;
jbe@81 344 }
jbe@81 345 }
jbe@103 346 handle->writebufin = 0;
jbe@103 347 handle->writebufout = 0;
jbe@81 348 }
jbe@103 349 if (nonblocking) lua_pushinteger(L, 0);
jbe@103 350 else lua_pushvalue(L, 1);
jbe@103 351 handle->writeerr = 0;
jbe@80 352 return 1;
jbe@81 353 moonbr_io_write_impl_block:
jbe@91 354 lua_pushinteger(L, handle->writeleft);
jbe@103 355 handle->writeerr = 0;
jbe@81 356 return 1;
jbe@81 357 }
jbe@81 358
jbe@81 359 static int moonbr_io_write(lua_State *L) {
jbe@81 360 return moonbr_io_write_impl(L, 0, 0);
jbe@81 361 }
jbe@81 362
jbe@81 363 static int moonbr_io_write_nb(lua_State *L) {
jbe@81 364 return moonbr_io_write_impl(L, 1, 0);
jbe@80 365 }
jbe@80 366
jbe@80 367 static int moonbr_io_flush(lua_State *L) {
jbe@81 368 return moonbr_io_write_impl(L, 0, 1);
jbe@81 369 }
jbe@81 370
jbe@81 371 static int moonbr_io_flush_nb(lua_State *L) {
jbe@81 372 return moonbr_io_write_impl(L, 1, 1);
jbe@80 373 }
jbe@80 374
jbe@88 375 static int moonbr_io_finish(lua_State *L) {
jbe@88 376 moonbr_io_handle_t *handle;
jbe@88 377 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 378 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
jbe@94 379 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
jbe@94 380 if (handle->writeleft) {
jbe@94 381 lua_pushcfunction(L, moonbr_io_flush);
jbe@94 382 lua_pushvalue(L, 1);
jbe@94 383 lua_call(L, 1, 2);
jbe@94 384 if (!lua_toboolean(L, -2)) {
jbe@94 385 handle->finished = 1;
jbe@94 386 return 2;
jbe@88 387 }
jbe@94 388 }
jbe@94 389 handle->finished = 1;
jbe@95 390 if (handle->isnetwork) {
jbe@88 391 if (shutdown(handle->fd, SHUT_WR)) {
jbe@88 392 moonbr_io_errmsg();
jbe@88 393 lua_pushnil(L);
jbe@88 394 lua_pushstring(L, errmsg);
jbe@88 395 return 2;
jbe@88 396 }
jbe@94 397 } else {
jbe@94 398 if (close(handle->fd)) {
jbe@94 399 moonbr_io_errmsg();
jbe@94 400 handle->fd = -1;
jbe@94 401 lua_pushnil(L);
jbe@94 402 lua_pushstring(L, errmsg);
jbe@94 403 return 2;
jbe@94 404 }
jbe@94 405 handle->fd = -1; /* fake EOF on read */
jbe@88 406 }
jbe@88 407 lua_pushboolean(L, 1);
jbe@88 408 return 1;
jbe@88 409 }
jbe@88 410
jbe@94 411 static int moonbr_io_close_impl(lua_State *L, int reset) {
jbe@83 412 moonbr_io_handle_t *handle;
jbe@83 413 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 414 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
jbe@94 415 if (!reset) {
jbe@87 416 if (handle->writeleft) {
jbe@87 417 lua_pushcfunction(L, moonbr_io_flush);
jbe@87 418 lua_pushvalue(L, 1);
jbe@87 419 lua_call(L, 1, 2);
jbe@87 420 if (!lua_toboolean(L, -2)) {
jbe@87 421 close(handle->fd);
jbe@87 422 handle->fd = -1;
jbe@87 423 return 2;
jbe@87 424 }
jbe@83 425 }
jbe@94 426 moonbr_io_handle_set_linger(L, handle, -1);
jbe@83 427 }
jbe@94 428 if (handle->fd >= 0) {
jbe@94 429 if (close(handle->fd)) {
jbe@94 430 moonbr_io_errmsg();
jbe@94 431 handle->fd = -1;
jbe@94 432 lua_pushnil(L);
jbe@94 433 lua_pushstring(L, errmsg);
jbe@94 434 return 2;
jbe@94 435 }
jbe@104 436 handle->fd = -1;
jbe@83 437 }
jbe@83 438 lua_pushboolean(L, 1);
jbe@83 439 return 1;
jbe@84 440
jbe@83 441 }
jbe@83 442
jbe@94 443 static int moonbr_io_close(lua_State *L) {
jbe@94 444 return moonbr_io_close_impl(L, 0);
jbe@94 445 }
jbe@94 446
jbe@84 447 static int moonbr_io_reset(lua_State *L) {
jbe@94 448 return moonbr_io_close_impl(L, 1);
jbe@84 449 }
jbe@84 450
jbe@88 451 static int moonbr_io_gc(lua_State *L) {
jbe@88 452 moonbr_io_handle_t *handle;
jbe@88 453 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@88 454 if (handle->fd >= 0) {
jbe@88 455 lua_pushcfunction(L, moonbr_io_close);
jbe@88 456 lua_pushvalue(L, 1);
jbe@88 457 lua_pushinteger(L, 0);
jbe@88 458 lua_call(L, 2, 0);
jbe@88 459 }
jbe@88 460 return 0;
jbe@88 461 }
jbe@88 462
jbe@100 463 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
jbe@88 464 moonbr_io_handle_t *handle;
jbe@88 465 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@100 466 if (!handle->closed) {
jbe@100 467 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
jbe@100 468 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
jbe@100 469 lua_call(L, 1, 0);
jbe@88 470 }
jbe@88 471 }
jbe@88 472
jbe@95 473 void moonbr_io_pushhandle(lua_State *L, int fd, int isnetwork) {
jbe@79 474 moonbr_io_handle_t *handle;
jbe@79 475 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
jbe@79 476 handle->fd = fd;
jbe@95 477 handle->isnetwork = isnetwork;
jbe@94 478 handle->finished = 0;
jbe@94 479 handle->closed = 0;
jbe@81 480 handle->nonblocking = -1;
jbe@95 481 handle->nopush = -1;
jbe@85 482 handle->readerr = 0;
jbe@105 483 handle->readbufin = 0;
jbe@105 484 handle->readbufout = 0;
jbe@81 485 handle->writeerr = 0;
jbe@81 486 handle->writeleft = 0;
jbe@83 487 handle->writeqin = 0;
jbe@83 488 handle->writeqout = 0;
jbe@81 489 handle->writeqoff = 0;
jbe@103 490 handle->writebufin = 0;
jbe@103 491 handle->writebufout = 0;
jbe@87 492 moonbr_io_handle_set_linger(L, handle, 0);
jbe@79 493 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 494 lua_setmetatable(L, -2);
jbe@79 495 lua_newtable(L); // uservalue
jbe@81 496 lua_newtable(L);
jbe@103 497 lua_setfield(L, -2, "writequeue");
jbe@79 498 lua_newtable(L); // public
jbe@79 499 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
jbe@79 500 lua_setmetatable(L, -2);
jbe@79 501 lua_setfield(L, -2, "public");
jbe@79 502 lua_setuservalue(L, -2);
jbe@79 503 }
jbe@79 504
jbe@79 505 static int moonbr_io_handleindex(lua_State *L) {
jbe@80 506 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 507 lua_getuservalue(L, 1);
jbe@79 508 lua_getfield(L, -1, "public");
jbe@79 509 lua_pushvalue(L, 2);
jbe@79 510 lua_gettable(L, -2);
jbe@79 511 return 1;
jbe@79 512 }
jbe@79 513
jbe@79 514 static int moonbr_io_handlenewindex(lua_State *L) {
jbe@80 515 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 516 lua_getuservalue(L, 1);
jbe@79 517 lua_getfield(L, -1, "public");
jbe@79 518 lua_pushvalue(L, 2);
jbe@79 519 lua_pushvalue(L, 3);
jbe@79 520 lua_settable(L, -3);
jbe@79 521 return 0;
jbe@79 522 }
jbe@79 523
jbe@99 524 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
jbe@98 525 const char *host, *port;
jbe@98 526 struct addrinfo hints = { 0, };
jbe@98 527 struct addrinfo *res, *addrinfo;
jbe@98 528 int errcode;
jbe@98 529 int sock;
jbe@98 530 host = luaL_checkstring(L, 1);
jbe@98 531 port = luaL_checkstring(L, 2);
jbe@98 532 hints.ai_family = AF_UNSPEC;
jbe@98 533 hints.ai_socktype = SOCK_STREAM;
jbe@98 534 hints.ai_protocol = IPPROTO_TCP;
jbe@98 535 hints.ai_flags = AI_ADDRCONFIG;
jbe@98 536 errcode = getaddrinfo(host, port, &hints, &res);
jbe@98 537 if (errcode) {
jbe@102 538 freeaddrinfo(res);
jbe@98 539 if (errcode == EAI_SYSTEM) {
jbe@98 540 moonbr_io_errmsg();
jbe@98 541 lua_pushnil(L);
jbe@98 542 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
jbe@98 543 } else {
jbe@98 544 lua_pushnil(L);
jbe@98 545 lua_pushstring(L, gai_strerror(errcode));
jbe@98 546 }
jbe@98 547 return 2;
jbe@98 548 }
jbe@98 549 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@98 550 if (addrinfo->ai_family == PF_INET6) goto moonbr_io_tcpconnect_found;
jbe@98 551 }
jbe@98 552 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@98 553 if (addrinfo->ai_family == PF_INET) goto moonbr_io_tcpconnect_found;
jbe@98 554 }
jbe@98 555 addrinfo = res;
jbe@98 556 moonbr_io_tcpconnect_found:
jbe@99 557 sock = socket(
jbe@99 558 addrinfo->ai_family,
jbe@99 559 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
jbe@99 560 addrinfo->ai_protocol
jbe@99 561 );
jbe@102 562 freeaddrinfo(res);
jbe@98 563 if (sock < 0) {
jbe@98 564 moonbr_io_errmsg();
jbe@98 565 lua_pushnil(L);
jbe@98 566 lua_pushstring(L, errmsg);
jbe@98 567 }
jbe@98 568 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
jbe@99 569 if (!nonblocking && errno == EINTR) {
jbe@99 570 moonbr_io_errmsg();
jbe@99 571 close(sock);
jbe@99 572 lua_pushnil(L);
jbe@99 573 lua_pushstring(L, errmsg);
jbe@99 574 return 2;
jbe@99 575 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
jbe@99 576 moonbr_io_errmsg();
jbe@99 577 lua_pushnil(L);
jbe@99 578 lua_pushstring(L, errmsg);
jbe@99 579 return 2;
jbe@99 580 }
jbe@98 581 }
jbe@98 582 moonbr_io_pushhandle(L, sock, 1);
jbe@98 583 return 1;
jbe@98 584 }
jbe@98 585
jbe@99 586 static int moonbr_io_tcpconnect(lua_State *L) {
jbe@99 587 return moonbr_io_tcpconnect_impl(L, 0);
jbe@99 588 }
jbe@99 589
jbe@99 590 static int moonbr_io_tcpconnect_nb(lua_State *L) {
jbe@99 591 return moonbr_io_tcpconnect_impl(L, 1);
jbe@99 592 }
jbe@99 593
jbe@106 594 static int moonbr_io_poll(lua_State *L) {
jbe@106 595 moonbr_io_handle_t *handle;
jbe@106 596 int fd, isnum;
jbe@106 597 int nfds = 0;
jbe@106 598 fd_set readfds, writefds, exceptfds;
jbe@106 599 struct timeval timeout = {0, };
jbe@106 600 int status;
jbe@106 601 FD_ZERO(&readfds);
jbe@106 602 FD_ZERO(&writefds);
jbe@106 603 FD_ZERO(&exceptfds);
jbe@106 604 if (!lua_isnoneornil(L, 1)) {
jbe@106 605 luaL_checktype(L, 1, LUA_TTABLE);
jbe@106 606 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
jbe@106 607 if (lua_toboolean(L, -1)) {
jbe@106 608 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 609 if (handle) {
jbe@106 610 fd = handle->fd;
jbe@106 611 if (fd < 0) luaL_error(L, "Handle in illegal state");
jbe@106 612 } else {
jbe@106 613 fd = lua_tointegerx(L, -2, &isnum);
jbe@106 614 if (!isnum) luaL_error(L, "File descriptor is not an integer");
jbe@106 615 }
jbe@106 616 FD_SET(fd, &readfds);
jbe@106 617 if (fd+1 > nfds) nfds = fd+1;
jbe@106 618 }
jbe@106 619 }
jbe@106 620 }
jbe@106 621 if (!lua_isnoneornil(L, 2)) {
jbe@106 622 luaL_checktype(L, 2, LUA_TTABLE);
jbe@106 623 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
jbe@106 624 if (lua_toboolean(L, -1)) {
jbe@106 625 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 626 if (handle) {
jbe@106 627 fd = handle->fd;
jbe@106 628 if (fd < 0) luaL_error(L, "Handle in illegal state");
jbe@106 629 } else {
jbe@106 630 fd = lua_tointegerx(L, -2, &isnum);
jbe@106 631 if (!isnum) luaL_error(L, "File descriptor is not an integer");
jbe@106 632 }
jbe@106 633 FD_SET(fd, &writefds);
jbe@106 634 if (fd+1 > nfds) nfds = fd+1;
jbe@106 635 }
jbe@106 636 }
jbe@106 637 }
jbe@106 638 if (!lua_isnoneornil(L, 3)) {
jbe@106 639 lua_Number n;
jbe@106 640 n = lua_tonumberx(L, 3, &isnum);
jbe@106 641 if (isnum && n>=0 && n<100000000) {
jbe@106 642 timeout.tv_sec = n;
jbe@106 643 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
jbe@106 644 } else {
jbe@106 645 luaL_argcheck(L, 0, 3, "not a valid timeout");
jbe@106 646 }
jbe@106 647 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
jbe@106 648 } else {
jbe@106 649 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
jbe@106 650 }
jbe@106 651 if (status == -1) {
jbe@106 652 if (errno == EINTR) {
jbe@106 653 lua_pushboolean(L, 0);
jbe@106 654 lua_pushliteral(L, "Signal received while polling file descriptors");
jbe@106 655 return 2;
jbe@106 656 } else {
jbe@106 657 moonbr_io_errmsg();
jbe@106 658 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
jbe@106 659 }
jbe@106 660 } else if (status == 0) {
jbe@106 661 lua_pushboolean(L, 0);
jbe@106 662 lua_pushliteral(L, "Timeout while polling file descriptors");
jbe@106 663 return 2;
jbe@106 664 } else {
jbe@106 665 lua_pushboolean(L, 1);
jbe@106 666 return 1;
jbe@106 667 }
jbe@106 668 }
jbe@106 669
jbe@79 670 static const struct luaL_Reg moonbr_io_handle_methods[] = {
jbe@85 671 {"read", moonbr_io_read},
jbe@85 672 {"read_nb", moonbr_io_read_nb},
jbe@86 673 {"drain", moonbr_io_drain},
jbe@86 674 {"drain_nb", moonbr_io_drain_nb},
jbe@80 675 {"write", moonbr_io_write},
jbe@81 676 {"write_nb", moonbr_io_write_nb},
jbe@80 677 {"flush", moonbr_io_flush},
jbe@81 678 {"flush_nb", moonbr_io_flush_nb},
jbe@88 679 {"finish", moonbr_io_finish},
jbe@87 680 {"close", moonbr_io_close},
jbe@85 681 {"reset", moonbr_io_reset},
jbe@79 682 {NULL, NULL}
jbe@79 683 };
jbe@79 684
jbe@79 685 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
jbe@79 686 {"__index", moonbr_io_handleindex},
jbe@79 687 {"__newindex", moonbr_io_handlenewindex},
jbe@88 688 {"__gc", moonbr_io_gc},
jbe@79 689 {NULL, NULL}
jbe@79 690 };
jbe@79 691
jbe@79 692 static const struct luaL_Reg moonbr_io_module_funcs[] = {
jbe@98 693 {"tcpconnect", moonbr_io_tcpconnect},
jbe@99 694 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
jbe@106 695 {"poll", moonbr_io_poll},
jbe@79 696 {NULL, NULL}
jbe@79 697 };
jbe@79 698
jbe@79 699 int luaopen_moonbridge_io(lua_State *L) {
jbe@79 700
jbe@80 701 lua_newtable(L); // module
jbe@80 702
jbe@79 703 lua_newtable(L); // public metatable
jbe@79 704 lua_newtable(L); // handle methods
jbe@79 705 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
jbe@80 706 lua_pushvalue(L, -1);
jbe@80 707 lua_setfield(L, -4, "handle");
jbe@79 708 lua_setfield(L, -2, "__index");
jbe@79 709 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
jbe@79 710
jbe@79 711 lua_newtable(L); // handle metatable
jbe@79 712 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
jbe@79 713 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 714
jbe@79 715 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
jbe@79 716 return 1;
jbe@79 717
jbe@79 718 }
jbe@79 719

Impressum / About Us