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