moonbridge

annotate moonbridge_io.c @ 247:ba5ed7cf0a30

Modifications to poll(...) function in regard to TLS handshake
author jbe
date Wed Aug 24 23:50:22 2016 +0200 (2016-08-24)
parents 00e1ee683355
children 4c9102fb77eb
rev   line source
jbe@209 1
jbe@209 2 #ifndef __has_include
jbe@209 3 #define __has_include(x) 0
jbe@209 4 #endif
jbe@79 5
jbe@79 6 #include <stdlib.h>
jbe@135 7 #include <stdint.h>
jbe@135 8 #include <string.h>
jbe@135 9 #include <errno.h>
jbe@79 10 #include <unistd.h>
jbe@135 11 #include <signal.h>
jbe@135 12 #include <fcntl.h>
jbe@135 13 #include <sys/stat.h>
jbe@79 14 #include <sys/socket.h>
jbe@111 15 #include <sys/un.h>
jbe@95 16 #include <netinet/in.h>
jbe@95 17 #include <netinet/tcp.h>
jbe@135 18 #include <sys/select.h>
jbe@136 19 #include <time.h>
jbe@135 20 #include <netdb.h>
jbe@107 21 #include <arpa/inet.h>
jbe@205 22 #include <sys/types.h>
jbe@205 23 #include <sys/wait.h>
jbe@209 24 #if defined(__linux__) || __has_include(<bsd/unistd.h>)
jbe@209 25 #include <bsd/unistd.h>
jbe@209 26 #endif
jbe@211 27
jbe@243 28 #ifdef MOONBR_IO_USE_TLS
jbe@243 29 #include <tls.h>
jbe@243 30 #endif
jbe@243 31
jbe@79 32 #include <lua.h>
jbe@79 33 #include <lauxlib.h>
jbe@79 34 #include <lualib.h>
jbe@79 35
jbe@149 36 #include <assert.h>
jbe@149 37
jbe@80 38 #define MOONBR_IO_MAXSTRERRORLEN 80
jbe@85 39 #define MOONBR_IO_READBUFLEN 4096
jbe@80 40 #define MOONBR_IO_WRITEBUFLEN 4096
jbe@80 41
jbe@108 42 #define MOONBR_IO_LISTEN_BACKLOG 1024
jbe@108 43
jbe@213 44 #define MOONBR_IO_STRERROR_R_MSG "Error detail unavailable due to noncompliant strerror_r() implementation"
jbe@80 45 #define moonbr_io_errmsg() \
jbe@213 46 char errmsg[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG; \
jbe@80 47 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
jbe@80 48
jbe@79 49 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
jbe@79 50 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
jbe@108 51 #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
jbe@205 52 #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
jbe@205 53 #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
jbe@79 54
jbe@243 55 #ifdef MOONBR_IO_USE_TLS
jbe@243 56 #define MOONBR_IO_TLSCONF_MT_REGKEY "moonbridge_io_tlsconf"
jbe@243 57 #endif
jbe@243 58
jbe@79 59 typedef struct {
jbe@79 60 int fd;
jbe@107 61 int issock;
jbe@107 62 sa_family_t addrfam;
jbe@94 63 int finished;
jbe@94 64 int closed;
jbe@81 65 int nonblocking;
jbe@95 66 int nopush;
jbe@85 67 int readerr;
jbe@105 68 int readbufin;
jbe@105 69 int readbufout;
jbe@81 70 int writeerr;
jbe@83 71 size_t writeleft;
jbe@132 72 size_t flushedleft;
jbe@83 73 #if LUA_VERSION_NUM >= 503
jbe@83 74 lua_Integer writeqin;
jbe@83 75 lua_Integer writeqout;
jbe@83 76 #else
jbe@83 77 int writeqin;
jbe@83 78 int writeqout;
jbe@83 79 #endif
jbe@83 80 size_t writeqoff;
jbe@103 81 int writebufin;
jbe@103 82 int writebufout;
jbe@85 83 char readbuf[MOONBR_IO_READBUFLEN];
jbe@80 84 char writebuf[MOONBR_IO_WRITEBUFLEN];
jbe@246 85 #ifdef MOONBR_IO_USE_TLS
jbe@246 86 struct tls *tls, *servertls;
jbe@246 87 #endif
jbe@79 88 } moonbr_io_handle_t;
jbe@79 89
jbe@108 90 typedef struct {
jbe@108 91 int fd;
jbe@118 92 sa_family_t addrfam;
jbe@108 93 int nonblocking;
jbe@108 94 } moonbr_io_listener_t;
jbe@108 95
jbe@205 96 typedef struct {
jbe@205 97 pid_t pid;
jbe@205 98 } moonbr_io_child_t;
jbe@205 99
jbe@148 100 static int moonbr_io_yield(lua_State *L) {
jbe@149 101 return lua_yield(L, lua_gettop(L));
jbe@140 102 }
jbe@140 103
jbe@140 104 #if LUA_VERSION_NUM >= 503
jbe@140 105 static int moonbr_io_cont_returnall(lua_State *L, int status, lua_KContext ctx) {
jbe@140 106 #else
jbe@140 107 static int moonbr_io_cont_returnall(lua_State *L) {
jbe@140 108 #endif
jbe@140 109 return lua_gettop(L);
jbe@140 110 }
jbe@140 111
jbe@145 112 #define moonbr_io_yield_wrapper(yieldfunc, callfunc) \
jbe@145 113 static int yieldfunc(lua_State *L) { \
jbe@145 114 int args; \
jbe@145 115 lua_pushcfunction(L, callfunc); \
jbe@145 116 lua_insert(L, 1); \
jbe@145 117 args = lua_gettop(L); \
jbe@148 118 lua_pushcfunction(L, moonbr_io_yield); \
jbe@145 119 lua_insert(L, 3); \
jbe@145 120 lua_callk(L, args, LUA_MULTRET, 0, moonbr_io_cont_returnall); \
jbe@145 121 return lua_gettop(L); \
jbe@145 122 }
jbe@145 123
jbe@81 124 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
jbe@95 125 int flags;
jbe@95 126 if (handle->nonblocking == nonblocking) return;
jbe@95 127 flags = fcntl(handle->fd, F_GETFL, 0);
jbe@95 128 if (flags == -1) {
jbe@95 129 moonbr_io_errmsg();
jbe@96 130 close(handle->fd);
jbe@96 131 handle->fd = -1;
jbe@96 132 handle->closed = 1;
jbe@95 133 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@81 134 }
jbe@95 135 if (nonblocking) flags |= O_NONBLOCK;
jbe@95 136 else flags &= ~O_NONBLOCK;
jbe@95 137 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
jbe@95 138 moonbr_io_errmsg();
jbe@96 139 close(handle->fd);
jbe@96 140 handle->fd = -1;
jbe@96 141 handle->closed = 1;
jbe@95 142 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@95 143 }
jbe@95 144 handle->nonblocking = nonblocking;
jbe@81 145 }
jbe@81 146
jbe@87 147 static void moonbr_io_handle_set_linger(lua_State *L, moonbr_io_handle_t *handle, int timeout) {
jbe@87 148 struct linger lingerval = { 0, };
jbe@107 149 if (!handle->issock) return;
jbe@87 150 if (timeout >= 0) {
jbe@87 151 lingerval.l_onoff = 1;
jbe@87 152 lingerval.l_linger = timeout;
jbe@87 153 }
jbe@87 154 if (setsockopt(handle->fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) {
jbe@87 155 moonbr_io_errmsg();
jbe@96 156 close(handle->fd);
jbe@96 157 handle->fd = -1;
jbe@96 158 handle->closed = 1;
jbe@95 159 luaL_error(L, "Unexpected error while setting SO_LINGER with setsockopt: %s", errmsg);
jbe@87 160 }
jbe@87 161 }
jbe@87 162
jbe@133 163 static inline void moonbr_io_handle_set_nopush(lua_State *L, moonbr_io_handle_t *handle, int nopush) {
jbe@96 164 #if defined(TCP_NOPUSH) || defined(TCP_CORK)
jbe@107 165 if (
jbe@107 166 !(handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) ||
jbe@107 167 handle->nopush == nopush
jbe@107 168 ) return;
jbe@96 169 #if defined(TCP_NOPUSH)
jbe@96 170 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_NOPUSH, &nopush, sizeof(nopush))) {
jbe@104 171 #elif defined(TCP_CORK)
jbe@104 172 if (setsockopt(handle->fd, IPPROTO_TCP, TCP_CORK, &nopush, sizeof(nopush))) {
jbe@104 173 #endif
jbe@96 174 moonbr_io_errmsg();
jbe@96 175 close(handle->fd);
jbe@96 176 handle->fd = -1;
jbe@96 177 handle->closed = 1;
jbe@104 178 #if defined(TCP_NOPUSH)
jbe@96 179 luaL_error(L, "Unexpected error while setting TCP_NOPUSH with setsockopt: %s", errmsg);
jbe@96 180 #elif defined(TCP_CORK)
jbe@95 181 luaL_error(L, "Unexpected error while setting TCP_CORK with setsockopt: %s", errmsg);
jbe@104 182 #endif
jbe@95 183 }
jbe@95 184 handle->nopush = nopush;
jbe@96 185 #else
jbe@96 186 #warning Neither TCP_NOPUSH nor TCP_CORK is available
jbe@96 187 #endif
jbe@95 188 }
jbe@95 189
jbe@86 190 static int moonbr_io_read_impl(lua_State *L, int nonblocking, int drain) {
jbe@85 191 moonbr_io_handle_t *handle;
jbe@85 192 lua_Integer maxread;
jbe@85 193 const char *terminatorstr;
jbe@210 194 size_t terminatorlen;
jbe@210 195 char terminator = 0; /* initialize to avoid compiler warning */
jbe@85 196 luaL_Buffer luabuf;
jbe@85 197 size_t luabufcnt = 0;
jbe@105 198 int remaining;
jbe@85 199 char *terminatorpos;
jbe@103 200 ssize_t bytesread;
jbe@85 201 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@153 202 maxread = luaL_optinteger(L, 2, -1);
jbe@85 203 terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
jbe@85 204 if (terminatorlen) {
jbe@85 205 luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected");
jbe@85 206 terminator = terminatorstr[0];
jbe@85 207 }
jbe@86 208 lua_settop(L, 1); /* return handle on drain, terminator string may be garbage collected */
jbe@94 209 if (handle->closed) luaL_error(L, "Attempt to read from a closed I/O handle");
jbe@85 210 if (handle->readerr) {
jbe@85 211 lua_pushnil(L);
jbe@85 212 lua_pushliteral(L, "Previous read error");
jbe@85 213 return 2;
jbe@85 214 }
jbe@143 215 if (handle->fd < 0) {
jbe@143 216 /* fake EOF to simulate shutdown */
jbe@143 217 if (!drain) lua_pushliteral(L, "");
jbe@143 218 else lua_pushinteger(L, 0);
jbe@143 219 lua_pushliteral(L, "eof");
jbe@143 220 return 2;
jbe@143 221 }
jbe@105 222 handle->readerr = 1;
jbe@85 223 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
jbe@86 224 if (!drain) luaL_buffinit(L, &luabuf);
jbe@85 225 while (1) {
jbe@105 226 remaining = -1;
jbe@142 227 terminatorpos = NULL;
jbe@105 228 if (
jbe@153 229 maxread >= 0 &&
jbe@143 230 handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt
jbe@105 231 ) {
jbe@142 232 remaining = (size_t)maxread - luabufcnt;
jbe@193 233 if (terminatorlen) {
jbe@193 234 terminatorpos = memchr(
jbe@193 235 handle->readbuf + handle->readbufout,
jbe@193 236 terminator,
jbe@193 237 remaining
jbe@193 238 );
jbe@193 239 }
jbe@85 240 } else if (terminatorlen) {
jbe@105 241 terminatorpos = memchr(
jbe@105 242 handle->readbuf + handle->readbufout,
jbe@105 243 terminator,
jbe@105 244 handle->readbufin - handle->readbufout
jbe@105 245 );
jbe@85 246 }
jbe@142 247 if (terminatorpos) remaining = 1 + (
jbe@142 248 terminatorpos - (handle->readbuf + handle->readbufout)
jbe@142 249 );
jbe@105 250 if (remaining >= 0) {
jbe@86 251 if (!drain) {
jbe@105 252 luaL_addlstring(
jbe@105 253 &luabuf,
jbe@105 254 handle->readbuf + handle->readbufout,
jbe@105 255 remaining
jbe@105 256 );
jbe@86 257 luaL_pushresult(&luabuf);
jbe@90 258 } else {
jbe@105 259 lua_pushinteger(L, luabufcnt + remaining);
jbe@86 260 }
jbe@143 261 if (terminatorpos) lua_pushliteral(L, "term");
jbe@143 262 else lua_pushliteral(L, "maxlen");
jbe@105 263 handle->readbufout += remaining;
jbe@105 264 if (handle->readbufout == handle->readbufin) {
jbe@105 265 handle->readbufin = 0;
jbe@143 266 handle->readbufout = 0;
jbe@105 267 }
jbe@104 268 handle->readerr = 0;
jbe@143 269 return 2;
jbe@85 270 }
jbe@105 271 if (!drain) luaL_addlstring(
jbe@105 272 &luabuf,
jbe@105 273 handle->readbuf + handle->readbufout,
jbe@105 274 handle->readbufin - handle->readbufout
jbe@105 275 );
jbe@105 276 luabufcnt += handle->readbufin - handle->readbufout;
jbe@143 277 handle->readbufout = 0;
jbe@85 278 do {
jbe@103 279 bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN);
jbe@103 280 } while (bytesread < 0 && (errno == EINTR));
jbe@105 281 if (
jbe@105 282 bytesread == 0 || (
jbe@105 283 nonblocking &&
jbe@105 284 bytesread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
jbe@105 285 )
jbe@105 286 ) {
jbe@105 287 handle->readbufin = 0;
jbe@143 288 if (!drain) luaL_pushresult(&luabuf);
jbe@143 289 else lua_pushinteger(L, luabufcnt);
jbe@143 290 if (bytesread == 0) lua_pushliteral(L, "eof");
jbe@143 291 else lua_pushliteral(L, "block");
jbe@105 292 handle->readerr = 0;
jbe@143 293 return 2;
jbe@105 294 }
jbe@103 295 if (bytesread < 0) {
jbe@85 296 moonbr_io_errmsg();
jbe@85 297 lua_pushnil(L);
jbe@85 298 lua_pushstring(L, errmsg);
jbe@85 299 return 2;
jbe@85 300 }
jbe@105 301 handle->readbufin = bytesread;
jbe@86 302 }
jbe@85 303 }
jbe@85 304
jbe@85 305 static int moonbr_io_read(lua_State *L) {
jbe@86 306 return moonbr_io_read_impl(L, 0, 0);
jbe@85 307 }
jbe@85 308
jbe@85 309 static int moonbr_io_read_nb(lua_State *L) {
jbe@86 310 return moonbr_io_read_impl(L, 1, 0);
jbe@86 311 }
jbe@86 312
jbe@86 313 static int moonbr_io_drain(lua_State *L) {
jbe@86 314 return moonbr_io_read_impl(L, 0, 1);
jbe@86 315 }
jbe@86 316
jbe@86 317 static int moonbr_io_drain_nb(lua_State *L) {
jbe@86 318 return moonbr_io_read_impl(L, 1, 1);
jbe@85 319 }
jbe@85 320
jbe@140 321 #if LUA_VERSION_NUM >= 503
jbe@140 322 static int moonbr_io_read_cont(lua_State *L, int status, lua_KContext ctx) {
jbe@140 323 #else
jbe@140 324 static int moonbr_io_read_cont(lua_State *L) {
jbe@140 325 #endif
jbe@143 326 lua_Integer remaining;
jbe@143 327 size_t len;
jbe@140 328 #if !(LUA_VERSION_NUM >= 503)
jbe@140 329 int ctx = 0;
jbe@140 330 lua_getctx(L, &ctx);
jbe@140 331 #endif
jbe@140 332 remaining = lua_tointeger(L, 3);
jbe@140 333 while (1) {
jbe@140 334 lua_pushcfunction(L, moonbr_io_read_nb);
jbe@140 335 lua_pushvalue(L, 1);
jbe@140 336 lua_pushvalue(L, 3);
jbe@140 337 lua_pushvalue(L, 4);
jbe@140 338 lua_call(L, 3, 2);
jbe@143 339 if (lua_isnil(L, -2)) return 2;
jbe@143 340 lua_insert(L, -2);
jbe@143 341 len = lua_rawlen(L, -1);
jbe@143 342 if (ctx == 0) {
jbe@143 343 lua_replace(L, 5);
jbe@143 344 ctx = 1;
jbe@143 345 } else if (ctx == 1) {
jbe@143 346 lua_pushvalue(L, 5);
jbe@143 347 lua_newtable(L);
jbe@143 348 lua_replace(L, 5);
jbe@143 349 lua_rawseti(L, 5, 2);
jbe@143 350 lua_rawseti(L, 5, 1);
jbe@143 351 ctx = 2;
jbe@140 352 } else {
jbe@143 353 lua_rawseti(L, 5, lua_rawlen(L, 5) + 1);
jbe@140 354 }
jbe@144 355 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
jbe@144 356 lua_pop(L, 1);
jbe@144 357 if (remaining >= 0 && len) {
jbe@143 358 remaining -= len;
jbe@143 359 lua_pushinteger(L, remaining);
jbe@143 360 lua_replace(L, 3);
jbe@143 361 }
jbe@140 362 lua_pushvalue(L, 2);
jbe@152 363 lua_callk(L, 0, 0, ctx, moonbr_io_read_cont);
jbe@140 364 }
jbe@140 365 if (ctx == 1) {
jbe@140 366 lua_pushvalue(L, 5);
jbe@140 367 } else {
jbe@140 368 luaL_Buffer buf;
jbe@140 369 lua_Integer i, chunkcount;
jbe@140 370 chunkcount = lua_rawlen(L, 5);
jbe@140 371 luaL_buffinit(L, &buf);
jbe@140 372 for (i=1; i<=chunkcount && i>0; i++) {
jbe@140 373 lua_rawgeti(L, 5, i);
jbe@140 374 luaL_addvalue(&buf);
jbe@140 375 }
jbe@140 376 luaL_pushresult(&buf);
jbe@140 377 }
jbe@143 378 lua_pushvalue(L, -2);
jbe@143 379 return 2;
jbe@140 380 }
jbe@140 381
jbe@140 382 static int moonbr_io_read_call(lua_State *L) {
jbe@140 383 lua_settop(L, 4);
jbe@140 384 lua_pushnil(L);
jbe@140 385 #if LUA_VERSION_NUM >= 503
jbe@140 386 return moonbr_io_read_cont(L, 0, 0);
jbe@140 387 #else
jbe@140 388 return moonbr_io_read_cont(L);
jbe@140 389 #endif
jbe@140 390 }
jbe@140 391
jbe@145 392 moonbr_io_yield_wrapper(moonbr_io_read_yield, moonbr_io_read_call);
jbe@140 393
jbe@144 394 #if LUA_VERSION_NUM >= 503
jbe@144 395 static int moonbr_io_drain_cont(lua_State *L, int status, lua_KContext ctx) {
jbe@144 396 #else
jbe@144 397 static int moonbr_io_drain_cont(lua_State *L) {
jbe@144 398 #endif
jbe@144 399 lua_Integer remaining, len;
jbe@144 400 size_t totallen = 0;
jbe@144 401 #if !(LUA_VERSION_NUM >= 503)
jbe@144 402 int ctx = 0;
jbe@144 403 lua_getctx(L, &ctx);
jbe@144 404 #endif
jbe@144 405 remaining = lua_tointeger(L, 3);
jbe@144 406 while (1) {
jbe@144 407 lua_pushcfunction(L, moonbr_io_drain_nb);
jbe@144 408 lua_pushvalue(L, 1);
jbe@144 409 lua_pushvalue(L, 3);
jbe@144 410 lua_pushvalue(L, 4);
jbe@144 411 lua_call(L, 3, 2);
jbe@144 412 if (lua_isnil(L, -2)) return 2;
jbe@144 413 lua_insert(L, -2);
jbe@144 414 len = lua_tointeger(L, -1);
jbe@144 415 lua_pop(L, 1);
jbe@144 416 totallen += len;
jbe@144 417 if (strcmp(lua_tostring(L, -1), "block") != 0) break;
jbe@144 418 lua_pop(L, 1);
jbe@144 419 if (remaining >= 0 && len) {
jbe@144 420 remaining -= len;
jbe@144 421 lua_pushinteger(L, remaining);
jbe@144 422 lua_replace(L, 3);
jbe@144 423 }
jbe@144 424 lua_pushvalue(L, 2);
jbe@152 425 lua_callk(L, 0, 0, ctx, moonbr_io_drain_cont);
jbe@144 426 }
jbe@144 427 lua_pushinteger(L, totallen);
jbe@144 428 lua_pushvalue(L, -2);
jbe@144 429 return 2;
jbe@144 430 }
jbe@144 431
jbe@144 432 static int moonbr_io_drain_call(lua_State *L) {
jbe@144 433 #if LUA_VERSION_NUM >= 503
jbe@144 434 return moonbr_io_drain_cont(L, 0, 0);
jbe@144 435 #else
jbe@144 436 return moonbr_io_drain_cont(L);
jbe@144 437 #endif
jbe@144 438 }
jbe@144 439
jbe@145 440 moonbr_io_yield_wrapper(moonbr_io_drain_yield, moonbr_io_drain_call);
jbe@144 441
jbe@81 442 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
jbe@80 443 moonbr_io_handle_t *handle;
jbe@80 444 int i, top;
jbe@80 445 const char *str;
jbe@92 446 size_t strlen;
jbe@103 447 ssize_t written;
jbe@80 448 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 449 if (handle->closed) luaL_error(L, "Attempt to write to a closed I/O handle");
jbe@94 450 if (handle->finished) luaL_error(L, "Attempt to write to a finished I/O handle");
jbe@81 451 if (handle->writeerr) {
jbe@80 452 lua_pushnil(L);
jbe@80 453 lua_pushliteral(L, "Previous write error");
jbe@80 454 return 2;
jbe@80 455 }
jbe@103 456 handle->writeerr = 1;
jbe@81 457 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
jbe@84 458 top = lua_gettop(L);
jbe@81 459 lua_getuservalue(L, 1);
jbe@103 460 lua_getfield(L, -1, "writequeue");
jbe@84 461 for (i=2; i<=top; i++) {
jbe@84 462 luaL_checklstring(L, i, &strlen);
jbe@84 463 lua_pushvalue(L, i);
jbe@84 464 lua_rawseti(L, -2, handle->writeqin++);
jbe@84 465 handle->writeleft += strlen;
jbe@81 466 }
jbe@132 467 if (flush) handle->flushedleft = handle->writeleft;
jbe@83 468 while (handle->writeqout != handle->writeqin) {
jbe@83 469 lua_rawgeti(L, -1, handle->writeqout);
jbe@81 470 str = lua_tolstring(L, -1, &strlen);
jbe@92 471 while (handle->writeqoff < strlen) {
jbe@103 472 if (
jbe@132 473 strlen - handle->writeqoff <
jbe@103 474 MOONBR_IO_WRITEBUFLEN - handle->writebufin
jbe@103 475 ) {
jbe@103 476 memcpy(
jbe@103 477 handle->writebuf + handle->writebufin,
jbe@103 478 str + handle->writeqoff,
jbe@103 479 strlen - handle->writeqoff
jbe@103 480 );
jbe@103 481 handle->writebufin += strlen - handle->writeqoff;
jbe@80 482 break;
jbe@80 483 } else {
jbe@103 484 memcpy(
jbe@103 485 handle->writebuf + handle->writebufin,
jbe@103 486 str + handle->writeqoff,
jbe@103 487 MOONBR_IO_WRITEBUFLEN - handle->writebufin
jbe@103 488 );
jbe@103 489 handle->writeqoff += MOONBR_IO_WRITEBUFLEN - handle->writebufin;
jbe@228 490 handle->writebufin = MOONBR_IO_WRITEBUFLEN;
jbe@103 491 while (handle->writebufout < MOONBR_IO_WRITEBUFLEN) {
jbe@133 492 moonbr_io_handle_set_nopush(L, handle, 1);
jbe@103 493 written = write(
jbe@103 494 handle->fd,
jbe@103 495 handle->writebuf + handle->writebufout,
jbe@103 496 MOONBR_IO_WRITEBUFLEN - handle->writebufout
jbe@103 497 );
jbe@103 498 if (written < 0) {
jbe@81 499 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@81 500 goto moonbr_io_write_impl_block;
jbe@81 501 } else if (errno != EINTR) {
jbe@80 502 moonbr_io_errmsg();
jbe@80 503 lua_pushnil(L);
jbe@80 504 lua_pushstring(L, errmsg);
jbe@80 505 return 2;
jbe@80 506 }
jbe@103 507 } else {
jbe@103 508 handle->writebufout += written;
jbe@103 509 handle->writeleft -= written;
jbe@133 510 if (handle->flushedleft) {
jbe@133 511 if (written >= handle->flushedleft) {
jbe@133 512 handle->flushedleft = 0;
jbe@133 513 moonbr_io_handle_set_nopush(L, handle, 0);
jbe@133 514 } else {
jbe@133 515 handle->flushedleft -= written;
jbe@133 516 }
jbe@133 517 }
jbe@80 518 }
jbe@80 519 }
jbe@103 520 handle->writebufin = 0;
jbe@103 521 handle->writebufout = 0;
jbe@80 522 }
jbe@80 523 }
jbe@81 524 handle->writeqoff = 0;
jbe@81 525 lua_pop(L, 1);
jbe@81 526 lua_pushnil(L);
jbe@83 527 lua_rawseti(L, -2, handle->writeqout++);
jbe@80 528 }
jbe@132 529 while (handle->flushedleft) {
jbe@133 530 moonbr_io_handle_set_nopush(L, handle, 1);
jbe@132 531 written = write(
jbe@132 532 handle->fd,
jbe@132 533 handle->writebuf + handle->writebufout,
jbe@132 534 handle->writebufin - handle->writebufout
jbe@132 535 );
jbe@132 536 if (written < 0) {
jbe@132 537 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@132 538 goto moonbr_io_write_impl_block;
jbe@132 539 } else if (errno != EINTR) {
jbe@132 540 moonbr_io_errmsg();
jbe@132 541 lua_pushnil(L);
jbe@132 542 lua_pushstring(L, errmsg);
jbe@132 543 return 2;
jbe@81 544 }
jbe@132 545 } else {
jbe@132 546 handle->writebufout += written;
jbe@132 547 handle->writeleft -= written;
jbe@133 548 if (handle->flushedleft) {
jbe@133 549 if (written >= handle->flushedleft) {
jbe@133 550 handle->flushedleft = 0;
jbe@133 551 moonbr_io_handle_set_nopush(L, handle, 0);
jbe@133 552 } else {
jbe@133 553 handle->flushedleft -= written;
jbe@133 554 }
jbe@133 555 }
jbe@81 556 }
jbe@132 557 }
jbe@132 558 if (handle->writebufout == handle->writebufin) {
jbe@103 559 handle->writebufin = 0;
jbe@103 560 handle->writebufout = 0;
jbe@81 561 }
jbe@103 562 if (nonblocking) lua_pushinteger(L, 0);
jbe@103 563 else lua_pushvalue(L, 1);
jbe@103 564 handle->writeerr = 0;
jbe@80 565 return 1;
jbe@81 566 moonbr_io_write_impl_block:
jbe@91 567 lua_pushinteger(L, handle->writeleft);
jbe@103 568 handle->writeerr = 0;
jbe@81 569 return 1;
jbe@81 570 }
jbe@81 571
jbe@81 572 static int moonbr_io_write(lua_State *L) {
jbe@81 573 return moonbr_io_write_impl(L, 0, 0);
jbe@81 574 }
jbe@81 575
jbe@81 576 static int moonbr_io_write_nb(lua_State *L) {
jbe@81 577 return moonbr_io_write_impl(L, 1, 0);
jbe@80 578 }
jbe@80 579
jbe@80 580 static int moonbr_io_flush(lua_State *L) {
jbe@81 581 return moonbr_io_write_impl(L, 0, 1);
jbe@81 582 }
jbe@81 583
jbe@81 584 static int moonbr_io_flush_nb(lua_State *L) {
jbe@81 585 return moonbr_io_write_impl(L, 1, 1);
jbe@80 586 }
jbe@80 587
jbe@145 588 #if LUA_VERSION_NUM >= 503
jbe@145 589 static int moonbr_io_write_cont(lua_State *L, int status, lua_KContext ctx) {
jbe@145 590 #else
jbe@145 591 static int moonbr_io_write_cont(lua_State *L) {
jbe@145 592 #endif
jbe@145 593 while (1) {
jbe@145 594 lua_pushcfunction(L, moonbr_io_write_nb);
jbe@145 595 lua_pushvalue(L, 1);
jbe@145 596 lua_call(L, 1, 2);
jbe@145 597 if (lua_isnil(L, -2)) return 2;
jbe@145 598 if (!lua_tointeger(L, -2)) {
jbe@145 599 lua_pushvalue(L, 1);
jbe@145 600 return 1;
jbe@145 601 }
jbe@145 602 lua_pop(L, 2);
jbe@145 603 lua_pushvalue(L, 2);
jbe@152 604 lua_callk(L, 0, 0, 0, moonbr_io_write_cont);
jbe@145 605 }
jbe@145 606 }
jbe@145 607
jbe@145 608 static int moonbr_io_write_call(lua_State *L) {
jbe@145 609 lua_pushcfunction(L, moonbr_io_write_nb);
jbe@145 610 lua_insert(L, 3);
jbe@145 611 lua_pushvalue(L, 1);
jbe@145 612 lua_insert(L, 4);
jbe@145 613 lua_call(L, lua_gettop(L) - 3, 2);
jbe@145 614 if (lua_isnil(L, -2)) return 2;
jbe@145 615 if (!lua_tointeger(L, -2)) {
jbe@145 616 lua_pushvalue(L, 1);
jbe@145 617 return 1;
jbe@145 618 }
jbe@145 619 #if LUA_VERSION_NUM >= 503
jbe@145 620 return moonbr_io_write_cont(L, 0, 0);
jbe@145 621 #else
jbe@145 622 return moonbr_io_write_cont(L);
jbe@145 623 #endif
jbe@145 624 }
jbe@145 625
jbe@145 626 moonbr_io_yield_wrapper(moonbr_io_write_yield, moonbr_io_write_call);
jbe@145 627
jbe@145 628 static int moonbr_io_flush_call(lua_State *L) {
jbe@145 629 lua_pushcfunction(L, moonbr_io_flush_nb);
jbe@145 630 lua_insert(L, 3);
jbe@145 631 lua_pushvalue(L, 1);
jbe@145 632 lua_insert(L, 4);
jbe@145 633 lua_call(L, lua_gettop(L) - 3, 2);
jbe@145 634 if (lua_isnil(L, -2)) return 2;
jbe@145 635 if (!lua_tointeger(L, -2)) {
jbe@145 636 lua_pushvalue(L, 1);
jbe@145 637 return 1;
jbe@145 638 }
jbe@145 639 #if LUA_VERSION_NUM >= 503
jbe@145 640 return moonbr_io_write_cont(L, 0, 0);
jbe@145 641 #else
jbe@145 642 return moonbr_io_write_cont(L);
jbe@145 643 #endif
jbe@145 644 }
jbe@145 645
jbe@145 646 moonbr_io_yield_wrapper(moonbr_io_flush_yield, moonbr_io_flush_call);
jbe@145 647
jbe@88 648 static int moonbr_io_finish(lua_State *L) {
jbe@88 649 moonbr_io_handle_t *handle;
jbe@88 650 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 651 if (handle->closed) luaL_error(L, "Attempt to finish a closed I/O handle");
jbe@94 652 if (handle->finished) luaL_error(L, "Attempt to finish a finished I/O handle");
jbe@94 653 if (handle->writeleft) {
jbe@94 654 lua_pushcfunction(L, moonbr_io_flush);
jbe@94 655 lua_pushvalue(L, 1);
jbe@116 656 if (lua_pcall(L, 1, 2, 0)) {
jbe@116 657 handle->finished = 1;
jbe@116 658 lua_error(L);
jbe@116 659 }
jbe@94 660 if (!lua_toboolean(L, -2)) {
jbe@94 661 handle->finished = 1;
jbe@94 662 return 2;
jbe@88 663 }
jbe@94 664 }
jbe@94 665 handle->finished = 1;
jbe@107 666 if (handle->addrfam == AF_INET6 || handle->addrfam == AF_INET) {
jbe@88 667 if (shutdown(handle->fd, SHUT_WR)) {
jbe@88 668 moonbr_io_errmsg();
jbe@88 669 lua_pushnil(L);
jbe@88 670 lua_pushstring(L, errmsg);
jbe@88 671 return 2;
jbe@88 672 }
jbe@94 673 } else {
jbe@94 674 if (close(handle->fd)) {
jbe@94 675 moonbr_io_errmsg();
jbe@94 676 handle->fd = -1;
jbe@94 677 lua_pushnil(L);
jbe@94 678 lua_pushstring(L, errmsg);
jbe@94 679 return 2;
jbe@94 680 }
jbe@94 681 handle->fd = -1; /* fake EOF on read */
jbe@88 682 }
jbe@88 683 lua_pushboolean(L, 1);
jbe@88 684 return 1;
jbe@88 685 }
jbe@88 686
jbe@94 687 static int moonbr_io_close_impl(lua_State *L, int reset) {
jbe@83 688 moonbr_io_handle_t *handle;
jbe@83 689 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@94 690 if (handle->closed) luaL_error(L, "Attempt to close a closed I/O handle");
jbe@94 691 if (!reset) {
jbe@87 692 if (handle->writeleft) {
jbe@87 693 lua_pushcfunction(L, moonbr_io_flush);
jbe@87 694 lua_pushvalue(L, 1);
jbe@116 695 if (lua_pcall(L, 1, 2, 0)) {
jbe@129 696 handle->closed = 1;
jbe@116 697 close(handle->fd);
jbe@116 698 handle->fd = -1;
jbe@116 699 lua_error(L);
jbe@116 700 }
jbe@129 701 handle->closed = 1;
jbe@87 702 if (!lua_toboolean(L, -2)) {
jbe@87 703 close(handle->fd);
jbe@87 704 handle->fd = -1;
jbe@87 705 return 2;
jbe@87 706 }
jbe@129 707 } else {
jbe@129 708 handle->closed = 1;
jbe@129 709 moonbr_io_handle_set_linger(L, handle, -1);
jbe@83 710 }
jbe@129 711 } else {
jbe@129 712 handle->closed = 1;
jbe@83 713 }
jbe@94 714 if (handle->fd >= 0) {
jbe@94 715 if (close(handle->fd)) {
jbe@94 716 moonbr_io_errmsg();
jbe@94 717 handle->fd = -1;
jbe@94 718 lua_pushnil(L);
jbe@94 719 lua_pushstring(L, errmsg);
jbe@94 720 return 2;
jbe@94 721 }
jbe@104 722 handle->fd = -1;
jbe@83 723 }
jbe@83 724 lua_pushboolean(L, 1);
jbe@83 725 return 1;
jbe@84 726
jbe@83 727 }
jbe@83 728
jbe@94 729 static int moonbr_io_close(lua_State *L) {
jbe@94 730 return moonbr_io_close_impl(L, 0);
jbe@94 731 }
jbe@94 732
jbe@84 733 static int moonbr_io_reset(lua_State *L) {
jbe@94 734 return moonbr_io_close_impl(L, 1);
jbe@84 735 }
jbe@84 736
jbe@108 737 static int moonbr_io_handlegc(lua_State *L) {
jbe@88 738 moonbr_io_handle_t *handle;
jbe@88 739 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@88 740 if (handle->fd >= 0) {
jbe@218 741 lua_pushcfunction(L, moonbr_io_reset);
jbe@88 742 lua_pushvalue(L, 1);
jbe@88 743 lua_pushinteger(L, 0);
jbe@88 744 lua_call(L, 2, 0);
jbe@88 745 }
jbe@246 746 #ifdef MOONBR_IO_USE_TLS
jbe@246 747 if (handle->tls) {
jbe@246 748 tls_free(handle->tls);
jbe@246 749 handle->tls = NULL;
jbe@246 750 }
jbe@246 751 if (handle->servertls) {
jbe@246 752 tls_free(handle->servertls);
jbe@246 753 handle->servertls = NULL;
jbe@246 754 }
jbe@246 755 #endif
jbe@88 756 return 0;
jbe@88 757 }
jbe@88 758
jbe@100 759 void moonbr_io_closehandle(lua_State *L, int idx, int reset) {
jbe@88 760 moonbr_io_handle_t *handle;
jbe@88 761 handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@100 762 if (!handle->closed) {
jbe@100 763 lua_pushcfunction(L, reset ? moonbr_io_reset : moonbr_io_close);
jbe@100 764 lua_pushvalue(L, idx < 0 ? idx-1 : idx);
jbe@100 765 lua_call(L, 1, 0);
jbe@88 766 }
jbe@88 767 }
jbe@88 768
jbe@208 769 static int moonbr_io_pushhandle_impl(lua_State *L) {
jbe@208 770 int *fd;
jbe@79 771 moonbr_io_handle_t *handle;
jbe@107 772 struct sockaddr addr;
jbe@107 773 socklen_t addrlen;
jbe@208 774 fd = lua_touserdata(L, 1);
jbe@79 775 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
jbe@208 776 handle->fd = -1; /* avoid closing incomplete handle */
jbe@107 777 addrlen = sizeof(addr);
jbe@208 778 if (getsockname(*fd, &addr, &addrlen)) {
jbe@107 779 if (errno != ENOTSOCK) {
jbe@107 780 moonbr_io_errmsg();
jbe@107 781 luaL_error(L, "Unexpected error when examining socket: %s", errmsg);
jbe@107 782 }
jbe@107 783 handle->issock = 0;
jbe@107 784 } else {
jbe@107 785 handle->issock = 1;
jbe@107 786 handle->addrfam = addr.sa_family;
jbe@107 787 }
jbe@94 788 handle->finished = 0;
jbe@94 789 handle->closed = 0;
jbe@81 790 handle->nonblocking = -1;
jbe@95 791 handle->nopush = -1;
jbe@85 792 handle->readerr = 0;
jbe@105 793 handle->readbufin = 0;
jbe@105 794 handle->readbufout = 0;
jbe@81 795 handle->writeerr = 0;
jbe@81 796 handle->writeleft = 0;
jbe@132 797 handle->flushedleft = 0;
jbe@83 798 handle->writeqin = 0;
jbe@83 799 handle->writeqout = 0;
jbe@81 800 handle->writeqoff = 0;
jbe@103 801 handle->writebufin = 0;
jbe@103 802 handle->writebufout = 0;
jbe@246 803 #ifdef MOONBR_IO_USE_TLS
jbe@246 804 handle->tls = NULL;
jbe@246 805 handle->servertls = NULL;
jbe@246 806 #endif
jbe@208 807 handle->fd = *fd; /* required for set_linger call */
jbe@87 808 moonbr_io_handle_set_linger(L, handle, 0);
jbe@208 809 handle->fd = -1; /* avoid closing incomplete handle */
jbe@238 810 luaL_setmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 811 lua_newtable(L); // uservalue
jbe@81 812 lua_newtable(L);
jbe@103 813 lua_setfield(L, -2, "writequeue");
jbe@79 814 lua_newtable(L); // public
jbe@107 815 if (handle->addrfam == AF_INET6) {
jbe@107 816 struct sockaddr_in6 addr_in6;
jbe@107 817 char addrstrbuf[INET6_ADDRSTRLEN];
jbe@107 818 const char *addrstr;
jbe@107 819 addrlen = sizeof(addr_in6);
jbe@208 820 if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
jbe@107 821 moonbr_io_errmsg();
jbe@107 822 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
jbe@107 823 }
jbe@107 824 if (addrlen > sizeof(addr_in6)) {
jbe@107 825 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
jbe@107 826 }
jbe@107 827 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
jbe@107 828 if (!addrstr) {
jbe@107 829 moonbr_io_errmsg();
jbe@107 830 luaL_error(L, "Could not format local IP address: %s", errmsg);
jbe@107 831 } else {
jbe@107 832 lua_pushstring(L, addrstr);
jbe@107 833 lua_setfield(L, -2, "local_ip6");
jbe@107 834 }
jbe@107 835 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
jbe@107 836 lua_setfield(L, -2, "local_tcpport");
jbe@208 837 if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
jbe@107 838 moonbr_io_errmsg();
jbe@107 839 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
jbe@107 840 }
jbe@107 841 if (addrlen > sizeof(addr_in6)) {
jbe@107 842 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
jbe@107 843 }
jbe@107 844 addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
jbe@107 845 if (!addrstr) {
jbe@107 846 moonbr_io_errmsg();
jbe@107 847 luaL_error(L, "Could not format remote IP address: %s", errmsg);
jbe@107 848 } else {
jbe@107 849 lua_pushstring(L, addrstr);
jbe@107 850 lua_setfield(L, -2, "remote_ip6");
jbe@107 851 }
jbe@107 852 lua_pushinteger(L, ntohs(addr_in6.sin6_port));
jbe@107 853 lua_setfield(L, -2, "remote_tcpport");
jbe@107 854 } else if (handle->addrfam == AF_INET) {
jbe@107 855 struct sockaddr_in addr_in;
jbe@107 856 char addrstrbuf[INET_ADDRSTRLEN];
jbe@107 857 const char *addrstr;
jbe@107 858 addrlen = sizeof(addr_in);
jbe@208 859 if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
jbe@107 860 moonbr_io_errmsg();
jbe@107 861 luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
jbe@107 862 }
jbe@107 863 if (addrlen > sizeof(addr_in)) {
jbe@107 864 luaL_error(L, "Could not determine local IP address/port: buffer size exceeded");
jbe@107 865 }
jbe@107 866 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
jbe@107 867 if (!addrstr) {
jbe@107 868 moonbr_io_errmsg();
jbe@107 869 luaL_error(L, "Could not format local IP address: %s", errmsg);
jbe@107 870 } else {
jbe@107 871 lua_pushstring(L, addrstr);
jbe@107 872 lua_setfield(L, -2, "local_ip4");
jbe@107 873 }
jbe@107 874 lua_pushinteger(L, ntohs(addr_in.sin_port));
jbe@107 875 lua_setfield(L, -2, "local_tcpport");
jbe@208 876 if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
jbe@107 877 moonbr_io_errmsg();
jbe@107 878 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
jbe@107 879 }
jbe@107 880 if (addrlen > sizeof(addr_in)) {
jbe@107 881 luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
jbe@107 882 }
jbe@107 883 addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
jbe@107 884 if (!addrstr) {
jbe@107 885 moonbr_io_errmsg();
jbe@107 886 luaL_error(L, "Could not format remote IP address: %s", errmsg);
jbe@107 887 } else {
jbe@107 888 lua_pushstring(L, addrstr);
jbe@107 889 lua_setfield(L, -2, "remote_ip4");
jbe@107 890 }
jbe@107 891 lua_pushinteger(L, ntohs(addr_in.sin_port));
jbe@107 892 lua_setfield(L, -2, "remote_tcpport");
jbe@107 893 }
jbe@238 894 luaL_setmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
jbe@79 895 lua_setfield(L, -2, "public");
jbe@79 896 lua_setuservalue(L, -2);
jbe@208 897 handle->fd = *fd;
jbe@208 898 *fd = -1; /* closing is now handled by garbage collection */
jbe@208 899 return 1;
jbe@208 900 }
jbe@208 901
jbe@208 902 void moonbr_io_pushhandle(lua_State *L, int fd) {
jbe@208 903 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 904 lua_pushlightuserdata(L, &fd);
jbe@208 905 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 906 if (fd != -1) close(fd);
jbe@208 907 lua_error(L);
jbe@208 908 }
jbe@79 909 }
jbe@79 910
jbe@79 911 static int moonbr_io_handleindex(lua_State *L) {
jbe@80 912 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@205 913 luaL_checkany(L, 2);
jbe@79 914 lua_getuservalue(L, 1);
jbe@79 915 lua_getfield(L, -1, "public");
jbe@79 916 lua_pushvalue(L, 2);
jbe@79 917 lua_gettable(L, -2);
jbe@79 918 return 1;
jbe@79 919 }
jbe@79 920
jbe@79 921 static int moonbr_io_handlenewindex(lua_State *L) {
jbe@80 922 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@205 923 luaL_checkany(L, 2);
jbe@205 924 luaL_checkany(L, 3);
jbe@79 925 lua_getuservalue(L, 1);
jbe@79 926 lua_getfield(L, -1, "public");
jbe@79 927 lua_pushvalue(L, 2);
jbe@79 928 lua_pushvalue(L, 3);
jbe@79 929 lua_settable(L, -3);
jbe@79 930 return 0;
jbe@79 931 }
jbe@79 932
jbe@111 933 static int moonbr_io_localconnect_impl(lua_State *L, int nonblocking) {
jbe@111 934 const char *path;
jbe@111 935 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
jbe@111 936 const int path_maxlen = sizeof(struct sockaddr_un) - (
jbe@111 937 (void *)sockaddr.sun_path - (void *)&sockaddr
jbe@111 938 ) - 1; /* one byte for termination */
jbe@111 939 int sock;
jbe@111 940 path = luaL_checkstring(L, 1);
jbe@111 941 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
jbe@111 942 strcpy(sockaddr.sun_path, path);
jbe@111 943 sock = socket(
jbe@111 944 PF_LOCAL,
jbe@111 945 SOCK_STREAM | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
jbe@111 946 0
jbe@111 947 );
jbe@111 948 if (sock < 0) {
jbe@111 949 moonbr_io_errmsg();
jbe@111 950 lua_pushnil(L);
jbe@111 951 lua_pushstring(L, errmsg);
jbe@111 952 return 2;
jbe@111 953 }
jbe@111 954 if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
jbe@111 955 if (!nonblocking && errno == EINTR) {
jbe@111 956 moonbr_io_errmsg();
jbe@111 957 close(sock);
jbe@111 958 lua_pushnil(L);
jbe@111 959 lua_pushstring(L, errmsg);
jbe@111 960 return 2;
jbe@111 961 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
jbe@111 962 moonbr_io_errmsg();
jbe@111 963 lua_pushnil(L);
jbe@111 964 lua_pushstring(L, errmsg);
jbe@111 965 return 2;
jbe@111 966 }
jbe@111 967 }
jbe@111 968 moonbr_io_pushhandle(L, sock);
jbe@111 969 return 1;
jbe@111 970 }
jbe@111 971
jbe@111 972 static int moonbr_io_localconnect(lua_State *L) {
jbe@111 973 return moonbr_io_localconnect_impl(L, 0);
jbe@111 974 }
jbe@111 975
jbe@111 976 static int moonbr_io_localconnect_nb(lua_State *L) {
jbe@111 977 return moonbr_io_localconnect_impl(L, 1);
jbe@111 978 }
jbe@111 979
jbe@99 980 static int moonbr_io_tcpconnect_impl(lua_State *L, int nonblocking) {
jbe@98 981 const char *host, *port;
jbe@98 982 struct addrinfo hints = { 0, };
jbe@98 983 struct addrinfo *res, *addrinfo;
jbe@98 984 int errcode;
jbe@98 985 int sock;
jbe@98 986 host = luaL_checkstring(L, 1);
jbe@98 987 port = luaL_checkstring(L, 2);
jbe@98 988 hints.ai_family = AF_UNSPEC;
jbe@98 989 hints.ai_socktype = SOCK_STREAM;
jbe@98 990 hints.ai_protocol = IPPROTO_TCP;
jbe@98 991 hints.ai_flags = AI_ADDRCONFIG;
jbe@98 992 errcode = getaddrinfo(host, port, &hints, &res);
jbe@98 993 if (errcode) {
jbe@102 994 freeaddrinfo(res);
jbe@98 995 if (errcode == EAI_SYSTEM) {
jbe@98 996 moonbr_io_errmsg();
jbe@98 997 lua_pushnil(L);
jbe@98 998 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
jbe@98 999 } else {
jbe@98 1000 lua_pushnil(L);
jbe@98 1001 lua_pushstring(L, gai_strerror(errcode));
jbe@98 1002 }
jbe@98 1003 return 2;
jbe@98 1004 }
jbe@98 1005 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1006 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
jbe@98 1007 }
jbe@98 1008 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1009 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
jbe@98 1010 }
jbe@98 1011 addrinfo = res;
jbe@98 1012 moonbr_io_tcpconnect_found:
jbe@99 1013 sock = socket(
jbe@134 1014 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
jbe@99 1015 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
jbe@99 1016 addrinfo->ai_protocol
jbe@99 1017 );
jbe@98 1018 if (sock < 0) {
jbe@98 1019 moonbr_io_errmsg();
jbe@108 1020 freeaddrinfo(res);
jbe@98 1021 lua_pushnil(L);
jbe@98 1022 lua_pushstring(L, errmsg);
jbe@108 1023 return 2;
jbe@98 1024 }
jbe@98 1025 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
jbe@108 1026 freeaddrinfo(res);
jbe@99 1027 if (!nonblocking && errno == EINTR) {
jbe@99 1028 moonbr_io_errmsg();
jbe@99 1029 close(sock);
jbe@99 1030 lua_pushnil(L);
jbe@99 1031 lua_pushstring(L, errmsg);
jbe@99 1032 return 2;
jbe@99 1033 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) {
jbe@99 1034 moonbr_io_errmsg();
jbe@99 1035 lua_pushnil(L);
jbe@99 1036 lua_pushstring(L, errmsg);
jbe@99 1037 return 2;
jbe@99 1038 }
jbe@108 1039 } else {
jbe@108 1040 freeaddrinfo(res);
jbe@98 1041 }
jbe@107 1042 moonbr_io_pushhandle(L, sock);
jbe@98 1043 return 1;
jbe@98 1044 }
jbe@98 1045
jbe@99 1046 static int moonbr_io_tcpconnect(lua_State *L) {
jbe@99 1047 return moonbr_io_tcpconnect_impl(L, 0);
jbe@99 1048 }
jbe@99 1049
jbe@99 1050 static int moonbr_io_tcpconnect_nb(lua_State *L) {
jbe@99 1051 return moonbr_io_tcpconnect_impl(L, 1);
jbe@99 1052 }
jbe@99 1053
jbe@112 1054 static int moonbr_io_locallisten(lua_State *L) {
jbe@112 1055 moonbr_io_listener_t *listener;
jbe@112 1056 const char *path;
jbe@118 1057 struct stat sb;
jbe@112 1058 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
jbe@112 1059 const int path_maxlen = sizeof(struct sockaddr_un) - (
jbe@112 1060 (void *)sockaddr.sun_path - (void *)&sockaddr
jbe@112 1061 ) - 1; /* one byte for termination */
jbe@112 1062 int sock;
jbe@112 1063 path = luaL_checkstring(L, 1);
jbe@112 1064 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
jbe@112 1065 strcpy(sockaddr.sun_path, path);
jbe@118 1066 if (stat(path, &sb) == 0) {
jbe@118 1067 if (S_ISSOCK(sb.st_mode)) unlink(path);
jbe@118 1068 }
jbe@112 1069 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
jbe@117 1070 listener->fd = -1;
jbe@112 1071 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@112 1072 sock = socket(
jbe@112 1073 PF_LOCAL,
jbe@112 1074 SOCK_STREAM | SOCK_CLOEXEC,
jbe@112 1075 0
jbe@112 1076 );
jbe@112 1077 if (sock < 0) {
jbe@112 1078 moonbr_io_errmsg();
jbe@112 1079 lua_pushnil(L);
jbe@112 1080 lua_pushstring(L, errmsg);
jbe@112 1081 return 2;
jbe@112 1082 }
jbe@112 1083 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
jbe@112 1084 moonbr_io_errmsg();
jbe@112 1085 close(sock);
jbe@112 1086 lua_pushnil(L);
jbe@112 1087 lua_pushstring(L, errmsg);
jbe@112 1088 return 2;
jbe@112 1089 }
jbe@112 1090 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
jbe@112 1091 moonbr_io_errmsg();
jbe@112 1092 close(sock);
jbe@112 1093 lua_pushnil(L);
jbe@112 1094 lua_pushstring(L, errmsg);
jbe@112 1095 return 2;
jbe@112 1096 }
jbe@112 1097 listener->fd = sock;
jbe@118 1098 listener->addrfam = AF_LOCAL;
jbe@112 1099 listener->nonblocking = -1;
jbe@112 1100 return 1;
jbe@112 1101 }
jbe@112 1102
jbe@108 1103 static int moonbr_io_tcplisten(lua_State *L) {
jbe@108 1104 moonbr_io_listener_t *listener;
jbe@108 1105 const char *host, *port;
jbe@108 1106 struct addrinfo hints = { 0, };
jbe@108 1107 struct addrinfo *res, *addrinfo;
jbe@108 1108 int errcode;
jbe@108 1109 int sock;
jbe@108 1110 host = luaL_optstring(L, 1, NULL);
jbe@108 1111 port = luaL_checkstring(L, 2);
jbe@108 1112 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
jbe@117 1113 listener->fd = -1;
jbe@108 1114 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1115 hints.ai_family = AF_UNSPEC;
jbe@108 1116 hints.ai_socktype = SOCK_STREAM;
jbe@108 1117 hints.ai_protocol = IPPROTO_TCP;
jbe@108 1118 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
jbe@108 1119 errcode = getaddrinfo(host, port, &hints, &res);
jbe@108 1120 if (errcode) {
jbe@108 1121 freeaddrinfo(res);
jbe@108 1122 if (errcode == EAI_SYSTEM) {
jbe@108 1123 moonbr_io_errmsg();
jbe@108 1124 lua_pushnil(L);
jbe@108 1125 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
jbe@108 1126 } else {
jbe@108 1127 lua_pushnil(L);
jbe@108 1128 lua_pushstring(L, gai_strerror(errcode));
jbe@108 1129 }
jbe@108 1130 return 2;
jbe@108 1131 }
jbe@108 1132 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1133 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
jbe@108 1134 }
jbe@108 1135 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1136 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
jbe@108 1137 }
jbe@108 1138 addrinfo = res;
jbe@108 1139 moonbr_io_tcpconnect_found:
jbe@118 1140 listener->addrfam = addrinfo->ai_family;
jbe@108 1141 sock = socket(
jbe@134 1142 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
jbe@108 1143 addrinfo->ai_socktype | SOCK_CLOEXEC,
jbe@108 1144 addrinfo->ai_protocol
jbe@108 1145 );
jbe@108 1146 if (sock < 0) {
jbe@108 1147 moonbr_io_errmsg();
jbe@108 1148 freeaddrinfo(res);
jbe@108 1149 lua_pushnil(L);
jbe@108 1150 lua_pushstring(L, errmsg);
jbe@108 1151 return 2;
jbe@108 1152 }
jbe@120 1153 {
jbe@120 1154 static const int reuseval = 1;
jbe@120 1155 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
jbe@120 1156 moonbr_io_errmsg();
jbe@120 1157 freeaddrinfo(res);
jbe@120 1158 close(sock);
jbe@120 1159 lua_pushnil(L);
jbe@120 1160 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
jbe@120 1161 return 2;
jbe@120 1162 }
jbe@120 1163 }
jbe@108 1164 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
jbe@108 1165 moonbr_io_errmsg();
jbe@108 1166 freeaddrinfo(res);
jbe@108 1167 close(sock);
jbe@108 1168 lua_pushnil(L);
jbe@108 1169 lua_pushstring(L, errmsg);
jbe@108 1170 return 2;
jbe@108 1171 }
jbe@108 1172 freeaddrinfo(res);
jbe@108 1173 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
jbe@108 1174 moonbr_io_errmsg();
jbe@108 1175 close(sock);
jbe@108 1176 lua_pushnil(L);
jbe@108 1177 lua_pushstring(L, errmsg);
jbe@108 1178 return 2;
jbe@108 1179 }
jbe@108 1180 listener->fd = sock;
jbe@108 1181 listener->nonblocking = -1;
jbe@108 1182 return 1;
jbe@108 1183 }
jbe@108 1184
jbe@108 1185 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
jbe@108 1186 moonbr_io_listener_t *listener;
jbe@108 1187 int fd;
jbe@108 1188 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1189 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
jbe@108 1190 if (listener->nonblocking != nonblocking) {
jbe@108 1191 int flags;
jbe@108 1192 flags = fcntl(listener->fd, F_GETFL, 0);
jbe@108 1193 if (flags == -1) {
jbe@108 1194 moonbr_io_errmsg();
jbe@108 1195 close(listener->fd);
jbe@108 1196 listener->fd = -1;
jbe@108 1197 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@108 1198 }
jbe@108 1199 if (nonblocking) flags |= O_NONBLOCK;
jbe@108 1200 else flags &= ~O_NONBLOCK;
jbe@108 1201 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
jbe@108 1202 moonbr_io_errmsg();
jbe@108 1203 close(listener->fd);
jbe@108 1204 listener->fd = -1;
jbe@108 1205 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@108 1206 }
jbe@108 1207 listener->nonblocking = nonblocking;
jbe@108 1208 }
jbe@108 1209 while (1) {
jbe@214 1210 #if defined(__linux__) && !defined(_GNU_SOURCE)
jbe@215 1211 fd = accept(listener->fd, NULL, NULL);
jbe@214 1212 if (fd != -1) {
jbe@214 1213 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
jbe@214 1214 moonbr_io_errmsg();
jbe@214 1215 close(listener->fd);
jbe@214 1216 listener->fd = -1;
jbe@214 1217 close(fd);
jbe@214 1218 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@214 1219 }
jbe@214 1220 }
jbe@214 1221 #else
jbe@108 1222 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
jbe@214 1223 #endif
jbe@108 1224 if (fd < 0) {
jbe@108 1225 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@108 1226 lua_pushboolean(L, 0);
jbe@108 1227 lua_pushliteral(L, "No incoming connection pending");
jbe@108 1228 return 2;
jbe@108 1229 } else if (errno != EINTR) {
jbe@108 1230 moonbr_io_errmsg();
jbe@108 1231 lua_pushnil(L);
jbe@108 1232 lua_pushstring(L, errmsg);
jbe@108 1233 return 2;
jbe@108 1234 }
jbe@108 1235 } else {
jbe@108 1236 moonbr_io_pushhandle(L, fd);
jbe@108 1237 return 1;
jbe@108 1238 }
jbe@108 1239 }
jbe@108 1240 }
jbe@108 1241
jbe@108 1242 static int moonbr_io_accept(lua_State *L) {
jbe@108 1243 return moonbr_io_accept_impl(L, 0);
jbe@108 1244 }
jbe@108 1245
jbe@108 1246 static int moonbr_io_accept_nb(lua_State *L) {
jbe@108 1247 return moonbr_io_accept_impl(L, 1);
jbe@108 1248 }
jbe@108 1249
jbe@108 1250 static int moonbr_io_unlisten(lua_State *L) {
jbe@108 1251 moonbr_io_listener_t *listener;
jbe@118 1252 struct sockaddr_un addr;
jbe@118 1253 socklen_t addrlen;
jbe@118 1254 struct stat sb;
jbe@108 1255 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1256 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
jbe@118 1257 addrlen = sizeof(addr);
jbe@118 1258 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
jbe@108 1259 if (close(listener->fd)) {
jbe@108 1260 moonbr_io_errmsg();
jbe@108 1261 listener->fd = -1;
jbe@118 1262 if (addrlen && addrlen <= sizeof(addr)) {
jbe@118 1263 if (stat(addr.sun_path, &sb) == 0) {
jbe@118 1264 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
jbe@118 1265 }
jbe@118 1266 }
jbe@108 1267 lua_pushnil(L);
jbe@108 1268 lua_pushstring(L, errmsg);
jbe@108 1269 return 2;
jbe@108 1270 }
jbe@108 1271 listener->fd = -1;
jbe@118 1272 if (addrlen && addrlen <= sizeof(addr)) {
jbe@118 1273 if (stat(addr.sun_path, &sb) == 0) {
jbe@118 1274 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
jbe@118 1275 }
jbe@118 1276 }
jbe@108 1277 lua_pushboolean(L, 1);
jbe@108 1278 return 1;
jbe@108 1279 }
jbe@108 1280
jbe@108 1281 static int moonbr_io_listenergc(lua_State *L) {
jbe@108 1282 moonbr_io_listener_t *listener;
jbe@108 1283 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@117 1284 if (listener->fd >= 0) close(listener->fd);
jbe@108 1285 listener->fd = -1;
jbe@108 1286 return 0;
jbe@108 1287 }
jbe@108 1288
jbe@205 1289 static int moonbr_io_exec(lua_State *L) {
jbe@205 1290 char **argv;
jbe@205 1291 int i, argc;
jbe@205 1292 int sockin[2], sockout[2], sockerr[2];
jbe@205 1293 volatile int errorcond = 0;
jbe@213 1294 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
jbe@205 1295 moonbr_io_child_t *child;
jbe@205 1296 argc = lua_gettop(L);
jbe@205 1297 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
jbe@205 1298 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
jbe@205 1299 argv[argc] = NULL;
jbe@208 1300 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
jbe@208 1301 child->pid = 0;
jbe@208 1302 lua_newtable(L);
jbe@208 1303 lua_setuservalue(L, -2);
jbe@238 1304 luaL_setmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
jbe@206 1305 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
jbe@205 1306 moonbr_io_errmsg();
jbe@205 1307 lua_pushnil(L);
jbe@205 1308 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1309 return 2;
jbe@205 1310 }
jbe@206 1311 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
jbe@205 1312 moonbr_io_errmsg();
jbe@205 1313 close(sockin[0]);
jbe@205 1314 close(sockin[1]);
jbe@205 1315 lua_pushnil(L);
jbe@205 1316 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1317 return 2;
jbe@205 1318 }
jbe@206 1319 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
jbe@205 1320 moonbr_io_errmsg();
jbe@205 1321 close(sockin[0]);
jbe@205 1322 close(sockin[1]);
jbe@205 1323 close(sockout[0]);
jbe@205 1324 close(sockout[1]);
jbe@205 1325 lua_pushnil(L);
jbe@205 1326 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1327 return 2;
jbe@205 1328 }
jbe@205 1329 child->pid = vfork();
jbe@205 1330 if (child->pid == -1) {
jbe@205 1331 moonbr_io_errmsg();
jbe@205 1332 close(sockin[0]);
jbe@205 1333 close(sockin[1]);
jbe@205 1334 close(sockout[0]);
jbe@205 1335 close(sockout[1]);
jbe@205 1336 close(sockerr[0]);
jbe@205 1337 close(sockerr[1]);
jbe@205 1338 lua_pushnil(L);
jbe@205 1339 lua_pushfstring(L, "Could not fork: %s", errmsg);
jbe@205 1340 return 2;
jbe@205 1341 }
jbe@205 1342 if (!child->pid) {
jbe@208 1343 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1344 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
jbe@208 1345 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
jbe@232 1346 closefrom(3);
jbe@208 1347 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1348 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1349 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@205 1350 if (execvp(argv[0], argv)) {
jbe@205 1351 errorcond = 2;
jbe@205 1352 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
jbe@205 1353 _exit(0);
jbe@205 1354 }
jbe@208 1355 moonbr_io_exec_error1:
jbe@206 1356 errorcond = 1;
jbe@206 1357 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
jbe@206 1358 _exit(0);
jbe@205 1359 }
jbe@205 1360 close(sockin[1]);
jbe@205 1361 close(sockout[1]);
jbe@205 1362 close(sockerr[1]);
jbe@205 1363 if (errorcond) {
jbe@205 1364 int status;
jbe@205 1365 close(sockin[0]);
jbe@205 1366 close(sockout[0]);
jbe@205 1367 close(sockerr[0]);
jbe@205 1368 while (waitpid(child->pid, &status, 0) == -1) {
jbe@205 1369 if (errno != EINTR) {
jbe@205 1370 moonbr_io_errmsg();
jbe@205 1371 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
jbe@205 1372 }
jbe@205 1373 }
jbe@208 1374 child->pid = 0;
jbe@205 1375 lua_pushnil(L);
jbe@205 1376 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
jbe@205 1377 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
jbe@205 1378 return 2;
jbe@205 1379 }
jbe@208 1380 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1381 lua_pushlightuserdata(L, &sockin[0]);
jbe@208 1382 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1383 if (sockin[0] != -1) close(sockin[0]);
jbe@208 1384 close(sockout[0]);
jbe@208 1385 close(sockerr[0]);
jbe@208 1386 goto moonbr_io_exec_error2;
jbe@208 1387 }
jbe@205 1388 lua_setfield(L, -2, "stdin");
jbe@208 1389 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1390 lua_pushlightuserdata(L, &sockout[0]);
jbe@208 1391 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1392 if (sockout[0] != -1) close(sockout[0]);
jbe@208 1393 close(sockerr[0]);
jbe@208 1394 goto moonbr_io_exec_error2;
jbe@208 1395 }
jbe@205 1396 lua_setfield(L, -2, "stdout");
jbe@208 1397 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1398 lua_pushlightuserdata(L, &sockerr[0]);
jbe@208 1399 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1400 if (sockerr[0] != -1) close(sockerr[0]);
jbe@208 1401 goto moonbr_io_exec_error2;
jbe@208 1402 }
jbe@205 1403 lua_setfield(L, -2, "stderr");
jbe@205 1404 return 1;
jbe@208 1405 moonbr_io_exec_error2:
jbe@208 1406 {
jbe@208 1407 int status;
jbe@208 1408 while (waitpid(child->pid, &status, 0) == -1) {
jbe@208 1409 if (errno != EINTR) {
jbe@208 1410 moonbr_io_errmsg();
jbe@208 1411 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
jbe@208 1412 }
jbe@208 1413 }
jbe@208 1414 }
jbe@208 1415 child->pid = 0;
jbe@208 1416 return lua_error(L);
jbe@205 1417 }
jbe@205 1418
jbe@205 1419 static int moonbr_io_childindex(lua_State *L) {
jbe@205 1420 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1421 luaL_checkany(L, 2);
jbe@205 1422 lua_getuservalue(L, 1);
jbe@205 1423 lua_pushvalue(L, 2);
jbe@205 1424 lua_gettable(L, -2);
jbe@205 1425 if (lua_isnil(L, -1)) {
jbe@205 1426 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
jbe@205 1427 lua_pushvalue(L, 2);
jbe@205 1428 lua_gettable(L, -2);
jbe@205 1429 }
jbe@205 1430 return 1;
jbe@205 1431 }
jbe@205 1432
jbe@205 1433 static int moonbr_io_childnewindex(lua_State *L) {
jbe@205 1434 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1435 luaL_checkany(L, 2);
jbe@205 1436 luaL_checkany(L, 3);
jbe@205 1437 lua_getuservalue(L, 1);
jbe@205 1438 lua_pushvalue(L, 2);
jbe@205 1439 lua_pushvalue(L, 3);
jbe@205 1440 lua_settable(L, -3);
jbe@205 1441 return 0;
jbe@205 1442 }
jbe@205 1443
jbe@205 1444 static int moonbr_io_childgc(lua_State *L) {
jbe@205 1445 moonbr_io_child_t *child;
jbe@205 1446 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1447 if (child->pid) {
jbe@205 1448 int status;
jbe@205 1449 if (kill(child->pid, SIGKILL)) {
jbe@205 1450 moonbr_io_errmsg();
jbe@205 1451 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
jbe@205 1452 }
jbe@205 1453 while (waitpid(child->pid, &status, 0) == -1) {
jbe@205 1454 if (errno != EINTR) {
jbe@205 1455 moonbr_io_errmsg();
jbe@205 1456 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
jbe@205 1457 }
jbe@205 1458 }
jbe@205 1459 }
jbe@205 1460 return 0;
jbe@205 1461 }
jbe@205 1462
jbe@205 1463 static int moonbr_io_kill(lua_State *L) {
jbe@205 1464 moonbr_io_child_t *child;
jbe@205 1465 int sig;
jbe@205 1466 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1467 sig = luaL_optinteger(L, 2, SIGTERM);
jbe@205 1468 if (!child->pid) luaL_error(L, "Attempt to kill an already collected child process");
jbe@205 1469 if (kill(child->pid, sig)) {
jbe@205 1470 moonbr_io_errmsg();
jbe@205 1471 luaL_error(L, "Error in kill call: %s", errmsg);
jbe@205 1472 }
jbe@205 1473 lua_settop(L, 1);
jbe@205 1474 return 1;
jbe@205 1475 }
jbe@205 1476
jbe@205 1477 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
jbe@205 1478 moonbr_io_child_t *child;
jbe@205 1479 pid_t waitedpid;
jbe@205 1480 int status;
jbe@205 1481 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1482 if (!child->pid) luaL_error(L, "Attempt to wait for an already collected child process");
jbe@205 1483 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
jbe@205 1484 if (errno != EINTR) {
jbe@205 1485 moonbr_io_errmsg();
jbe@205 1486 luaL_error(L, "Error in waitpid call: %s", errmsg);
jbe@205 1487 }
jbe@205 1488 }
jbe@205 1489 if (!waitedpid) {
jbe@219 1490 lua_pushboolean(L, 0);
jbe@219 1491 lua_pushliteral(L, "Process is still running");
jbe@219 1492 return 2;
jbe@205 1493 } else {
jbe@205 1494 child->pid = 0;
jbe@205 1495 if (WIFEXITED(status)) {
jbe@205 1496 lua_pushinteger(L, WEXITSTATUS(status));
jbe@205 1497 } else if (WIFSIGNALED(status)) {
jbe@205 1498 lua_pushinteger(L, -WTERMSIG(status));
jbe@205 1499 } else {
jbe@205 1500 luaL_error(L, "Unexpected status value returned by waitpid call");
jbe@205 1501 }
jbe@219 1502 return 1;
jbe@205 1503 }
jbe@205 1504 }
jbe@205 1505
jbe@205 1506 static int moonbr_io_wait(lua_State *L) {
jbe@205 1507 return moonbr_io_wait_impl(L, 0);
jbe@205 1508 }
jbe@205 1509
jbe@205 1510 static int moonbr_io_wait_nb(lua_State *L) {
jbe@205 1511 return moonbr_io_wait_impl(L, 1);
jbe@205 1512 }
jbe@205 1513
jbe@205 1514 #if LUA_VERSION_NUM >= 503
jbe@205 1515 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
jbe@205 1516 #else
jbe@205 1517 static int moonbr_io_wait_cont(lua_State *L) {
jbe@205 1518 #endif
jbe@205 1519 #if !(LUA_VERSION_NUM >= 503)
jbe@205 1520 int ctx = 0;
jbe@205 1521 lua_getctx(L, &ctx);
jbe@205 1522 #endif
jbe@205 1523 while (1) {
jbe@205 1524 lua_pushcfunction(L, moonbr_io_wait_nb);
jbe@205 1525 lua_pushvalue(L, 1);
jbe@205 1526 lua_call(L, 1, 1);
jbe@205 1527 if (!lua_isnil(L, -1)) break;
jbe@205 1528 lua_pushvalue(L, 2);
jbe@205 1529 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
jbe@205 1530 }
jbe@205 1531 return 1;
jbe@205 1532 }
jbe@205 1533
jbe@205 1534 static int moonbr_io_wait_call(lua_State *L) {
jbe@205 1535 lua_settop(L, 2);
jbe@205 1536 #if LUA_VERSION_NUM >= 503
jbe@205 1537 return moonbr_io_wait_cont(L, 0, 0);
jbe@205 1538 #else
jbe@205 1539 return moonbr_io_wait_cont(L);
jbe@205 1540 #endif
jbe@205 1541 }
jbe@205 1542
jbe@205 1543 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
jbe@205 1544
jbe@106 1545 static int moonbr_io_poll(lua_State *L) {
jbe@106 1546 moonbr_io_handle_t *handle;
jbe@108 1547 moonbr_io_listener_t *listener;
jbe@106 1548 int fd, isnum;
jbe@106 1549 int nfds = 0;
jbe@106 1550 fd_set readfds, writefds, exceptfds;
jbe@106 1551 struct timeval timeout = {0, };
jbe@106 1552 int status;
jbe@106 1553 FD_ZERO(&readfds);
jbe@106 1554 FD_ZERO(&writefds);
jbe@106 1555 FD_ZERO(&exceptfds);
jbe@106 1556 if (!lua_isnoneornil(L, 1)) {
jbe@106 1557 luaL_checktype(L, 1, LUA_TTABLE);
jbe@106 1558 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
jbe@106 1559 if (lua_toboolean(L, -1)) {
jbe@106 1560 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 1561 if (handle) {
jbe@109 1562 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
jbe@106 1563 fd = handle->fd;
jbe@247 1564 #if MOONBR_IO_USE_TLS
jbe@247 1565 if (handle->tls && tls_handshake(handle->tls) == TLS_WANT_POLLOUT) {
jbe@247 1566 if (fd < 0) {
jbe@247 1567 // TODO?
jbe@247 1568 lua_pushboolean(L, 1);
jbe@247 1569 return 1;
jbe@247 1570 }
jbe@247 1571 FD_SET(fd, &writefds);
jbe@247 1572 if (fd+1 > nfds) nfds = fd+1;
jbe@247 1573 continue;
jbe@247 1574 }
jbe@247 1575 #endif
jbe@122 1576 if (
jbe@122 1577 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
jbe@122 1578 handle->readbufin != handle->readbufout /* data pending in buffer */
jbe@122 1579 ) {
jbe@109 1580 lua_pushboolean(L, 1);
jbe@109 1581 return 1;
jbe@109 1582 }
jbe@106 1583 } else {
jbe@108 1584 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1585 if (listener) {
jbe@108 1586 fd = listener->fd;
jbe@108 1587 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
jbe@108 1588 } else {
jbe@108 1589 fd = lua_tointegerx(L, -2, &isnum);
jbe@108 1590 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
jbe@108 1591 }
jbe@106 1592 }
jbe@138 1593 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
jbe@106 1594 FD_SET(fd, &readfds);
jbe@106 1595 if (fd+1 > nfds) nfds = fd+1;
jbe@106 1596 }
jbe@106 1597 }
jbe@106 1598 }
jbe@106 1599 if (!lua_isnoneornil(L, 2)) {
jbe@106 1600 luaL_checktype(L, 2, LUA_TTABLE);
jbe@106 1601 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
jbe@106 1602 if (lua_toboolean(L, -1)) {
jbe@106 1603 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 1604 if (handle) {
jbe@109 1605 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
jbe@109 1606 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
jbe@106 1607 fd = handle->fd;
jbe@247 1608 #if MOONBR_IO_USE_TLS
jbe@247 1609 if (handle->tls && tls_handshake(handle->tls) == TLS_WANT_POLLIN) {
jbe@247 1610 FD_SET(fd, &readfds);
jbe@247 1611 if (fd+1 > nfds) nfds = fd+1;
jbe@247 1612 continue;
jbe@247 1613 }
jbe@247 1614 #endif
jbe@106 1615 } else {
jbe@108 1616 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@109 1617 if (listener) luaL_error(L, "Attempt to write-poll a listener");
jbe@109 1618 fd = lua_tointegerx(L, -2, &isnum);
jbe@109 1619 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
jbe@106 1620 }
jbe@138 1621 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
jbe@106 1622 FD_SET(fd, &writefds);
jbe@106 1623 if (fd+1 > nfds) nfds = fd+1;
jbe@106 1624 }
jbe@106 1625 }
jbe@106 1626 }
jbe@106 1627 if (!lua_isnoneornil(L, 3)) {
jbe@106 1628 lua_Number n;
jbe@106 1629 n = lua_tonumberx(L, 3, &isnum);
jbe@146 1630 if (isnum && n<0) {
jbe@146 1631 lua_pushboolean(L, 0);
jbe@146 1632 lua_pushliteral(L, "Negative timeout");
jbe@146 1633 return 2;
jbe@146 1634 } else if (isnum && n>=0 && n<100000000) {
jbe@106 1635 timeout.tv_sec = n;
jbe@106 1636 timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
jbe@106 1637 } else {
jbe@106 1638 luaL_argcheck(L, 0, 3, "not a valid timeout");
jbe@106 1639 }
jbe@106 1640 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
jbe@106 1641 } else {
jbe@106 1642 status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
jbe@106 1643 }
jbe@106 1644 if (status == -1) {
jbe@106 1645 if (errno == EINTR) {
jbe@146 1646 lua_pushnil(L);
jbe@106 1647 lua_pushliteral(L, "Signal received while polling file descriptors");
jbe@106 1648 return 2;
jbe@106 1649 } else {
jbe@106 1650 moonbr_io_errmsg();
jbe@106 1651 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
jbe@106 1652 }
jbe@106 1653 } else if (status == 0) {
jbe@106 1654 lua_pushboolean(L, 0);
jbe@106 1655 lua_pushliteral(L, "Timeout while polling file descriptors");
jbe@106 1656 return 2;
jbe@106 1657 } else {
jbe@106 1658 lua_pushboolean(L, 1);
jbe@106 1659 return 1;
jbe@106 1660 }
jbe@106 1661 }
jbe@106 1662
jbe@115 1663 static int moonbr_io_timeref(lua_State *L) {
jbe@115 1664 lua_Number sub;
jbe@115 1665 struct timespec tp;
jbe@115 1666 sub = luaL_optnumber(L, 1, 0);
jbe@115 1667 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
jbe@115 1668 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
jbe@115 1669 }
jbe@115 1670 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
jbe@115 1671 return 1;
jbe@115 1672 }
jbe@115 1673
jbe@243 1674 #ifdef MOONBR_IO_USE_TLS
jbe@243 1675
jbe@243 1676 #define moonbr_io_tlsconf_string(name, field, func) \
jbe@243 1677 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
jbe@243 1678 lua_getfield(L, 1, (field)); \
jbe@243 1679 valuetype = lua_type(L, -1); \
jbe@243 1680 if (valuetype != LUA_TNIL) { \
jbe@243 1681 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
jbe@243 1682 value = lua_tostring(L, -1); \
jbe@243 1683 if (func(tlsconf, value)) { \
jbe@243 1684 lua_pushnil(L); \
jbe@243 1685 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
jbe@243 1686 return 2; \
jbe@243 1687 } \
jbe@243 1688 } \
jbe@243 1689 lua_pop(L, 1);
jbe@243 1690
jbe@243 1691 #define moonbr_io_tlsconf_binary(name, field, func) \
jbe@243 1692 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
jbe@243 1693 lua_getfield(L, 1, (field)); \
jbe@243 1694 valuetype = lua_type(L, -1); \
jbe@243 1695 if (valuetype != LUA_TNIL) { \
jbe@243 1696 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
jbe@243 1697 value = lua_tolstring(L, -1, &valuelen); \
jbe@243 1698 if (func(tlsconf, (void *)value, valuelen)) { \
jbe@243 1699 lua_pushnil(L); \
jbe@243 1700 lua_pushliteral(L, "Could not set " name); \
jbe@243 1701 return 2; \
jbe@243 1702 } \
jbe@243 1703 } \
jbe@243 1704 lua_pop(L, 1);
jbe@243 1705
jbe@243 1706 static int moonbr_io_tlsconf(lua_State *L) {
jbe@243 1707 struct tls_config *tlsconf;
jbe@243 1708 int valuetype;
jbe@243 1709 const char *value;
jbe@243 1710 size_t valuelen;
jbe@243 1711 luaL_checktype(L, 1, LUA_TTABLE);
jbe@243 1712 tlsconf = tls_config_new();
jbe@243 1713 if (!tlsconf) {
jbe@243 1714 return luaL_error(L, "Could not allocate memory for TLS configuration");
jbe@243 1715 }
jbe@243 1716 lua_pushlightuserdata(L, tlsconf);
jbe@243 1717 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@243 1718 lua_pushvalue(L, 1);
jbe@243 1719 lua_setuservalue(L, -2);
jbe@245 1720 #if LUA_VERSION_NUM >= 503
jbe@245 1721 if (lua_getfield(L, 1, "mode") == LUA_TSTRING) value = lua_tostring(L, -1);
jbe@245 1722 #else
jbe@245 1723 lua_getfield(L, 1, "mode");
jbe@245 1724 if (lua_type(L, -1) == LUA_TSTRING) value = lua_tostring(L, -1);
jbe@245 1725 #endif
jbe@245 1726 else value = "";
jbe@245 1727 if (strcmp(value, "server") && strcmp(value, "client")) {
jbe@245 1728 luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
jbe@245 1729 }
jbe@245 1730 lua_pop(L, 1);
jbe@243 1731 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
jbe@243 1732 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
jbe@243 1733 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
jbe@243 1734 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
jbe@243 1735 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
jbe@243 1736 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
jbe@243 1737 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
jbe@245 1738 #if LUA_VERSION_NUM >= 503
jbe@245 1739 valuetype = lua_getfield(L, 1, "verify_client");
jbe@245 1740 #else
jbe@244 1741 lua_getfield(L, 1, "verify_client");
jbe@245 1742 #endif
jbe@244 1743 if (lua_toboolean(L, -1)) {
jbe@245 1744 #if LUA_VERSION_NUM >= 503
jbe@245 1745 if (valuetype == LUA_TSTRING) value = lua_tostring(L, -1);
jbe@245 1746 #else
jbe@244 1747 if (lua_type(L, -1) == LUA_TSTRING) value = lua_tostring(L, -1);
jbe@245 1748 #endif
jbe@244 1749 else value = "";
jbe@244 1750 if (!strcmp(value, "required")) {
jbe@244 1751 tls_config_verify_client(tlsconf);
jbe@244 1752 } else if (!strcmp(value, "optional")) {
jbe@244 1753 tls_config_verify_client_optional(tlsconf);
jbe@244 1754 } else {
jbe@244 1755 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
jbe@244 1756 }
jbe@244 1757 }
jbe@244 1758 lua_pop(L, 1);
jbe@243 1759 return 1;
jbe@243 1760 }
jbe@243 1761
jbe@243 1762 static int moonbr_io_tlsconfindex(lua_State *L) {
jbe@243 1763 struct tls_config *tlsconf;
jbe@243 1764 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@243 1765 luaL_checkany(L, 2);
jbe@243 1766 #if LUA_VERSION_NUM >= 503
jbe@243 1767 if (lua_getuservalue(L, 1) == LUA_TNIL) {
jbe@243 1768 #else
jbe@243 1769 lua_getuservalue(L, 1);
jbe@243 1770 if (lua_isnil(L, -1)) {
jbe@243 1771 #endif
jbe@243 1772 return luaL_error(L, "Attempt to use a destroyed TLS configuration");
jbe@243 1773 }
jbe@243 1774 lua_pushvalue(L, 2);
jbe@243 1775 lua_gettable(L, -2);
jbe@243 1776 return 1;
jbe@243 1777 }
jbe@243 1778
jbe@243 1779 static int moonbr_io_tlsconfgc(lua_State *L) {
jbe@243 1780 struct tls_config *tlsconf;
jbe@243 1781 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@243 1782 #if LUA_VERSION_NUM >= 503
jbe@243 1783 if (lua_getuservalue(L, 1) == LUA_TNIL) return 0;
jbe@243 1784 #else
jbe@243 1785 lua_getuservalue(L, 1);
jbe@243 1786 if (lua_isnil(L, -1)) return 0;
jbe@243 1787 #endif
jbe@243 1788 tls_config_free(tlsconf);
jbe@243 1789 lua_pushnil(L);
jbe@243 1790 lua_setuservalue(L, 1);
jbe@243 1791 return 0;
jbe@243 1792 }
jbe@243 1793
jbe@246 1794 static int moonbr_io_starttls(lua_State *L) {
jbe@246 1795 moonbr_io_handle_t *handle;
jbe@246 1796 struct tls_config *tlsconf;
jbe@246 1797 const char *mode;
jbe@246 1798 const char *servername;
jbe@246 1799 struct tls *tls, *tls2;
jbe@246 1800 int is_server = 0;
jbe@246 1801 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@246 1802 if (lua_type(L, 2) == LUA_TTABLE) {
jbe@246 1803 lua_pushcfunction(L, moonbr_io_tlsconf);
jbe@246 1804 lua_pushvalue(L, 2);
jbe@246 1805 lua_call(L, 1, 2);
jbe@246 1806 if (lua_isnil(L, -2)) return 2;
jbe@246 1807 lua_pop(L, 1);
jbe@246 1808 lua_replace(L, 2);
jbe@246 1809 }
jbe@246 1810 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@246 1811 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
jbe@246 1812 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
jbe@247 1813 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
jbe@246 1814 if (handle->readbufin || handle->writebufin) {
jbe@246 1815 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
jbe@246 1816 }
jbe@246 1817 lua_getfield(L, 2, "mode");
jbe@246 1818 mode = lua_tostring(L, -1);
jbe@246 1819 if (mode && !strcmp(mode, "server")) {
jbe@246 1820 lua_pop(L, 1);
jbe@246 1821 tls = tls_server();
jbe@246 1822 is_server = 1;
jbe@246 1823 } else if (mode && !strcmp(mode, "client")) {
jbe@246 1824 lua_pop(L, 1);
jbe@246 1825 servername = luaL_checkstring(L, 3);
jbe@246 1826 tls = tls_client();
jbe@246 1827 } else {
jbe@246 1828 /* shouldn't happen unless table has been modified */
jbe@246 1829 lua_pop(L, 1);
jbe@246 1830 return luaL_error(L, "Field \"mode\" of TLS configuration is neither set to \"server\" nor \"client\"");
jbe@246 1831 }
jbe@246 1832 if (!tls) {
jbe@246 1833 return luaL_error(L, "Could not allocate memory for TLS context");
jbe@246 1834 }
jbe@246 1835 if (tls_configure(tls, tlsconf)) goto moonbr_io_starttls_error;
jbe@246 1836 if (is_server) {
jbe@246 1837 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
jbe@246 1838 handle->servertls = tls;
jbe@246 1839 handle->tls = tls2;
jbe@246 1840 } else {
jbe@246 1841 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
jbe@246 1842 handle->tls = tls;
jbe@246 1843 }
jbe@246 1844 lua_settop(L, 1);
jbe@246 1845 return 1;
jbe@246 1846 moonbr_io_starttls_error:
jbe@246 1847 lua_pushnil(L);
jbe@246 1848 lua_pushstring(L, tls_error(tls));
jbe@246 1849 tls_free(tls);
jbe@246 1850 return 2;
jbe@246 1851 }
jbe@246 1852
jbe@243 1853 #endif
jbe@243 1854
jbe@79 1855 static const struct luaL_Reg moonbr_io_handle_methods[] = {
jbe@85 1856 {"read", moonbr_io_read},
jbe@85 1857 {"read_nb", moonbr_io_read_nb},
jbe@140 1858 {"read_call", moonbr_io_read_call},
jbe@140 1859 {"read_yield", moonbr_io_read_yield},
jbe@86 1860 {"drain", moonbr_io_drain},
jbe@86 1861 {"drain_nb", moonbr_io_drain_nb},
jbe@144 1862 {"drain_call", moonbr_io_drain_call},
jbe@144 1863 {"drain_yield", moonbr_io_drain_yield},
jbe@80 1864 {"write", moonbr_io_write},
jbe@81 1865 {"write_nb", moonbr_io_write_nb},
jbe@145 1866 {"write_call", moonbr_io_write_call},
jbe@145 1867 {"write_yield", moonbr_io_write_yield},
jbe@80 1868 {"flush", moonbr_io_flush},
jbe@81 1869 {"flush_nb", moonbr_io_flush_nb},
jbe@145 1870 {"flush_call", moonbr_io_flush_call},
jbe@145 1871 {"flush_yield", moonbr_io_flush_yield},
jbe@88 1872 {"finish", moonbr_io_finish},
jbe@87 1873 {"close", moonbr_io_close},
jbe@85 1874 {"reset", moonbr_io_reset},
jbe@246 1875 #ifdef MOONBR_IO_USE_TLS
jbe@246 1876 {"starttls", moonbr_io_starttls},
jbe@246 1877 #endif
jbe@79 1878 {NULL, NULL}
jbe@79 1879 };
jbe@79 1880
jbe@79 1881 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
jbe@79 1882 {"__index", moonbr_io_handleindex},
jbe@79 1883 {"__newindex", moonbr_io_handlenewindex},
jbe@108 1884 {"__gc", moonbr_io_handlegc},
jbe@108 1885 {NULL, NULL}
jbe@108 1886 };
jbe@108 1887
jbe@108 1888 static const struct luaL_Reg moonbr_io_listener_methods[] = {
jbe@108 1889 {"accept", moonbr_io_accept},
jbe@108 1890 {"accept_nb", moonbr_io_accept_nb},
jbe@108 1891 {"close", moonbr_io_unlisten},
jbe@108 1892 {NULL, NULL}
jbe@108 1893 };
jbe@108 1894
jbe@108 1895 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
jbe@108 1896 {"__gc", moonbr_io_listenergc},
jbe@79 1897 {NULL, NULL}
jbe@79 1898 };
jbe@79 1899
jbe@205 1900 static const struct luaL_Reg moonbr_io_child_methods[] = {
jbe@205 1901 {"kill", moonbr_io_kill},
jbe@205 1902 {"wait", moonbr_io_wait},
jbe@205 1903 {"wait_nb", moonbr_io_wait_nb},
jbe@205 1904 {"wait_call", moonbr_io_wait_call},
jbe@205 1905 {"wait_yield", moonbr_io_wait_yield},
jbe@205 1906 {NULL, NULL}
jbe@205 1907 };
jbe@205 1908
jbe@205 1909 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
jbe@205 1910 {"__index", moonbr_io_childindex},
jbe@205 1911 {"__newindex", moonbr_io_childnewindex},
jbe@205 1912 {"__gc", moonbr_io_childgc},
jbe@205 1913 {NULL, NULL}
jbe@205 1914 };
jbe@205 1915
jbe@79 1916 static const struct luaL_Reg moonbr_io_module_funcs[] = {
jbe@111 1917 {"localconnect", moonbr_io_localconnect},
jbe@111 1918 {"localconnect_nb", moonbr_io_localconnect_nb},
jbe@98 1919 {"tcpconnect", moonbr_io_tcpconnect},
jbe@99 1920 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
jbe@112 1921 {"locallisten", moonbr_io_locallisten},
jbe@108 1922 {"tcplisten", moonbr_io_tcplisten},
jbe@205 1923 {"exec", moonbr_io_exec},
jbe@106 1924 {"poll", moonbr_io_poll},
jbe@115 1925 {"timeref", moonbr_io_timeref},
jbe@243 1926 #ifdef MOONBR_IO_USE_TLS
jbe@243 1927 {"tlsconf", moonbr_io_tlsconf},
jbe@243 1928 #endif
jbe@79 1929 {NULL, NULL}
jbe@79 1930 };
jbe@79 1931
jbe@243 1932 #ifdef MOONBR_IO_USE_TLS
jbe@243 1933 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
jbe@243 1934 {"__index", moonbr_io_tlsconfindex},
jbe@243 1935 {"__gc", moonbr_io_tlsconfgc},
jbe@243 1936 {NULL, NULL}
jbe@243 1937 };
jbe@243 1938 #endif
jbe@243 1939
jbe@79 1940 int luaopen_moonbridge_io(lua_State *L) {
jbe@79 1941
jbe@113 1942 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
jbe@113 1943
jbe@80 1944 lua_newtable(L); // module
jbe@80 1945
jbe@79 1946 lua_newtable(L); // public metatable
jbe@79 1947 lua_newtable(L); // handle methods
jbe@79 1948 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
jbe@80 1949 lua_pushvalue(L, -1);
jbe@146 1950 lua_setfield(L, -4, "handle_pt");
jbe@79 1951 lua_setfield(L, -2, "__index");
jbe@79 1952 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
jbe@79 1953
jbe@79 1954 lua_newtable(L); // handle metatable
jbe@79 1955 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
jbe@146 1956 lua_pushvalue(L, -1);
jbe@146 1957 lua_setfield(L, -3, "handle_mt");
jbe@79 1958 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 1959
jbe@108 1960 lua_newtable(L); // listener metatable
jbe@108 1961 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
jbe@108 1962 lua_newtable(L); // listener methods
jbe@108 1963 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
jbe@108 1964 lua_pushvalue(L, -1);
jbe@146 1965 lua_setfield(L, -4, "listener_pt");
jbe@108 1966 lua_setfield(L, -2, "__index");
jbe@146 1967 lua_pushvalue(L, -1);
jbe@146 1968 lua_setfield(L, -3, "listener_mt");
jbe@108 1969 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1970
jbe@205 1971 lua_newtable(L); // child methods
jbe@205 1972 luaL_setfuncs(L, moonbr_io_child_methods, 0);
jbe@205 1973 lua_pushvalue(L, -1);
jbe@205 1974 lua_setfield(L, -3, "child_pt");
jbe@205 1975 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
jbe@205 1976 lua_newtable(L); // child metatable
jbe@205 1977 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
jbe@205 1978 lua_pushvalue(L, -1);
jbe@205 1979 lua_setfield(L, -3, "child_mt");
jbe@205 1980 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1981
jbe@243 1982 #ifdef MOONBR_IO_USE_TLS
jbe@243 1983 if(tls_init()) {
jbe@243 1984 return luaL_error(L, "Could not initialize TLS library");
jbe@243 1985 }
jbe@243 1986 lua_newtable(L); // tlsconf metatable
jbe@243 1987 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
jbe@243 1988 lua_pushvalue(L, -1);
jbe@243 1989 lua_setfield(L, -3, "tlsconf_mt");
jbe@243 1990 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@243 1991 #endif
jbe@243 1992
jbe@205 1993 moonbr_io_pushhandle(L, 0);
jbe@205 1994 lua_setfield(L, -2, "stdin");
jbe@205 1995 moonbr_io_pushhandle(L, 1);
jbe@205 1996 lua_setfield(L, -2, "stdout");
jbe@205 1997 moonbr_io_pushhandle(L, 2);
jbe@205 1998 lua_setfield(L, -2, "stderr");
jbe@205 1999
jbe@79 2000 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
jbe@79 2001 return 1;
jbe@79 2002
jbe@79 2003 }
jbe@79 2004

Impressum / About Us