moonbridge

annotate moonbridge_io.c @ 249:53962483bf1c

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

Impressum / About Us