moonbridge

annotate moonbridge_io.c @ 320:5fe68ba5fe0e

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

Impressum / About Us