moonbridge

annotate moonbridge_io.c @ 327:a8b1012856a5

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

Impressum / About Us