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