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