moonbridge
diff moonbridge.c @ 78:0ec070d6f5d9
Reverted experimental work on non-blocking I/O with file handles
author | jbe |
---|---|
date | Sun Apr 05 15:15:06 2015 +0200 (2015-04-05) |
parents | 38e7bd13200d |
children | 22dbb9d09f02 |
line diff
1.1 --- a/moonbridge.c Sun Apr 05 01:17:06 2015 +0200 1.2 +++ b/moonbridge.c Sun Apr 05 15:15:06 2015 +0200 1.3 @@ -936,20 +936,10 @@ 1.4 return lua_gettop(L); 1.5 } 1.6 1.7 -/* Lua method for socket object to read from input stream using xread */ 1.8 -static int moonbr_child_lua_xread_stream(lua_State *L) { 1.9 +/* Lua method for socket object to read from input stream until terminator */ 1.10 +static int moonbr_child_lua_readuntil_stream(lua_State *L) { 1.11 lua_getfield(L, 1, "input"); 1.12 - lua_getfield(L, -1, "xread"); 1.13 - lua_insert(L, 1); 1.14 - lua_replace(L, 2); 1.15 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.16 - return lua_gettop(L); 1.17 -} 1.18 - 1.19 -/* Lua method for socket object to read from input stream using xread_nb */ 1.20 -static int moonbr_child_lua_xread_nb_stream(lua_State *L) { 1.21 - lua_getfield(L, 1, "input"); 1.22 - lua_getfield(L, -1, "xread_nb"); 1.23 + lua_getfield(L, -1, "readuntil"); 1.24 lua_insert(L, 1); 1.25 lua_replace(L, 2); 1.26 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.27 @@ -976,16 +966,6 @@ 1.28 return lua_gettop(L); 1.29 } 1.30 1.31 -/* Lua method for socket object to write to output stream using write_nb */ 1.32 -static int moonbr_child_lua_write_nb_stream(lua_State *L) { 1.33 - lua_getfield(L, 1, "output"); 1.34 - lua_getfield(L, -1, "write_nb"); 1.35 - lua_insert(L, 1); 1.36 - lua_replace(L, 2); 1.37 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.38 - return lua_gettop(L); 1.39 -} 1.40 - 1.41 /* Lua method for socket object to flush the output stream */ 1.42 static int moonbr_child_lua_flush_stream(lua_State *L) { 1.43 lua_getfield(L, 1, "output"); 1.44 @@ -1062,15 +1042,13 @@ 1.45 1.46 /* Methods of (bidirectional) socket object passed to handler */ 1.47 static luaL_Reg moonbr_child_lua_socket_functions[] = { 1.48 - {"read", moonbr_child_lua_read_stream}, 1.49 - {"xread", moonbr_child_lua_xread_stream}, 1.50 - {"xread_nb", moonbr_child_lua_xread_nb_stream}, 1.51 - {"lines", moonbr_child_lua_lines_stream}, 1.52 - {"write", moonbr_child_lua_write_stream}, 1.53 - {"write_nb", moonbr_child_lua_write_nb_stream}, 1.54 - {"flush", moonbr_child_lua_flush_stream}, 1.55 - {"close", moonbr_child_lua_close_both_streams}, 1.56 - {"cancel", moonbr_child_lua_cancel_both_streams}, 1.57 + {"read", moonbr_child_lua_read_stream}, 1.58 + {"readuntil", moonbr_child_lua_readuntil_stream}, 1.59 + {"lines", moonbr_child_lua_lines_stream}, 1.60 + {"write", moonbr_child_lua_write_stream}, 1.61 + {"flush", moonbr_child_lua_flush_stream}, 1.62 + {"close", moonbr_child_lua_close_both_streams}, 1.63 + {"cancel", moonbr_child_lua_cancel_both_streams}, 1.64 {NULL, NULL} 1.65 }; 1.66 1.67 @@ -2258,7 +2236,46 @@ 1.68 return ptr; 1.69 } 1.70 1.71 -/* Helper function to convert a value at the given stack index to a natural number */ 1.72 +/* New method for Lua file objects: read until terminator or length exceeded */ 1.73 +static int moonbr_readuntil(lua_State *L) { 1.74 + luaL_Stream *stream; 1.75 + FILE *file; 1.76 + const char *terminatorstr; 1.77 + size_t terminatorlen; 1.78 + luaL_Buffer buf; 1.79 + lua_Integer maxlen; 1.80 + char terminator; 1.81 + int byte; 1.82 + stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.83 + terminatorstr = luaL_checklstring(L, 2, &terminatorlen); 1.84 + luaL_argcheck(L, terminatorlen == 1, 2, "single byte expected"); 1.85 + maxlen = luaL_optinteger(L, 3, 0); 1.86 + if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.87 + file = stream->f; 1.88 + luaL_buffinit(L, &buf); 1.89 + if (!maxlen) maxlen = -1; 1.90 + terminator = terminatorstr[0]; 1.91 + while (maxlen > 0 ? maxlen-- : maxlen) { 1.92 + byte = fgetc(file); 1.93 + if (byte == EOF) { 1.94 + if (ferror(file)) { 1.95 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.96 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.97 + lua_pushnil(L); 1.98 + lua_pushstring(L, errmsg); 1.99 + return 2; 1.100 + } else { 1.101 + break; 1.102 + } 1.103 + } 1.104 + luaL_addchar(&buf, byte); 1.105 + if (byte == terminator) break; 1.106 + } 1.107 + luaL_pushresult(&buf); 1.108 + if (!lua_rawlen(L, -1)) lua_pushnil(L); 1.109 + return 1; 1.110 +} 1.111 + 1.112 static int moonbr_lua_tonatural(lua_State *L, int idx) { 1.113 int isnum; 1.114 lua_Number n; 1.115 @@ -2267,7 +2284,6 @@ 1.116 else return -1; 1.117 } 1.118 1.119 -/* Helper function to convert a value at the given stack index to a timeval struct */ 1.120 static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) { 1.121 int isnum; 1.122 lua_Number n; 1.123 @@ -2281,275 +2297,6 @@ 1.124 } 1.125 } 1.126 1.127 -/* New function io.poll(...) */ 1.128 -static int moonbr_io_poll(lua_State *L) { 1.129 - int i; 1.130 - luaL_Stream *stream; 1.131 - int fd, isnum; 1.132 - int nfds = 0; 1.133 - fd_set readfds, writefds, exceptfds; 1.134 - struct timeval timeout = {0, }; 1.135 - int status; 1.136 - FD_ZERO(&readfds); 1.137 - FD_ZERO(&writefds); 1.138 - FD_ZERO(&exceptfds); 1.139 - if (!lua_isnoneornil(L, 1)) { 1.140 - luaL_checktype(L, 1, LUA_TTABLE); 1.141 - for (i=1; ; i++) { 1.142 -#if LUA_VERSION_NUM >= 503 1.143 - if (lua_geti(L, 1, i) == LUA_TNIL) break; 1.144 -#else 1.145 - lua_pushinteger(L, i); 1.146 - lua_gettable(L, 1); 1.147 - if (lua_isnil(L, -1)) break; 1.148 -#endif 1.149 - stream = luaL_testudata(L, -1, LUA_FILEHANDLE); 1.150 - if (stream) { 1.151 - /* in case of file handle, check for pending data in buffer */ 1.152 - FILE *file = stream->f; 1.153 - int flags, chr; 1.154 - flockfile(file); 1.155 - fd = fileno_unlocked(file); 1.156 - if (ferror(file) || feof(file)) goto moonbr_io_poll_pending_shortcut1; 1.157 - flags = fcntl(fd, F_GETFL, 0); 1.158 - if (flags == -1) goto moonbr_io_poll_pending_error; 1.159 - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_poll_pending_error; 1.160 - chr = getc_unlocked(file); 1.161 - if (chr == EOF) { 1.162 - if (ferror(file) && errno == EAGAIN) clearerr_unlocked(file); 1.163 - else goto moonbr_io_poll_pending_shortcut2; 1.164 - } else { 1.165 - if (ungetc(chr, file) == EOF) { 1.166 - fcntl(fd, F_SETFL, flags); 1.167 - goto moonbr_io_poll_pending_error; 1.168 - } 1.169 - goto moonbr_io_poll_pending_shortcut2; 1.170 - } 1.171 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error; 1.172 - funlockfile(file); 1.173 - goto moonbr_io_poll_pending_cont; 1.174 - moonbr_io_poll_pending_shortcut2: 1.175 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error; 1.176 - moonbr_io_poll_pending_shortcut1: 1.177 - funlockfile(file); 1.178 - lua_pushboolean(L, 1); 1.179 - return 1; 1.180 - moonbr_io_poll_pending_error: 1.181 - funlockfile(file); 1.182 - { 1.183 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.184 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.185 - return luaL_error(L, "Unexpected error while checking buffer of FILE handle: %s", errmsg); 1.186 - } 1.187 - } 1.188 - fd = lua_tointegerx(L, -1, &isnum); 1.189 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.190 - moonbr_io_poll_pending_cont: 1.191 - FD_SET(fd, &readfds); 1.192 - if (fd+1 > nfds) nfds = fd+1; 1.193 - lua_pop(L, 1); 1.194 - } 1.195 - } 1.196 - if (!lua_isnoneornil(L, 2)) { 1.197 - luaL_checktype(L, 2, LUA_TTABLE); 1.198 - for (i=1; ; i++) { 1.199 -#if LUA_VERSION_NUM >= 503 1.200 - if (lua_geti(L, 2, i) == LUA_TNIL) break; 1.201 -#else 1.202 - lua_pushinteger(L, i); 1.203 - lua_gettable(L, 2); 1.204 - if (lua_isnil(L, -1)) break; 1.205 -#endif 1.206 - stream = luaL_testudata(L, -1, LUA_FILEHANDLE); 1.207 - if (stream) { 1.208 - fd = fileno(stream->f); 1.209 - } else { 1.210 - fd = lua_tointegerx(L, -1, &isnum); 1.211 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.212 - } 1.213 - FD_SET(fd, &writefds); 1.214 - if (fd+1 > nfds) nfds = fd+1; 1.215 - lua_pop(L, 1); 1.216 - } 1.217 - lua_pop(L, 2); 1.218 - } 1.219 - if (!lua_isnoneornil(L, 3)) { 1.220 - luaL_argcheck(L, moonbr_lua_totimeval(L, 3, &timeout), 3, "not a valid timeout"); 1.221 - } 1.222 - status = select(nfds, &readfds, &writefds, &exceptfds, &timeout); 1.223 - if (status == -1) { 1.224 - if (errno == EINTR) { 1.225 - lua_pushboolean(L, 0); 1.226 - lua_pushliteral(L, "Signal received while polling file descriptors"); 1.227 - return 2; 1.228 - } else { 1.229 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.230 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.231 - return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg); 1.232 - } 1.233 - } else if (status == 0) { 1.234 - lua_pushboolean(L, 0); 1.235 - lua_pushliteral(L, "Timeout while polling file descriptors"); 1.236 - return 2; 1.237 - } else { 1.238 - lua_pushboolean(L, 1); 1.239 - return 1; 1.240 - } 1.241 -} 1.242 - 1.243 -/* New methods for Lua file objects: read until terminator or length exceeded (blocking and non-blocking) */ 1.244 -static int moonbr_io_xread_impl(lua_State *L, int nonblock) { 1.245 - luaL_Stream *stream; 1.246 - lua_Integer maxlen; 1.247 - const char *terminatorstr; 1.248 - size_t terminatorlen; 1.249 - FILE *file; 1.250 - int chr, terminator; 1.251 - luaL_Buffer buf; 1.252 - int wouldblock = 0; 1.253 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.254 - maxlen = luaL_optinteger(L, 2, 0); 1.255 - terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); 1.256 - luaL_argcheck(L, terminatorlen <= 1, 3, "single byte expected"); 1.257 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.258 - file = stream->f; 1.259 - if (ferror(file)) { 1.260 - lua_pushnil(L); 1.261 - lua_pushliteral(L, "Previous error condition on file handle"); 1.262 - return 2; 1.263 - } 1.264 - if (!maxlen) maxlen = -1; 1.265 - terminator = terminatorlen ? terminatorstr[0] : -1; 1.266 - luaL_buffinit(L, &buf); 1.267 - while (maxlen > 0 ? maxlen-- : maxlen) { 1.268 - chr = getc(file); 1.269 - if (chr == EOF) { 1.270 - if (ferror(file)) { 1.271 - if (nonblock && errno == EAGAIN) { 1.272 - clearerr(file); 1.273 - wouldblock = 1; 1.274 - } else { 1.275 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.276 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.277 - lua_pushnil(L); 1.278 - lua_pushstring(L, errmsg); 1.279 - return 2; 1.280 - } 1.281 - } 1.282 - break; 1.283 - } 1.284 - luaL_addchar(&buf, chr); 1.285 - if (chr == terminator) break; 1.286 - } 1.287 - luaL_pushresult(&buf); 1.288 - if (wouldblock || lua_rawlen(L, -1)) { 1.289 - return 1; 1.290 - } else { 1.291 - lua_pushboolean(L, 0); 1.292 - lua_pushliteral(L, "End of file"); 1.293 - return 2; 1.294 - } 1.295 -} 1.296 -static int moonbr_io_xread(lua_State *L) { 1.297 - return moonbr_io_xread_impl(L, 0); 1.298 -} 1.299 -static int moonbr_io_xread_nb_impl(lua_State *L) { 1.300 - return moonbr_io_xread_impl(L, 1); 1.301 -} 1.302 -static int moonbr_io_xread_nb(lua_State *L) { 1.303 - luaL_Stream *stream; 1.304 - int fd, flags; 1.305 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.306 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.307 - lua_pushcfunction(L, moonbr_io_xread_nb_impl); 1.308 - lua_insert(L, 1); 1.309 - lua_settop(L, 4); 1.310 - fd = fileno(stream->f); 1.311 - flags = fcntl(fd, F_GETFL, 0); 1.312 - if (flags == -1) goto moonbr_io_xread_nb_error; 1.313 - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_xread_nb_error; 1.314 - if (lua_pcall(L, 3, LUA_MULTRET, 0)) { 1.315 - fcntl(fd, F_SETFL, flags); 1.316 - return lua_error(L); 1.317 - } 1.318 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_nb_error; 1.319 - return lua_gettop(L); 1.320 - moonbr_io_xread_nb_error: 1.321 - { 1.322 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.323 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.324 - return luaL_error(L, "Unexpected error in xread_nb method: %s", errmsg); 1.325 - } 1.326 -} 1.327 - 1.328 -/* New methods for Lua file objects: non-blocking writing */ 1.329 -static int moonbr_io_write_nb_impl(lua_State *L) { 1.330 - int fd, argc, i; 1.331 - const char *str; 1.332 - size_t strlen; 1.333 - ssize_t written; 1.334 - luaL_Buffer buf; 1.335 - fd = lua_tointeger(L, 1); 1.336 - argc = lua_gettop(L) - 1; 1.337 - for (i=0; i<argc; i++) { 1.338 - str = luaL_checklstring(L, 2+i, &strlen); 1.339 - written = write(fd, str, strlen); 1.340 - if (written < 0) { 1.341 - if (errno != EAGAIN) { 1.342 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.343 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.344 - lua_pushnil(L); 1.345 - lua_pushstring(L, errmsg); 1.346 - return 2; 1.347 - } 1.348 - written = 0; 1.349 - } 1.350 - if (written < strlen) { 1.351 - luaL_buffinit(L, &buf); 1.352 - luaL_addlstring(&buf, str+written, strlen-written); 1.353 - for (i=i+1; i<argc; i++) { 1.354 - luaL_checkstring(L, 2+i); 1.355 - lua_pushvalue(L, 2+i); 1.356 - luaL_addvalue(&buf); 1.357 - } 1.358 - luaL_pushresult(&buf); 1.359 - return 1; 1.360 - } 1.361 - } 1.362 - lua_pushliteral(L, ""); 1.363 - return 1; 1.364 -} 1.365 -static int moonbr_io_write_nb(lua_State *L) { 1.366 - luaL_Stream *stream; 1.367 - FILE *file; 1.368 - int fd, flags; 1.369 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.370 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.371 - file = stream->f; 1.372 - if (fflush(file)) goto moonbr_io_write_nb_error; 1.373 - lua_pushcfunction(L, moonbr_io_write_nb_impl); 1.374 - lua_insert(L, 2); 1.375 - fd = fileno(file); 1.376 - lua_pushinteger(L, fd); 1.377 - lua_insert(L, 3); 1.378 - flags = fcntl(fd, F_GETFL, 0); 1.379 - if (flags == -1) goto moonbr_io_write_nb_error; 1.380 - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_write_nb_error; 1.381 - if (lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0)) { 1.382 - fcntl(fd, F_SETFL, flags); 1.383 - return lua_error(L); 1.384 - } 1.385 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_write_nb_error; 1.386 - return lua_gettop(L) - 1; 1.387 - moonbr_io_write_nb_error: 1.388 - { 1.389 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.390 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.391 - return luaL_error(L, "Unexpected error in write_nb method: %s", errmsg); 1.392 - } 1.393 -} 1.394 - 1.395 -/* New global function timeout(...) */ 1.396 static int moonbr_timeout(lua_State *L) { 1.397 struct itimerval oldval; 1.398 if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) { 1.399 @@ -3017,21 +2764,13 @@ 1.400 #ifdef MOONBR_LUA_CPATH 1.401 moonbr_modify_path(L, "cpath", MOONBR_LUA_CPATH); 1.402 #endif 1.403 - lua_getglobal(L, "io"); 1.404 - lua_pushcfunction(L, moonbr_io_poll); 1.405 - lua_setfield(L, -2, "poll"); 1.406 - lua_pop(L, 1); 1.407 if (luaL_newmetatable(L, LUA_FILEHANDLE)) { 1.408 moonbr_log(LOG_CRIT, "Lua metatable LUA_FILEHANDLE does not exist"); 1.409 moonbr_terminate_error(); 1.410 } 1.411 lua_getfield(L, -1, "__index"); 1.412 - lua_pushcfunction(L, moonbr_io_xread); 1.413 - lua_setfield(L, -2, "xread"); 1.414 - lua_pushcfunction(L, moonbr_io_xread_nb); 1.415 - lua_setfield(L, -2, "xread_nb"); 1.416 - lua_pushcfunction(L, moonbr_io_write_nb); 1.417 - lua_setfield(L, -2, "write_nb"); 1.418 + lua_pushcfunction(L, moonbr_readuntil); 1.419 + lua_setfield(L, -2, "readuntil"); 1.420 lua_pop(L, 2); 1.421 lua_pushcfunction(L, moonbr_timeout); 1.422 lua_setglobal(L, "timeout");