moonbridge

annotate moonbridge_io.c @ 325:73c009c2f389

Use "cc -shared" instead of "ld -shared" to create *.so files
author jbe
date Sat Oct 19 14:56:47 2019 +0200 (8 months ago)
parents fe1a134a92a4
children 4379766473ec
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@111 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@102 1191 freeaddrinfo(res);
jbe@98 1192 if (errcode == EAI_SYSTEM) {
jbe@257 1193 moonbr_io_prepare_errmsg();
jbe@98 1194 lua_pushnil(L);
jbe@98 1195 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
jbe@98 1196 } else {
jbe@98 1197 lua_pushnil(L);
jbe@98 1198 lua_pushstring(L, gai_strerror(errcode));
jbe@98 1199 }
jbe@98 1200 return 2;
jbe@98 1201 }
jbe@98 1202 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1203 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
jbe@98 1204 }
jbe@98 1205 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1206 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
jbe@98 1207 }
jbe@98 1208 addrinfo = res;
jbe@98 1209 moonbr_io_tcpconnect_found:
jbe@99 1210 sock = socket(
jbe@134 1211 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
jbe@99 1212 addrinfo->ai_socktype | SOCK_CLOEXEC | (nonblocking ? SOCK_NONBLOCK : 0),
jbe@99 1213 addrinfo->ai_protocol
jbe@99 1214 );
jbe@98 1215 if (sock < 0) {
jbe@257 1216 moonbr_io_prepare_errmsg();
jbe@108 1217 freeaddrinfo(res);
jbe@257 1218 moonbr_io_return_prepared_errmsg();
jbe@98 1219 }
jbe@98 1220 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
jbe@108 1221 freeaddrinfo(res);
jbe@99 1222 if (!nonblocking && errno == EINTR) {
jbe@257 1223 moonbr_io_prepare_errmsg();
jbe@99 1224 close(sock);
jbe@257 1225 moonbr_io_return_prepared_errmsg();
jbe@257 1226 } else if (!(nonblocking && (errno == EINPROGRESS || errno == EINTR))) moonbr_io_return_errmsg();
jbe@108 1227 } else {
jbe@108 1228 freeaddrinfo(res);
jbe@98 1229 }
jbe@311 1230 if (nonblocking) {
jbe@311 1231 moonbr_io_pushhandle_skip_peeraddr(L, sock);
jbe@311 1232 if (addrinfo->ai_family == AF_INET6) {
jbe@311 1233 // TODO: fill remote_ip6 and remote_tcpport
jbe@311 1234 } else if (addrinfo->ai_family == AF_INET) {
jbe@311 1235 // TODO: fill remote_ip4 and remote_tcpport
jbe@311 1236 }
jbe@311 1237 } else {
jbe@311 1238 moonbr_io_pushhandle(L, sock);
jbe@311 1239 }
jbe@98 1240 return 1;
jbe@98 1241 }
jbe@98 1242
jbe@99 1243 static int moonbr_io_tcpconnect(lua_State *L) {
jbe@99 1244 return moonbr_io_tcpconnect_impl(L, 0);
jbe@99 1245 }
jbe@99 1246
jbe@99 1247 static int moonbr_io_tcpconnect_nb(lua_State *L) {
jbe@99 1248 return moonbr_io_tcpconnect_impl(L, 1);
jbe@99 1249 }
jbe@99 1250
jbe@112 1251 static int moonbr_io_locallisten(lua_State *L) {
jbe@112 1252 moonbr_io_listener_t *listener;
jbe@112 1253 const char *path;
jbe@118 1254 struct stat sb;
jbe@112 1255 struct sockaddr_un sockaddr = { .sun_family = AF_LOCAL };
jbe@112 1256 const int path_maxlen = sizeof(struct sockaddr_un) - (
jbe@112 1257 (void *)sockaddr.sun_path - (void *)&sockaddr
jbe@112 1258 ) - 1; /* one byte for termination */
jbe@112 1259 int sock;
jbe@112 1260 path = luaL_checkstring(L, 1);
jbe@112 1261 if (strlen(path) > path_maxlen) luaL_error(L, "Path too long; only %i characters allowed", path_maxlen);
jbe@112 1262 strcpy(sockaddr.sun_path, path);
jbe@118 1263 if (stat(path, &sb) == 0) {
jbe@118 1264 if (S_ISSOCK(sb.st_mode)) unlink(path);
jbe@118 1265 }
jbe@112 1266 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
jbe@117 1267 listener->fd = -1;
jbe@112 1268 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@112 1269 sock = socket(
jbe@112 1270 PF_LOCAL,
jbe@112 1271 SOCK_STREAM | SOCK_CLOEXEC,
jbe@112 1272 0
jbe@112 1273 );
jbe@257 1274 if (sock < 0) moonbr_io_return_errmsg();
jbe@112 1275 if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
jbe@257 1276 moonbr_io_prepare_errmsg();
jbe@112 1277 close(sock);
jbe@257 1278 moonbr_io_return_prepared_errmsg();
jbe@112 1279 }
jbe@112 1280 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
jbe@257 1281 moonbr_io_prepare_errmsg();
jbe@112 1282 close(sock);
jbe@257 1283 moonbr_io_return_prepared_errmsg();
jbe@112 1284 }
jbe@112 1285 listener->fd = sock;
jbe@118 1286 listener->addrfam = AF_LOCAL;
jbe@112 1287 listener->nonblocking = -1;
jbe@112 1288 return 1;
jbe@112 1289 }
jbe@112 1290
jbe@108 1291 static int moonbr_io_tcplisten(lua_State *L) {
jbe@108 1292 moonbr_io_listener_t *listener;
jbe@108 1293 const char *host, *port;
jbe@108 1294 struct addrinfo hints = { 0, };
jbe@108 1295 struct addrinfo *res, *addrinfo;
jbe@108 1296 int errcode;
jbe@108 1297 int sock;
jbe@108 1298 host = luaL_optstring(L, 1, NULL);
jbe@108 1299 port = luaL_checkstring(L, 2);
jbe@108 1300 listener = lua_newuserdata(L, sizeof(moonbr_io_listener_t));
jbe@117 1301 listener->fd = -1;
jbe@108 1302 luaL_setmetatable(L, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1303 hints.ai_family = AF_UNSPEC;
jbe@108 1304 hints.ai_socktype = SOCK_STREAM;
jbe@108 1305 hints.ai_protocol = IPPROTO_TCP;
jbe@108 1306 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
jbe@108 1307 errcode = getaddrinfo(host, port, &hints, &res);
jbe@108 1308 if (errcode) {
jbe@108 1309 freeaddrinfo(res);
jbe@108 1310 if (errcode == EAI_SYSTEM) {
jbe@257 1311 moonbr_io_prepare_errmsg();
jbe@108 1312 lua_pushnil(L);
jbe@108 1313 lua_pushfstring(L, "%s: %s", gai_strerror(errcode), errmsg);
jbe@108 1314 } else {
jbe@108 1315 lua_pushnil(L);
jbe@108 1316 lua_pushstring(L, gai_strerror(errcode));
jbe@108 1317 }
jbe@108 1318 return 2;
jbe@108 1319 }
jbe@108 1320 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1321 if (addrinfo->ai_family == AF_INET6) goto moonbr_io_tcpconnect_found;
jbe@108 1322 }
jbe@108 1323 for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
jbe@134 1324 if (addrinfo->ai_family == AF_INET) goto moonbr_io_tcpconnect_found;
jbe@108 1325 }
jbe@108 1326 addrinfo = res;
jbe@108 1327 moonbr_io_tcpconnect_found:
jbe@118 1328 listener->addrfam = addrinfo->ai_family;
jbe@108 1329 sock = socket(
jbe@134 1330 addrinfo->ai_family, /* NOTE: not correctly using PF_* but AF_* constants here */
jbe@108 1331 addrinfo->ai_socktype | SOCK_CLOEXEC,
jbe@108 1332 addrinfo->ai_protocol
jbe@108 1333 );
jbe@108 1334 if (sock < 0) {
jbe@257 1335 moonbr_io_prepare_errmsg();
jbe@108 1336 freeaddrinfo(res);
jbe@257 1337 moonbr_io_return_prepared_errmsg();
jbe@108 1338 }
jbe@120 1339 {
jbe@120 1340 static const int reuseval = 1;
jbe@120 1341 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval))) {
jbe@257 1342 moonbr_io_prepare_errmsg();
jbe@120 1343 freeaddrinfo(res);
jbe@120 1344 close(sock);
jbe@120 1345 lua_pushnil(L);
jbe@120 1346 lua_pushfstring(L, "Error while setting SO_REUSEADDR with setsockopt: %s", errmsg);
jbe@120 1347 return 2;
jbe@120 1348 }
jbe@120 1349 }
jbe@108 1350 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen)) {
jbe@257 1351 moonbr_io_prepare_errmsg();
jbe@108 1352 freeaddrinfo(res);
jbe@108 1353 close(sock);
jbe@257 1354 moonbr_io_return_prepared_errmsg();
jbe@108 1355 }
jbe@108 1356 freeaddrinfo(res);
jbe@108 1357 if (listen(sock, MOONBR_IO_LISTEN_BACKLOG)) {
jbe@257 1358 moonbr_io_prepare_errmsg();
jbe@108 1359 close(sock);
jbe@257 1360 moonbr_io_return_prepared_errmsg();
jbe@108 1361 }
jbe@108 1362 listener->fd = sock;
jbe@108 1363 listener->nonblocking = -1;
jbe@108 1364 return 1;
jbe@108 1365 }
jbe@108 1366
jbe@108 1367 static int moonbr_io_accept_impl(lua_State *L, int nonblocking) {
jbe@108 1368 moonbr_io_listener_t *listener;
jbe@108 1369 int fd;
jbe@108 1370 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1371 if (listener->fd < 0) luaL_error(L, "Attempt to use a closed listener");
jbe@108 1372 if (listener->nonblocking != nonblocking) {
jbe@108 1373 int flags;
jbe@108 1374 flags = fcntl(listener->fd, F_GETFL, 0);
jbe@108 1375 if (flags == -1) {
jbe@257 1376 moonbr_io_prepare_errmsg();
jbe@108 1377 close(listener->fd);
jbe@108 1378 listener->fd = -1;
jbe@108 1379 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@108 1380 }
jbe@108 1381 if (nonblocking) flags |= O_NONBLOCK;
jbe@108 1382 else flags &= ~O_NONBLOCK;
jbe@108 1383 if (fcntl(listener->fd, F_SETFL, flags) == -1) {
jbe@257 1384 moonbr_io_prepare_errmsg();
jbe@108 1385 close(listener->fd);
jbe@108 1386 listener->fd = -1;
jbe@108 1387 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@108 1388 }
jbe@108 1389 listener->nonblocking = nonblocking;
jbe@108 1390 }
jbe@108 1391 while (1) {
jbe@214 1392 #if defined(__linux__) && !defined(_GNU_SOURCE)
jbe@215 1393 fd = accept(listener->fd, NULL, NULL);
jbe@214 1394 if (fd != -1) {
jbe@214 1395 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
jbe@257 1396 moonbr_io_prepare_errmsg();
jbe@214 1397 close(listener->fd);
jbe@214 1398 listener->fd = -1;
jbe@214 1399 close(fd);
jbe@214 1400 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
jbe@214 1401 }
jbe@214 1402 }
jbe@214 1403 #else
jbe@108 1404 fd = accept4(listener->fd, NULL, NULL, SOCK_CLOEXEC);
jbe@214 1405 #endif
jbe@108 1406 if (fd < 0) {
jbe@108 1407 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
jbe@108 1408 lua_pushboolean(L, 0);
jbe@108 1409 lua_pushliteral(L, "No incoming connection pending");
jbe@108 1410 return 2;
jbe@257 1411 } else if (errno != EINTR) moonbr_io_return_errmsg();
jbe@108 1412 } else {
jbe@108 1413 moonbr_io_pushhandle(L, fd);
jbe@108 1414 return 1;
jbe@108 1415 }
jbe@108 1416 }
jbe@108 1417 }
jbe@108 1418
jbe@108 1419 static int moonbr_io_accept(lua_State *L) {
jbe@108 1420 return moonbr_io_accept_impl(L, 0);
jbe@108 1421 }
jbe@108 1422
jbe@108 1423 static int moonbr_io_accept_nb(lua_State *L) {
jbe@108 1424 return moonbr_io_accept_impl(L, 1);
jbe@108 1425 }
jbe@108 1426
jbe@108 1427 static int moonbr_io_unlisten(lua_State *L) {
jbe@108 1428 moonbr_io_listener_t *listener;
jbe@118 1429 struct sockaddr_un addr;
jbe@118 1430 socklen_t addrlen;
jbe@118 1431 struct stat sb;
jbe@108 1432 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1433 if (listener->fd < 0) luaL_error(L, "Attempt to close a closed listener");
jbe@118 1434 addrlen = sizeof(addr);
jbe@118 1435 if (getsockname(listener->fd, (struct sockaddr *)&addr, &addrlen)) addrlen = 0;
jbe@108 1436 if (close(listener->fd)) {
jbe@257 1437 moonbr_io_prepare_errmsg();
jbe@108 1438 listener->fd = -1;
jbe@118 1439 if (addrlen && addrlen <= sizeof(addr)) {
jbe@118 1440 if (stat(addr.sun_path, &sb) == 0) {
jbe@118 1441 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
jbe@118 1442 }
jbe@118 1443 }
jbe@257 1444 moonbr_io_return_prepared_errmsg();
jbe@108 1445 }
jbe@108 1446 listener->fd = -1;
jbe@118 1447 if (addrlen && addrlen <= sizeof(addr)) {
jbe@118 1448 if (stat(addr.sun_path, &sb) == 0) {
jbe@118 1449 if (S_ISSOCK(sb.st_mode)) unlink(addr.sun_path);
jbe@118 1450 }
jbe@118 1451 }
jbe@108 1452 lua_pushboolean(L, 1);
jbe@108 1453 return 1;
jbe@108 1454 }
jbe@108 1455
jbe@108 1456 static int moonbr_io_listenergc(lua_State *L) {
jbe@108 1457 moonbr_io_listener_t *listener;
jbe@108 1458 listener = luaL_checkudata(L, 1, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@117 1459 if (listener->fd >= 0) close(listener->fd);
jbe@108 1460 listener->fd = -1;
jbe@108 1461 return 0;
jbe@108 1462 }
jbe@108 1463
jbe@205 1464 static int moonbr_io_exec(lua_State *L) {
jbe@205 1465 char **argv;
jbe@205 1466 int i, argc;
jbe@205 1467 int sockin[2], sockout[2], sockerr[2];
jbe@205 1468 volatile int errorcond = 0;
jbe@213 1469 volatile char errmsgbuf[MOONBR_IO_MAXSTRERRORLEN] = MOONBR_IO_STRERROR_R_MSG;
jbe@205 1470 moonbr_io_child_t *child;
jbe@205 1471 argc = lua_gettop(L);
jbe@205 1472 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *));
jbe@205 1473 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1);
jbe@205 1474 argv[argc] = NULL;
jbe@208 1475 child = lua_newuserdata(L, sizeof(moonbr_io_child_t));
jbe@208 1476 child->pid = 0;
jbe@303 1477 child->status_valid = 0;
jbe@208 1478 lua_newtable(L);
jbe@208 1479 lua_setuservalue(L, -2);
jbe@238 1480 luaL_setmetatable(L, MOONBR_IO_CHILD_MT_REGKEY);
jbe@206 1481 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) {
jbe@257 1482 moonbr_io_prepare_errmsg();
jbe@205 1483 lua_pushnil(L);
jbe@205 1484 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1485 return 2;
jbe@205 1486 }
jbe@206 1487 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockout)) {
jbe@257 1488 moonbr_io_prepare_errmsg();
jbe@205 1489 close(sockin[0]);
jbe@205 1490 close(sockin[1]);
jbe@205 1491 lua_pushnil(L);
jbe@205 1492 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1493 return 2;
jbe@205 1494 }
jbe@206 1495 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockerr)) {
jbe@257 1496 moonbr_io_prepare_errmsg();
jbe@205 1497 close(sockin[0]);
jbe@205 1498 close(sockin[1]);
jbe@205 1499 close(sockout[0]);
jbe@205 1500 close(sockout[1]);
jbe@205 1501 lua_pushnil(L);
jbe@205 1502 lua_pushfstring(L, "Could not create socket pair: %s", errmsg);
jbe@205 1503 return 2;
jbe@205 1504 }
jbe@205 1505 child->pid = vfork();
jbe@205 1506 if (child->pid == -1) {
jbe@257 1507 moonbr_io_prepare_errmsg();
jbe@205 1508 close(sockin[0]);
jbe@205 1509 close(sockin[1]);
jbe@205 1510 close(sockout[0]);
jbe@205 1511 close(sockout[1]);
jbe@205 1512 close(sockerr[0]);
jbe@205 1513 close(sockerr[1]);
jbe@205 1514 lua_pushnil(L);
jbe@205 1515 lua_pushfstring(L, "Could not fork: %s", errmsg);
jbe@205 1516 return 2;
jbe@205 1517 }
jbe@205 1518 if (!child->pid) {
jbe@208 1519 if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1520 if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1;
jbe@208 1521 if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1;
jbe@232 1522 closefrom(3);
jbe@208 1523 if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1524 if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@208 1525 if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1;
jbe@205 1526 if (execvp(argv[0], argv)) {
jbe@205 1527 errorcond = 2;
jbe@205 1528 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
jbe@205 1529 _exit(0);
jbe@205 1530 }
jbe@208 1531 moonbr_io_exec_error1:
jbe@206 1532 errorcond = 1;
jbe@206 1533 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN);
jbe@206 1534 _exit(0);
jbe@205 1535 }
jbe@205 1536 close(sockin[1]);
jbe@205 1537 close(sockout[1]);
jbe@205 1538 close(sockerr[1]);
jbe@205 1539 if (errorcond) {
jbe@205 1540 int status;
jbe@205 1541 close(sockin[0]);
jbe@205 1542 close(sockout[0]);
jbe@205 1543 close(sockerr[0]);
jbe@205 1544 while (waitpid(child->pid, &status, 0) == -1) {
jbe@205 1545 if (errno != EINTR) {
jbe@257 1546 moonbr_io_prepare_errmsg();
jbe@205 1547 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg);
jbe@205 1548 }
jbe@205 1549 }
jbe@208 1550 child->pid = 0;
jbe@205 1551 lua_pushnil(L);
jbe@205 1552 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf);
jbe@205 1553 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf);
jbe@205 1554 return 2;
jbe@205 1555 }
jbe@208 1556 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1557 lua_pushlightuserdata(L, &sockin[0]);
jbe@208 1558 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1559 if (sockin[0] != -1) close(sockin[0]);
jbe@208 1560 close(sockout[0]);
jbe@208 1561 close(sockerr[0]);
jbe@208 1562 goto moonbr_io_exec_error2;
jbe@208 1563 }
jbe@205 1564 lua_setfield(L, -2, "stdin");
jbe@208 1565 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1566 lua_pushlightuserdata(L, &sockout[0]);
jbe@208 1567 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1568 if (sockout[0] != -1) close(sockout[0]);
jbe@208 1569 close(sockerr[0]);
jbe@208 1570 goto moonbr_io_exec_error2;
jbe@208 1571 }
jbe@205 1572 lua_setfield(L, -2, "stdout");
jbe@208 1573 lua_pushcfunction(L, moonbr_io_pushhandle_impl);
jbe@208 1574 lua_pushlightuserdata(L, &sockerr[0]);
jbe@208 1575 if (lua_pcall(L, 1, 1, 0)) {
jbe@208 1576 if (sockerr[0] != -1) close(sockerr[0]);
jbe@208 1577 goto moonbr_io_exec_error2;
jbe@208 1578 }
jbe@205 1579 lua_setfield(L, -2, "stderr");
jbe@205 1580 return 1;
jbe@208 1581 moonbr_io_exec_error2:
jbe@208 1582 {
jbe@208 1583 int status;
jbe@208 1584 while (waitpid(child->pid, &status, 0) == -1) {
jbe@208 1585 if (errno != EINTR) {
jbe@257 1586 moonbr_io_prepare_errmsg();
jbe@208 1587 luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg);
jbe@208 1588 }
jbe@208 1589 }
jbe@208 1590 }
jbe@208 1591 child->pid = 0;
jbe@208 1592 return lua_error(L);
jbe@205 1593 }
jbe@205 1594
jbe@205 1595 static int moonbr_io_childindex(lua_State *L) {
jbe@205 1596 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1597 luaL_checkany(L, 2);
jbe@205 1598 lua_getuservalue(L, 1);
jbe@205 1599 lua_pushvalue(L, 2);
jbe@205 1600 lua_gettable(L, -2);
jbe@205 1601 if (lua_isnil(L, -1)) {
jbe@205 1602 luaL_getmetatable(L, MOONBR_IO_CHILD_PT_REGKEY);
jbe@205 1603 lua_pushvalue(L, 2);
jbe@205 1604 lua_gettable(L, -2);
jbe@205 1605 }
jbe@205 1606 return 1;
jbe@205 1607 }
jbe@205 1608
jbe@205 1609 static int moonbr_io_childnewindex(lua_State *L) {
jbe@205 1610 luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1611 luaL_checkany(L, 2);
jbe@205 1612 luaL_checkany(L, 3);
jbe@205 1613 lua_getuservalue(L, 1);
jbe@205 1614 lua_pushvalue(L, 2);
jbe@205 1615 lua_pushvalue(L, 3);
jbe@205 1616 lua_settable(L, -3);
jbe@205 1617 return 0;
jbe@205 1618 }
jbe@205 1619
jbe@205 1620 static int moonbr_io_childgc(lua_State *L) {
jbe@205 1621 moonbr_io_child_t *child;
jbe@205 1622 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 1623 if (child->pid) {
jbe@205 1624 int status;
jbe@281 1625 int pid = child->pid;
jbe@281 1626 child->pid = 0;
jbe@281 1627 if (kill(pid, SIGKILL)) {
jbe@257 1628 moonbr_io_prepare_errmsg();
jbe@205 1629 luaL_error(L, "Error in kill call during garbage collection: %s", errmsg);
jbe@205 1630 }
jbe@281 1631 while (waitpid(pid, &status, 0) == -1) {
jbe@205 1632 if (errno != EINTR) {
jbe@257 1633 moonbr_io_prepare_errmsg();
jbe@205 1634 luaL_error(L, "Error in waitpid call during garbage collection: %s", errmsg);
jbe@205 1635 }
jbe@205 1636 }
jbe@205 1637 }
jbe@205 1638 return 0;
jbe@205 1639 }
jbe@205 1640
jbe@205 1641 static int moonbr_io_kill(lua_State *L) {
jbe@205 1642 moonbr_io_child_t *child;
jbe@205 1643 int sig;
jbe@205 1644 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@285 1645 sig = luaL_optinteger(L, 2, SIGKILL);
jbe@303 1646 if (!child->pid) {
jbe@303 1647 if (!child->status_valid) luaL_error(L, "Attempt to kill an already collected child process");
jbe@303 1648 } else {
jbe@303 1649 if (kill(child->pid, sig)) {
jbe@303 1650 moonbr_io_prepare_errmsg();
jbe@303 1651 luaL_error(L, "Error in kill call: %s", errmsg);
jbe@303 1652 }
jbe@205 1653 }
jbe@205 1654 lua_settop(L, 1);
jbe@205 1655 return 1;
jbe@205 1656 }
jbe@205 1657
jbe@205 1658 static int moonbr_io_wait_impl(lua_State *L, int nonblocking) {
jbe@205 1659 moonbr_io_child_t *child;
jbe@205 1660 int status;
jbe@205 1661 child = luaL_checkudata(L, 1, MOONBR_IO_CHILD_MT_REGKEY);
jbe@303 1662 if (!child->pid) {
jbe@303 1663 if (!child->status_valid) luaL_error(L, "Attempt to wait for an already collected child process");
jbe@303 1664 status = child->status;
jbe@303 1665 child->status_valid = 0;
jbe@303 1666 } else {
jbe@303 1667 pid_t waitedpid;
jbe@303 1668 while ((waitedpid = waitpid(child->pid, &status, nonblocking ? WNOHANG : 0)) == -1) {
jbe@303 1669 if (errno != EINTR) {
jbe@303 1670 moonbr_io_prepare_errmsg();
jbe@303 1671 luaL_error(L, "Error in waitpid call: %s", errmsg);
jbe@303 1672 }
jbe@205 1673 }
jbe@303 1674 if (!waitedpid) {
jbe@303 1675 lua_pushboolean(L, 0);
jbe@303 1676 lua_pushliteral(L, "Process is still running");
jbe@303 1677 return 2;
jbe@303 1678 }
jbe@303 1679 child->pid = 0;
jbe@205 1680 }
jbe@303 1681 if (WIFEXITED(status)) {
jbe@303 1682 lua_pushinteger(L, WEXITSTATUS(status));
jbe@303 1683 } else if (WIFSIGNALED(status)) {
jbe@303 1684 lua_pushinteger(L, -WTERMSIG(status));
jbe@205 1685 } else {
jbe@303 1686 luaL_error(L, "Unexpected status value returned by waitpid call");
jbe@205 1687 }
jbe@303 1688 return 1;
jbe@205 1689 }
jbe@205 1690
jbe@205 1691 static int moonbr_io_wait(lua_State *L) {
jbe@205 1692 return moonbr_io_wait_impl(L, 0);
jbe@205 1693 }
jbe@205 1694
jbe@205 1695 static int moonbr_io_wait_nb(lua_State *L) {
jbe@205 1696 return moonbr_io_wait_impl(L, 1);
jbe@205 1697 }
jbe@205 1698
jbe@205 1699 #if LUA_VERSION_NUM >= 503
jbe@205 1700 static int moonbr_io_wait_cont(lua_State *L, int status, lua_KContext ctx) {
jbe@205 1701 #else
jbe@205 1702 static int moonbr_io_wait_cont(lua_State *L) {
jbe@205 1703 #endif
jbe@205 1704 #if !(LUA_VERSION_NUM >= 503)
jbe@205 1705 int ctx = 0;
jbe@315 1706 int status = lua_getctx(L, &ctx);
jbe@205 1707 #endif
jbe@205 1708 while (1) {
jbe@205 1709 lua_pushcfunction(L, moonbr_io_wait_nb);
jbe@205 1710 lua_pushvalue(L, 1);
jbe@205 1711 lua_call(L, 1, 1);
jbe@205 1712 if (!lua_isnil(L, -1)) break;
jbe@205 1713 lua_pushvalue(L, 2);
jbe@315 1714 lua_pushvalue(L, 1);
jbe@315 1715 lua_pushliteral(L, "r");
jbe@315 1716 lua_pushboolean(L, status != LUA_YIELD);
jbe@315 1717 lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
jbe@205 1718 lua_callk(L, 0, 0, ctx, moonbr_io_wait_cont);
jbe@315 1719 status = LUA_YIELD;
jbe@205 1720 }
jbe@205 1721 return 1;
jbe@205 1722 }
jbe@205 1723
jbe@205 1724 static int moonbr_io_wait_call(lua_State *L) {
jbe@205 1725 lua_settop(L, 2);
jbe@205 1726 #if LUA_VERSION_NUM >= 503
jbe@205 1727 return moonbr_io_wait_cont(L, 0, 0);
jbe@205 1728 #else
jbe@205 1729 return moonbr_io_wait_cont(L);
jbe@205 1730 #endif
jbe@205 1731 }
jbe@205 1732
jbe@205 1733 moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
jbe@205 1734
jbe@284 1735 static void moonbr_io_sigterm_handler(int sig) {
jbe@284 1736 moonbr_io_sigterm_flag = 1;
jbe@266 1737 }
jbe@266 1738
jbe@297 1739 static void moonbr_io_sigchld_handler(int sig) {
jbe@297 1740 moonbr_io_sigchld_flag = 1;
jbe@297 1741 }
jbe@297 1742
jbe@288 1743 int moonbr_io_catch_sigterm(lua_State *L) {
jbe@284 1744 signal(SIGTERM, moonbr_io_sigterm_handler);
jbe@284 1745 return 0;
jbe@284 1746 }
jbe@284 1747
jbe@266 1748 static int moonbr_io_getpid(lua_State *L) {
jbe@266 1749 lua_pushinteger(L, getpid());
jbe@266 1750 return 1;
jbe@266 1751 }
jbe@266 1752
jbe@250 1753 #ifdef MOONBR_IO_USE_TLS
jbe@258 1754
jbe@250 1755 #define moonbr_io_poll_tls() \
jbe@250 1756 if (!handle->tlshandshake) { \
jbe@295 1757 force_wakeup = 1; \
jbe@295 1758 continue; \
jbe@250 1759 } \
jbe@250 1760 if (handle->tlshandshake == TLS_WANT_POLLIN) { \
jbe@250 1761 if (fd < 0) { \
jbe@295 1762 force_wakeup = 1; \
jbe@295 1763 continue; \
jbe@250 1764 } \
jbe@250 1765 FD_SET(fd, &readfds); \
jbe@250 1766 if (fd+1 > nfds) nfds = fd+1; \
jbe@250 1767 continue; \
jbe@250 1768 } \
jbe@250 1769 if (handle->tlshandshake == TLS_WANT_POLLOUT) { \
jbe@250 1770 if (fd < 0) { \
jbe@295 1771 force_wakeup = 1; \
jbe@295 1772 continue; \
jbe@250 1773 } \
jbe@250 1774 FD_SET(fd, &writefds); \
jbe@250 1775 if (fd+1 > nfds) nfds = fd+1; \
jbe@250 1776 continue; \
jbe@250 1777 } \
jbe@250 1778 while (0)
jbe@258 1779
jbe@258 1780 #endif /* MOONBR_IO_USE_TLS */
jbe@250 1781
jbe@106 1782 static int moonbr_io_poll(lua_State *L) {
jbe@106 1783 moonbr_io_handle_t *handle;
jbe@108 1784 moonbr_io_listener_t *listener;
jbe@296 1785 moonbr_io_child_t *child;
jbe@106 1786 int fd, isnum;
jbe@106 1787 int nfds = 0;
jbe@106 1788 fd_set readfds, writefds, exceptfds;
jbe@284 1789 struct timespec timeout = {0, };
jbe@295 1790 int force_wakeup = 0;
jbe@288 1791 int use_timeout = 0; // negative for negative timeout
jbe@284 1792 int check_sigterm = 0;
jbe@297 1793 int check_sigchld = 0;
jbe@298 1794 pid_t waitedpid;
jbe@284 1795 sigset_t mask, orig_mask;
jbe@106 1796 int status;
jbe@106 1797 FD_ZERO(&readfds);
jbe@106 1798 FD_ZERO(&writefds);
jbe@106 1799 FD_ZERO(&exceptfds);
jbe@106 1800 if (!lua_isnoneornil(L, 1)) {
jbe@106 1801 luaL_checktype(L, 1, LUA_TTABLE);
jbe@106 1802 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
jbe@106 1803 if (lua_toboolean(L, -1)) {
jbe@106 1804 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 1805 if (handle) {
jbe@109 1806 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
jbe@106 1807 fd = handle->fd;
jbe@247 1808 #if MOONBR_IO_USE_TLS
jbe@250 1809 moonbr_io_poll_tls();
jbe@247 1810 #endif
jbe@122 1811 if (
jbe@122 1812 fd < 0 || /* fake EOF to simulate shutdown if fd < 0 */
jbe@122 1813 handle->readbufin != handle->readbufout /* data pending in buffer */
jbe@122 1814 ) {
jbe@295 1815 force_wakeup = 1;
jbe@295 1816 continue;
jbe@109 1817 }
jbe@106 1818 } else {
jbe@108 1819 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 1820 if (listener) {
jbe@108 1821 fd = listener->fd;
jbe@108 1822 if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
jbe@108 1823 } else {
jbe@296 1824 child = luaL_testudata(L, -2, MOONBR_IO_CHILD_MT_REGKEY);
jbe@296 1825 if (child) {
jbe@299 1826 if (!child->pid) luaL_error(L, "Attemt to poll an already collected child process");
jbe@297 1827 if (!check_sigchld) {
jbe@297 1828 check_sigchld = 1;
jbe@297 1829 moonbr_io_sigchld_flag = 0;
jbe@297 1830 signal(SIGCHLD, moonbr_io_sigchld_handler);
jbe@297 1831 }
jbe@303 1832 if (child->status_valid) {
jbe@303 1833 force_wakeup = 1;
jbe@303 1834 } else {
jbe@303 1835 while ((waitedpid = waitpid(child->pid, &status, WNOHANG)) == -1) {
jbe@303 1836 if (errno != EINTR) {
jbe@303 1837 moonbr_io_prepare_errmsg();
jbe@303 1838 luaL_error(L, "Error in waitpid call: %s", errmsg);
jbe@303 1839 }
jbe@303 1840 }
jbe@303 1841 if (waitedpid) {
jbe@303 1842 child->pid = 0;
jbe@303 1843 child->status = status;
jbe@303 1844 child->status_valid = 1;
jbe@303 1845 force_wakeup = 1;
jbe@298 1846 }
jbe@298 1847 }
jbe@296 1848 continue;
jbe@296 1849 } else {
jbe@296 1850 fd = lua_tointegerx(L, -2, &isnum);
jbe@296 1851 if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
jbe@296 1852 }
jbe@108 1853 }
jbe@106 1854 }
jbe@138 1855 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
jbe@106 1856 FD_SET(fd, &readfds);
jbe@106 1857 if (fd+1 > nfds) nfds = fd+1;
jbe@106 1858 }
jbe@106 1859 }
jbe@106 1860 }
jbe@106 1861 if (!lua_isnoneornil(L, 2)) {
jbe@106 1862 luaL_checktype(L, 2, LUA_TTABLE);
jbe@106 1863 for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
jbe@106 1864 if (lua_toboolean(L, -1)) {
jbe@106 1865 handle = luaL_testudata(L, -2, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@106 1866 if (handle) {
jbe@109 1867 if (handle->closed) luaL_error(L, "Attempt to poll a closed connection");
jbe@109 1868 if (handle->finished) luaL_error(L, "Attempt to write-poll a finished connection");
jbe@106 1869 fd = handle->fd;
jbe@247 1870 #if MOONBR_IO_USE_TLS
jbe@250 1871 moonbr_io_poll_tls();
jbe@247 1872 #endif
jbe@106 1873 } else {
jbe@108 1874 listener = luaL_testudata(L, -2, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@109 1875 if (listener) luaL_error(L, "Attempt to write-poll a listener");
jbe@109 1876 fd = lua_tointegerx(L, -2, &isnum);
jbe@109 1877 if (!isnum) luaL_error(L, "Expected integer (file descriptor) or I/O handle in table key");
jbe@106 1878 }
jbe@138 1879 if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
jbe@106 1880 FD_SET(fd, &writefds);
jbe@106 1881 if (fd+1 > nfds) nfds = fd+1;
jbe@106 1882 }
jbe@106 1883 }
jbe@106 1884 }
jbe@106 1885 if (!lua_isnoneornil(L, 3)) {
jbe@106 1886 lua_Number n;
jbe@106 1887 n = lua_tonumberx(L, 3, &isnum);
jbe@146 1888 if (isnum && n<0) {
jbe@288 1889 use_timeout = -1;
jbe@146 1890 } else if (isnum && n>=0 && n<100000000) {
jbe@288 1891 use_timeout = 1;
jbe@106 1892 timeout.tv_sec = n;
jbe@284 1893 timeout.tv_nsec = 1e9 * (n - timeout.tv_sec);
jbe@106 1894 } else {
jbe@106 1895 luaL_argcheck(L, 0, 3, "not a valid timeout");
jbe@106 1896 }
jbe@284 1897 }
jbe@295 1898 if (use_timeout < 0) force_wakeup = 1;
jbe@284 1899 if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN);
jbe@284 1900 check_sigterm = lua_toboolean(L, 4);
jbe@297 1901 if ((check_sigterm || check_sigchld) && !force_wakeup) {
jbe@296 1902 sigemptyset(&mask);
jbe@296 1903 if (check_sigterm) sigaddset(&mask, SIGTERM);
jbe@297 1904 if (check_sigchld) sigaddset(&mask, SIGCHLD);
jbe@296 1905 if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort();
jbe@296 1906 }
jbe@296 1907 if (check_sigterm && moonbr_io_sigterm_flag) {
jbe@295 1908 if (!force_wakeup) {
jbe@296 1909 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
jbe@295 1910 }
jbe@296 1911 lua_pushboolean(L, 0);
jbe@296 1912 lua_pushliteral(L, "SIGTERM received");
jbe@296 1913 lua_pushboolean(L, 1);
jbe@296 1914 return 3;
jbe@296 1915 }
jbe@297 1916 if (check_sigchld && !force_wakeup && moonbr_io_sigchld_flag) {
jbe@297 1917 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
jbe@297 1918 force_wakeup = 1;
jbe@288 1919 }
jbe@288 1920 if (use_timeout < 0) {
jbe@288 1921 lua_pushboolean(L, 0);
jbe@290 1922 lua_pushliteral(L, "Timeout");
jbe@288 1923 if (check_sigterm) {
jbe@288 1924 lua_pushboolean(L, 0);
jbe@288 1925 return 3;
jbe@288 1926 } else {
jbe@284 1927 return 2;
jbe@284 1928 }
jbe@284 1929 }
jbe@295 1930 if (!force_wakeup) {
jbe@295 1931 status = pselect(
jbe@295 1932 nfds, &readfds, &writefds, &exceptfds,
jbe@295 1933 use_timeout ? &timeout : NULL,
jbe@301 1934 (check_sigterm || check_sigchld) ? &orig_mask : NULL
jbe@295 1935 );
jbe@301 1936 if (check_sigterm || check_sigchld) {
jbe@295 1937 if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
jbe@301 1938 if (check_sigterm && moonbr_io_sigterm_flag) {
jbe@295 1939 lua_pushboolean(L, 0);
jbe@295 1940 lua_pushliteral(L, "SIGTERM received");
jbe@295 1941 lua_pushboolean(L, 1);
jbe@295 1942 return 3;
jbe@295 1943 }
jbe@295 1944 }
jbe@295 1945 if (status == -1) {
jbe@295 1946 if (errno == EINTR) {
jbe@295 1947 lua_pushboolean(L, 1);
jbe@295 1948 return 1;
jbe@295 1949 } else {
jbe@295 1950 moonbr_io_prepare_errmsg();
jbe@295 1951 return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
jbe@295 1952 }
jbe@295 1953 } else if (status == 0) {
jbe@292 1954 lua_pushboolean(L, 0);
jbe@295 1955 lua_pushliteral(L, "Timeout");
jbe@295 1956 if (check_sigterm) {
jbe@295 1957 lua_pushboolean(L, 0);
jbe@295 1958 return 3;
jbe@295 1959 } else {
jbe@295 1960 return 2;
jbe@295 1961 }
jbe@292 1962 }
jbe@106 1963 }
jbe@295 1964 lua_pushboolean(L, 1);
jbe@295 1965 return 1;
jbe@106 1966 }
jbe@106 1967
jbe@115 1968 static int moonbr_io_timeref(lua_State *L) {
jbe@115 1969 lua_Number sub;
jbe@115 1970 struct timespec tp;
jbe@115 1971 sub = luaL_optnumber(L, 1, 0);
jbe@115 1972 if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
jbe@115 1973 return luaL_error(L, "Could not access CLOCK_MONOTONIC");
jbe@115 1974 }
jbe@115 1975 lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub);
jbe@115 1976 return 1;
jbe@115 1977 }
jbe@115 1978
jbe@243 1979 #ifdef MOONBR_IO_USE_TLS
jbe@243 1980
jbe@243 1981 #define moonbr_io_tlsconf_string(name, field, func) \
jbe@243 1982 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
jbe@243 1983 lua_getfield(L, 1, (field)); \
jbe@243 1984 valuetype = lua_type(L, -1); \
jbe@243 1985 if (valuetype != LUA_TNIL) { \
jbe@243 1986 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
jbe@243 1987 value = lua_tostring(L, -1); \
jbe@252 1988 if (func(tlsconf->config, value)) { \
jbe@243 1989 lua_pushnil(L); \
jbe@243 1990 lua_pushfstring(L, "Could not set " name " \"%s\"", value); \
jbe@243 1991 return 2; \
jbe@243 1992 } \
jbe@243 1993 } \
jbe@243 1994 lua_pop(L, 1);
jbe@243 1995
jbe@243 1996 #define moonbr_io_tlsconf_binary(name, field, func) \
jbe@243 1997 /* NOTE: use valuetype = lua_getfield(...) for LUA_VERSION_NUM >= 503 */ \
jbe@243 1998 lua_getfield(L, 1, (field)); \
jbe@243 1999 valuetype = lua_type(L, -1); \
jbe@243 2000 if (valuetype != LUA_TNIL) { \
jbe@243 2001 luaL_argcheck(L, valuetype == LUA_TSTRING, 1, "field \"" field "\" is not a string"); \
jbe@243 2002 value = lua_tolstring(L, -1, &valuelen); \
jbe@252 2003 if (func(tlsconf->config, (void *)value, valuelen)) { \
jbe@243 2004 lua_pushnil(L); \
jbe@243 2005 lua_pushliteral(L, "Could not set " name); \
jbe@243 2006 return 2; \
jbe@243 2007 } \
jbe@243 2008 } \
jbe@243 2009 lua_pop(L, 1);
jbe@243 2010
jbe@243 2011 static int moonbr_io_tlsconf(lua_State *L) {
jbe@252 2012 moonbr_io_tlsconf_t *tlsconf;
jbe@243 2013 int valuetype;
jbe@243 2014 const char *value;
jbe@243 2015 size_t valuelen;
jbe@243 2016 luaL_checktype(L, 1, LUA_TTABLE);
jbe@252 2017 tlsconf = lua_newuserdata(L, sizeof(moonbr_io_tlsconf_t));
jbe@252 2018 tlsconf->config = tls_config_new();
jbe@252 2019 if (!tlsconf->config) {
jbe@243 2020 return luaL_error(L, "Could not allocate memory for TLS configuration");
jbe@243 2021 }
jbe@243 2022 luaL_setmetatable(L, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@245 2023 lua_getfield(L, 1, "mode");
jbe@252 2024 value = lua_tostring(L, -1);
jbe@252 2025 if (value && !strcmp(value, "server")) tlsconf->server = 1;
jbe@252 2026 else if (value && !strcmp(value, "client")) tlsconf->server = 0;
jbe@252 2027 else luaL_argcheck(L, 0, 1, "field \"mode\" must be set to \"server\" or \"client\"");
jbe@245 2028 lua_pop(L, 1);
jbe@243 2029 moonbr_io_tlsconf_string("CA file", "ca_file", tls_config_set_ca_file);
jbe@243 2030 moonbr_io_tlsconf_string("CA path", "ca_path", tls_config_set_ca_path);
jbe@243 2031 moonbr_io_tlsconf_binary("CA", "ca_mem", tls_config_set_ca_mem);
jbe@243 2032 moonbr_io_tlsconf_string("certificate file", "cert_file", tls_config_set_cert_file);
jbe@243 2033 moonbr_io_tlsconf_binary("certificate", "cert_mem", tls_config_set_cert_mem);
jbe@243 2034 moonbr_io_tlsconf_string("key file", "key_file", tls_config_set_key_file);
jbe@243 2035 moonbr_io_tlsconf_binary("key", "key_mem", tls_config_set_key_mem);
jbe@245 2036 #if LUA_VERSION_NUM >= 503
jbe@245 2037 valuetype = lua_getfield(L, 1, "verify_client");
jbe@245 2038 #else
jbe@244 2039 lua_getfield(L, 1, "verify_client");
jbe@245 2040 #endif
jbe@244 2041 if (lua_toboolean(L, -1)) {
jbe@252 2042 value = lua_tostring(L, -1);
jbe@252 2043 if (value && !strcmp(value, "required")) {
jbe@252 2044 tls_config_verify_client(tlsconf->config);
jbe@252 2045 } else if (value && !strcmp(value, "optional")) {
jbe@252 2046 tls_config_verify_client_optional(tlsconf->config);
jbe@244 2047 } else {
jbe@244 2048 luaL_argcheck(L, 0, 1, "field \"verify_client\" must be set to \"required\", \"optional\", or be false or nil");
jbe@244 2049 }
jbe@244 2050 }
jbe@244 2051 lua_pop(L, 1);
jbe@254 2052 // TODO: configurable legacy support
jbe@254 2053 // tls_config_set_protocols(tlsconf->config, TLS_PROTOCOLS_ALL);
jbe@254 2054 // tls_config_set_ciphers(tlsconf->config, "legacy");
jbe@243 2055 return 1;
jbe@243 2056 }
jbe@243 2057
jbe@252 2058 static int moonbr_io_tlsconfgc(lua_State *L) {
jbe@252 2059 moonbr_io_tlsconf_t *tlsconf;
jbe@243 2060 tlsconf = luaL_checkudata(L, 1, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@252 2061 if (tlsconf->config) tls_config_free(tlsconf->config);
jbe@252 2062 tlsconf->config = NULL;
jbe@243 2063 return 0;
jbe@243 2064 }
jbe@243 2065
jbe@246 2066 static int moonbr_io_starttls(lua_State *L) {
jbe@246 2067 moonbr_io_handle_t *handle;
jbe@252 2068 moonbr_io_tlsconf_t *tlsconf;
jbe@246 2069 const char *servername;
jbe@246 2070 struct tls *tls, *tls2;
jbe@246 2071 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@246 2072 if (lua_type(L, 2) == LUA_TTABLE) {
jbe@246 2073 lua_pushcfunction(L, moonbr_io_tlsconf);
jbe@246 2074 lua_pushvalue(L, 2);
jbe@246 2075 lua_call(L, 1, 2);
jbe@246 2076 if (lua_isnil(L, -2)) return 2;
jbe@246 2077 lua_pop(L, 1);
jbe@246 2078 lua_replace(L, 2);
jbe@246 2079 }
jbe@246 2080 tlsconf = luaL_checkudata(L, 2, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@246 2081 if (handle->closed) return luaL_error(L, "Attempt to start TLS on a closed I/O handle");
jbe@246 2082 if (handle->finished) return luaL_error(L, "Attempt to start TLS on a finished I/O handle");
jbe@247 2083 if (handle->tls) return luaL_error(L, "Attempt to start TLS twice");
jbe@246 2084 if (handle->readbufin || handle->writebufin) {
jbe@246 2085 return luaL_error(L, "Attempt to start TLS on an I/O handle with non-empty buffers");
jbe@246 2086 }
jbe@252 2087 if (tlsconf->server) tls = tls_server();
jbe@252 2088 else {
jbe@246 2089 servername = luaL_checkstring(L, 3);
jbe@246 2090 tls = tls_client();
jbe@246 2091 }
jbe@246 2092 if (!tls) {
jbe@246 2093 return luaL_error(L, "Could not allocate memory for TLS context");
jbe@246 2094 }
jbe@252 2095 if (tls_configure(tls, tlsconf->config)) goto moonbr_io_starttls_error;
jbe@252 2096 if (tlsconf->server) {
jbe@246 2097 if (tls_accept_socket(tls, &tls2, handle->fd)) goto moonbr_io_starttls_error;
jbe@246 2098 handle->servertls = tls;
jbe@246 2099 handle->tls = tls2;
jbe@246 2100 } else {
jbe@246 2101 if (tls_connect_socket(tls, handle->fd, servername)) goto moonbr_io_starttls_error;
jbe@246 2102 handle->tls = tls;
jbe@246 2103 }
jbe@246 2104 lua_settop(L, 1);
jbe@246 2105 return 1;
jbe@246 2106 moonbr_io_starttls_error:
jbe@246 2107 lua_pushnil(L);
jbe@246 2108 lua_pushstring(L, tls_error(tls));
jbe@246 2109 tls_free(tls);
jbe@246 2110 return 2;
jbe@246 2111 }
jbe@246 2112
jbe@258 2113 #endif /* MOONBR_IO_USE_TLS */
jbe@243 2114
jbe@79 2115 static const struct luaL_Reg moonbr_io_handle_methods[] = {
jbe@319 2116 {"get_rcvbuf", moonbr_io_get_rcvbuf},
jbe@319 2117 {"get_sndbuf", moonbr_io_get_sndbuf},
jbe@319 2118 {"set_rcvbuf", moonbr_io_set_rcvbuf},
jbe@319 2119 {"set_sndbuf", moonbr_io_set_sndbuf},
jbe@85 2120 {"read", moonbr_io_read},
jbe@85 2121 {"read_nb", moonbr_io_read_nb},
jbe@140 2122 {"read_call", moonbr_io_read_call},
jbe@140 2123 {"read_yield", moonbr_io_read_yield},
jbe@86 2124 {"drain", moonbr_io_drain},
jbe@86 2125 {"drain_nb", moonbr_io_drain_nb},
jbe@144 2126 {"drain_call", moonbr_io_drain_call},
jbe@144 2127 {"drain_yield", moonbr_io_drain_yield},
jbe@80 2128 {"write", moonbr_io_write},
jbe@81 2129 {"write_nb", moonbr_io_write_nb},
jbe@145 2130 {"write_call", moonbr_io_write_call},
jbe@145 2131 {"write_yield", moonbr_io_write_yield},
jbe@80 2132 {"flush", moonbr_io_flush},
jbe@81 2133 {"flush_nb", moonbr_io_flush_nb},
jbe@145 2134 {"flush_call", moonbr_io_flush_call},
jbe@145 2135 {"flush_yield", moonbr_io_flush_yield},
jbe@88 2136 {"finish", moonbr_io_finish},
jbe@87 2137 {"close", moonbr_io_close},
jbe@85 2138 {"reset", moonbr_io_reset},
jbe@246 2139 #ifdef MOONBR_IO_USE_TLS
jbe@246 2140 {"starttls", moonbr_io_starttls},
jbe@246 2141 #endif
jbe@79 2142 {NULL, NULL}
jbe@79 2143 };
jbe@79 2144
jbe@79 2145 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
jbe@79 2146 {"__index", moonbr_io_handleindex},
jbe@79 2147 {"__newindex", moonbr_io_handlenewindex},
jbe@108 2148 {"__gc", moonbr_io_handlegc},
jbe@108 2149 {NULL, NULL}
jbe@108 2150 };
jbe@108 2151
jbe@108 2152 static const struct luaL_Reg moonbr_io_listener_methods[] = {
jbe@108 2153 {"accept", moonbr_io_accept},
jbe@108 2154 {"accept_nb", moonbr_io_accept_nb},
jbe@108 2155 {"close", moonbr_io_unlisten},
jbe@108 2156 {NULL, NULL}
jbe@108 2157 };
jbe@108 2158
jbe@108 2159 static const struct luaL_Reg moonbr_io_listener_metamethods[] = {
jbe@108 2160 {"__gc", moonbr_io_listenergc},
jbe@79 2161 {NULL, NULL}
jbe@79 2162 };
jbe@79 2163
jbe@205 2164 static const struct luaL_Reg moonbr_io_child_methods[] = {
jbe@205 2165 {"kill", moonbr_io_kill},
jbe@205 2166 {"wait", moonbr_io_wait},
jbe@205 2167 {"wait_nb", moonbr_io_wait_nb},
jbe@205 2168 {"wait_call", moonbr_io_wait_call},
jbe@205 2169 {"wait_yield", moonbr_io_wait_yield},
jbe@205 2170 {NULL, NULL}
jbe@205 2171 };
jbe@205 2172
jbe@205 2173 static const struct luaL_Reg moonbr_io_child_metamethods[] = {
jbe@205 2174 {"__index", moonbr_io_childindex},
jbe@205 2175 {"__newindex", moonbr_io_childnewindex},
jbe@205 2176 {"__gc", moonbr_io_childgc},
jbe@205 2177 {NULL, NULL}
jbe@205 2178 };
jbe@205 2179
jbe@79 2180 static const struct luaL_Reg moonbr_io_module_funcs[] = {
jbe@111 2181 {"localconnect", moonbr_io_localconnect},
jbe@111 2182 {"localconnect_nb", moonbr_io_localconnect_nb},
jbe@98 2183 {"tcpconnect", moonbr_io_tcpconnect},
jbe@99 2184 {"tcpconnect_nb", moonbr_io_tcpconnect_nb},
jbe@112 2185 {"locallisten", moonbr_io_locallisten},
jbe@108 2186 {"tcplisten", moonbr_io_tcplisten},
jbe@205 2187 {"exec", moonbr_io_exec},
jbe@288 2188 {"catch_sigterm", moonbr_io_catch_sigterm},
jbe@266 2189 {"getpid", moonbr_io_getpid},
jbe@106 2190 {"poll", moonbr_io_poll},
jbe@115 2191 {"timeref", moonbr_io_timeref},
jbe@243 2192 #ifdef MOONBR_IO_USE_TLS
jbe@243 2193 {"tlsconf", moonbr_io_tlsconf},
jbe@243 2194 #endif
jbe@79 2195 {NULL, NULL}
jbe@79 2196 };
jbe@79 2197
jbe@243 2198 #ifdef MOONBR_IO_USE_TLS
jbe@258 2199
jbe@243 2200 static const struct luaL_Reg moonbr_io_tlsconf_metamethods[] = {
jbe@243 2201 {"__gc", moonbr_io_tlsconfgc},
jbe@243 2202 {NULL, NULL}
jbe@243 2203 };
jbe@258 2204
jbe@258 2205 #endif /* MOONBR_IO_USE_TLS */
jbe@243 2206
jbe@79 2207 int luaopen_moonbridge_io(lua_State *L) {
jbe@79 2208
jbe@113 2209 signal(SIGPIPE, SIG_IGN); /* generate I/O errors instead of signal 13 */
jbe@113 2210
jbe@80 2211 lua_newtable(L); // module
jbe@313 2212 lua_pushvalue(L, -1);
jbe@313 2213 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_MODULE_REGKEY);
jbe@80 2214
jbe@79 2215 lua_newtable(L); // public metatable
jbe@79 2216 lua_newtable(L); // handle methods
jbe@79 2217 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
jbe@80 2218 lua_pushvalue(L, -1);
jbe@146 2219 lua_setfield(L, -4, "handle_pt");
jbe@79 2220 lua_setfield(L, -2, "__index");
jbe@79 2221 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
jbe@79 2222
jbe@79 2223 lua_newtable(L); // handle metatable
jbe@79 2224 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
jbe@146 2225 lua_pushvalue(L, -1);
jbe@146 2226 lua_setfield(L, -3, "handle_mt");
jbe@79 2227 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
jbe@79 2228
jbe@108 2229 lua_newtable(L); // listener metatable
jbe@108 2230 luaL_setfuncs(L, moonbr_io_listener_metamethods, 0);
jbe@108 2231 lua_newtable(L); // listener methods
jbe@108 2232 luaL_setfuncs(L, moonbr_io_listener_methods, 0);
jbe@108 2233 lua_pushvalue(L, -1);
jbe@146 2234 lua_setfield(L, -4, "listener_pt");
jbe@108 2235 lua_setfield(L, -2, "__index");
jbe@146 2236 lua_pushvalue(L, -1);
jbe@146 2237 lua_setfield(L, -3, "listener_mt");
jbe@108 2238 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_LISTENER_MT_REGKEY);
jbe@108 2239
jbe@205 2240 lua_newtable(L); // child methods
jbe@205 2241 luaL_setfuncs(L, moonbr_io_child_methods, 0);
jbe@205 2242 lua_pushvalue(L, -1);
jbe@205 2243 lua_setfield(L, -3, "child_pt");
jbe@205 2244 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_PT_REGKEY);
jbe@205 2245 lua_newtable(L); // child metatable
jbe@205 2246 luaL_setfuncs(L, moonbr_io_child_metamethods, 0);
jbe@205 2247 lua_pushvalue(L, -1);
jbe@205 2248 lua_setfield(L, -3, "child_mt");
jbe@205 2249 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_CHILD_MT_REGKEY);
jbe@205 2250
jbe@243 2251 #ifdef MOONBR_IO_USE_TLS
jbe@243 2252 if(tls_init()) {
jbe@243 2253 return luaL_error(L, "Could not initialize TLS library");
jbe@243 2254 }
jbe@243 2255 lua_newtable(L); // tlsconf metatable
jbe@243 2256 luaL_setfuncs(L, moonbr_io_tlsconf_metamethods, 0);
jbe@243 2257 lua_pushvalue(L, -1);
jbe@243 2258 lua_setfield(L, -3, "tlsconf_mt");
jbe@243 2259 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_TLSCONF_MT_REGKEY);
jbe@243 2260 #endif
jbe@243 2261
jbe@205 2262 moonbr_io_pushhandle(L, 0);
jbe@205 2263 lua_setfield(L, -2, "stdin");
jbe@205 2264 moonbr_io_pushhandle(L, 1);
jbe@205 2265 lua_setfield(L, -2, "stdout");
jbe@205 2266 moonbr_io_pushhandle(L, 2);
jbe@205 2267 lua_setfield(L, -2, "stderr");
jbe@270 2268
jbe@79 2269 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
jbe@79 2270 return 1;
jbe@79 2271
jbe@79 2272 }
jbe@79 2273

Impressum / About Us