moonbridge

annotate moonbridge_io.c @ 107:06d965df8a0c

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

Impressum / About Us