moonbridge
changeset 88:fca51922b708
Extended I/O library; Integrated new I/O library into moonbridge.c and moonbridge_http.lua
author | jbe |
---|---|
date | Tue Apr 07 02:15:17 2015 +0200 (2015-04-07) |
parents | 1d91c6eedf18 |
children | c4fd976d9537 |
files | moonbridge.c moonbridge_http.lua moonbridge_io.c moonbridge_io.h |
line diff
1.1 --- a/moonbridge.c Tue Apr 07 01:17:55 2015 +0200 1.2 +++ b/moonbridge.c Tue Apr 07 02:15:17 2015 +0200 1.3 @@ -277,12 +277,6 @@ 1.4 /* Variable set to nonzero value to disallow further calls of 'listen' function */ 1.5 static int moonbr_booted = 0; 1.6 1.7 -/* Global variables to store information on connection socket in child process */ 1.8 -static int moonbr_child_peersocket_type; /* type of socket by MOONBR_SOCKETTYPE constant */ 1.9 -static int moonbr_child_peersocket_fd; /* Original file descriptor of peer socket */ 1.10 -static luaL_Stream *moonbr_child_peersocket_inputstream; /* Lua input stream of socket */ 1.11 -static luaL_Stream *moonbr_child_peersocket_outputstream; /* Lua output stream of socket */ 1.12 - 1.13 /* Verbosity settings */ 1.14 static int moonbr_debug = 0; 1.15 static int moonbr_stat = 0; 1.16 @@ -817,249 +811,10 @@ 1.17 } 1.18 } 1.19 1.20 -/* Closes the input stream from peer unless it has already been closed */ 1.21 -static int moonbr_child_close_peersocket_inputstream( 1.22 - int cleanshut, /* nonzero = use shutdown() if applicable */ 1.23 - int mark /* nonzero = mark the stream as closed for Lua */ 1.24 -) { 1.25 - int err = 0; /* nonzero = error occurred */ 1.26 - int errno2; /* stores previous errno values that take precedence */ 1.27 - if (moonbr_child_peersocket_inputstream->f) { 1.28 - /* NOTE: shutdown() with SHUT_RD shows different behavior on different 1.29 - * operating systems and particularly causes problems with Linux. Hence it 1.30 - * is disabled here. */ 1.31 - /* 1.32 - if (cleanshut && moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) { 1.33 - if (shutdown(moonbr_child_peersocket_fd, SHUT_RD)) { 1.34 - errno2 = errno; 1.35 - err = -1; 1.36 - } 1.37 - } 1.38 - */ 1.39 - if (fclose(moonbr_child_peersocket_inputstream->f)) { 1.40 - if (!err) errno2 = errno; 1.41 - err = -1; 1.42 - } 1.43 - moonbr_child_peersocket_inputstream->f = NULL; 1.44 - } 1.45 - if (mark) moonbr_child_peersocket_inputstream->closef = NULL; 1.46 - if (err) errno = errno2; 1.47 - return err; 1.48 -} 1.49 - 1.50 -/* Closes the output stream to peer unless it has already been closed */ 1.51 -static int moonbr_child_close_peersocket_outputstream( 1.52 - int cleanshut, /* nonzero = use fflush() and shutdown() if applicable */ 1.53 - int mark /* nonzero = mark the stream as closed for Lua */ 1.54 -) { 1.55 - int err = 0; /* nonzero = error occurred */ 1.56 - int errno2; /* stores previous errno values that take precedence */ 1.57 - if (moonbr_child_peersocket_outputstream->f) { 1.58 - if (moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) { 1.59 - if (cleanshut) { 1.60 - if (fflush(moonbr_child_peersocket_outputstream->f)) { 1.61 - errno2 = errno; 1.62 - err = -1; 1.63 - } else { 1.64 - if (shutdown(moonbr_child_peersocket_fd, SHUT_WR)) { 1.65 - errno2 = errno; 1.66 - err = -1; 1.67 - } 1.68 - } 1.69 - } else { 1.70 - fpurge(moonbr_child_peersocket_outputstream->f); 1.71 - } 1.72 - } 1.73 - if (fclose(moonbr_child_peersocket_outputstream->f)) { 1.74 - if (!err) errno2 = errno; 1.75 - err = -1; 1.76 - } 1.77 - moonbr_child_peersocket_outputstream->f = NULL; 1.78 - } 1.79 - if (mark) moonbr_child_peersocket_outputstream->closef = NULL; 1.80 - if (err) errno = errno2; 1.81 - return err; 1.82 -} 1.83 - 1.84 -/* Perform a clean shutdown of input and output stream (may be called multiple times) */ 1.85 -static int moonbr_child_close_peersocket(int timeout) { 1.86 - int errprio = 0; 1.87 - int errno2; 1.88 - if (moonbr_child_peersocket_fd == -1) return 0; 1.89 - if (moonbr_child_close_peersocket_inputstream(1, 1)) { 1.90 - errprio = 1; 1.91 - errno2 = errno; 1.92 - } 1.93 - if (moonbr_child_close_peersocket_outputstream(1, 1)) { 1.94 - errprio = 4; 1.95 - errno2 = errno; 1.96 - } 1.97 - if (moonbr_child_peersocket_type == MOONBR_SOCKETTYPE_NETWORK) { 1.98 - struct linger lingerval = { 0, }; 1.99 - if (timeout && !errprio) { 1.100 - lingerval.l_onoff = 1; 1.101 - lingerval.l_linger = timeout; 1.102 - } 1.103 - if (setsockopt(moonbr_child_peersocket_fd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval))) { 1.104 - if (errprio < 2) { 1.105 - errprio = 2; 1.106 - errno2 = errno; 1.107 - } 1.108 - } 1.109 - } 1.110 - if (close(moonbr_child_peersocket_fd)) { 1.111 - if (errprio < 3) { 1.112 - errprio = 3; 1.113 - errno2 = errno; 1.114 - } 1.115 - } 1.116 - moonbr_child_peersocket_fd = -1; 1.117 - if (errprio) { 1.118 - errno = errno2; 1.119 - return -1; 1.120 - } 1.121 - return 0; 1.122 -} 1.123 - 1.124 -/* Close socket and cause reset of TCP connection (TCP RST aka "Connection reset by peer") if possible */ 1.125 -static int moonbr_child_cancel_peersocket() { 1.126 - int err = 0; 1.127 - if (moonbr_child_close_peersocket_inputstream(0, 1)) err = -1; 1.128 - if (moonbr_child_close_peersocket_outputstream(0, 1)) err = -1; 1.129 - if (close(moonbr_child_peersocket_fd)) err = -1; 1.130 - moonbr_child_peersocket_fd = -1; 1.131 - return err; 1.132 -} 1.133 - 1.134 -/* Lua method for socket object to read from input stream */ 1.135 -static int moonbr_child_lua_read_stream(lua_State *L) { 1.136 - lua_getfield(L, 1, "input"); 1.137 - lua_getfield(L, -1, "read"); 1.138 - lua_insert(L, 1); 1.139 - lua_replace(L, 2); 1.140 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.141 - return lua_gettop(L); 1.142 -} 1.143 - 1.144 -/* Lua method for socket object to read from input stream until terminator */ 1.145 -static int moonbr_child_lua_readuntil_stream(lua_State *L) { 1.146 - lua_getfield(L, 1, "input"); 1.147 - lua_getfield(L, -1, "readuntil"); 1.148 - lua_insert(L, 1); 1.149 - lua_replace(L, 2); 1.150 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.151 - return lua_gettop(L); 1.152 -} 1.153 - 1.154 -/* Lua method for socket object to iterate over input stream */ 1.155 -static int moonbr_child_lua_lines_stream(lua_State *L) { 1.156 - lua_getfield(L, 1, "input"); 1.157 - lua_getfield(L, -1, "lines"); 1.158 - lua_insert(L, 1); 1.159 - lua_replace(L, 2); 1.160 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.161 - return lua_gettop(L); 1.162 -} 1.163 - 1.164 -/* Lua method for socket object to write to output stream */ 1.165 -static int moonbr_child_lua_write_stream(lua_State *L) { 1.166 - lua_getfield(L, 1, "output"); 1.167 - lua_getfield(L, -1, "write"); 1.168 - lua_insert(L, 1); 1.169 - lua_replace(L, 2); 1.170 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.171 - return lua_gettop(L); 1.172 -} 1.173 - 1.174 -/* Lua method for socket object to flush the output stream */ 1.175 -static int moonbr_child_lua_flush_stream(lua_State *L) { 1.176 - lua_getfield(L, 1, "output"); 1.177 - lua_getfield(L, -1, "flush"); 1.178 - lua_insert(L, 1); 1.179 - lua_replace(L, 2); 1.180 - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.181 - return lua_gettop(L); 1.182 -} 1.183 - 1.184 -/* Lua function to close a single stream (input or output) from/to peer */ 1.185 -static int moonbr_child_lua_close_stream(lua_State *L) { 1.186 - luaL_Stream *stream = lua_touserdata(L, 1); 1.187 - if (stream == moonbr_child_peersocket_inputstream) { 1.188 - if (moonbr_child_close_peersocket_inputstream(1, 0)) { /* don't mark as closed as it's done by Lua */ 1.189 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.190 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.191 - lua_pushnil(L); 1.192 - lua_pushfstring(L, "Could not close input stream from peer: %s", errmsg); 1.193 - return 2; 1.194 - } 1.195 - } else if (stream == moonbr_child_peersocket_outputstream) { 1.196 - if (moonbr_child_close_peersocket_outputstream(1, 0)) { /* don't mark as closed as it's done by Lua */ 1.197 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.198 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.199 - lua_pushnil(L); 1.200 - lua_pushfstring(L, "Could not close output stream to peer: %s", errmsg); 1.201 - return 2; 1.202 - } 1.203 - } else { 1.204 - luaL_argerror(L, 1, "Not a connection socket"); 1.205 - } 1.206 - lua_pushboolean(L, 1); 1.207 - return 1; 1.208 -} 1.209 - 1.210 -/* Lua function to close both input and output stream from/to peer */ 1.211 -static int moonbr_child_lua_close_both_streams(lua_State *L) { 1.212 - int timeout = 0; 1.213 - if (!lua_isnoneornil(L, 2)) { 1.214 - lua_Integer n = luaL_checkinteger(L, 2); 1.215 - luaL_argcheck(L, n >= 0 && n <= INT_MAX, 2, "out of range"); 1.216 - timeout = n; 1.217 - } 1.218 - if (moonbr_child_peersocket_fd == -1) { 1.219 - luaL_error(L, "Connection with peer has already been explicitly closed"); 1.220 - } 1.221 - if (moonbr_child_close_peersocket(timeout)) { 1.222 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.223 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.224 - lua_pushnil(L); 1.225 - lua_pushfstring(L, "Could not close socket connection with peer: %s", errmsg); 1.226 - return 2; 1.227 - } 1.228 - lua_pushboolean(L, 1); 1.229 - return 1; 1.230 -} 1.231 - 1.232 -/* Lua function to close both input and output stream from/to peer */ 1.233 -static int moonbr_child_lua_cancel_both_streams(lua_State *L) { 1.234 - if (moonbr_child_peersocket_fd == -1) { 1.235 - luaL_error(L, "Connection with peer has already been explicitly closed"); 1.236 - } 1.237 - if (moonbr_child_cancel_peersocket()) { 1.238 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.239 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.240 - lua_pushnil(L); 1.241 - lua_pushfstring(L, "Could not cancel socket connection with peer: %s", errmsg); 1.242 - return 2; 1.243 - } 1.244 - lua_pushboolean(L, 1); 1.245 - return 1; 1.246 -} 1.247 - 1.248 -/* Methods of (bidirectional) socket object passed to handler */ 1.249 -static luaL_Reg moonbr_child_lua_socket_functions[] = { 1.250 - {"read", moonbr_child_lua_read_stream}, 1.251 - {"readuntil", moonbr_child_lua_readuntil_stream}, 1.252 - {"lines", moonbr_child_lua_lines_stream}, 1.253 - {"write", moonbr_child_lua_write_stream}, 1.254 - {"flush", moonbr_child_lua_flush_stream}, 1.255 - {"close", moonbr_child_lua_close_both_streams}, 1.256 - {"cancel", moonbr_child_lua_cancel_both_streams}, 1.257 - {NULL, NULL} 1.258 -}; 1.259 - 1.260 /* Main function of child process to be called after fork() and file descriptor rearrangement */ 1.261 void moonbr_child_run(struct moonbr_pool *pool, lua_State *L) { 1.262 char controlmsg; 1.263 + int fd; 1.264 struct itimerval notimer = { { 0, }, { 0, } }; 1.265 lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); 1.266 if (lua_isnil(L, -1)) lua_pop(L, 1); 1.267 @@ -1076,66 +831,20 @@ 1.268 if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) { 1.269 moonbr_child_log_errno_fatal("Error while sending ready message to parent process"); 1.270 } 1.271 - moonbr_child_receive_control_message( 1.272 - MOONBR_FD_CONTROL, 1.273 - &controlmsg, 1.274 - &moonbr_child_peersocket_fd 1.275 - ); 1.276 + moonbr_child_receive_control_message(MOONBR_FD_CONTROL, &controlmsg, &fd); 1.277 if (!( 1.278 - (controlmsg == MOONBR_COMMAND_TERMINATE && moonbr_child_peersocket_fd == -1) || 1.279 - (controlmsg == MOONBR_SOCKETTYPE_INTERVAL && moonbr_child_peersocket_fd == -1) || 1.280 - (controlmsg == MOONBR_SOCKETTYPE_LOCAL && moonbr_child_peersocket_fd != -1) || 1.281 - (controlmsg == MOONBR_SOCKETTYPE_NETWORK && moonbr_child_peersocket_fd != -1) 1.282 + (controlmsg == MOONBR_COMMAND_TERMINATE && fd == -1) || 1.283 + (controlmsg == MOONBR_SOCKETTYPE_INTERVAL && fd == -1) || 1.284 + (controlmsg == MOONBR_SOCKETTYPE_LOCAL && fd != -1) || 1.285 + (controlmsg == MOONBR_SOCKETTYPE_NETWORK && fd != -1) 1.286 )) { 1.287 moonbr_child_log_fatal("Received illegal control message from parent process"); 1.288 } 1.289 if (controlmsg == MOONBR_COMMAND_TERMINATE) break; 1.290 listener = moonbr_child_receive_pointer(MOONBR_FD_CONTROL); 1.291 - moonbr_child_peersocket_type = controlmsg; 1.292 - if (moonbr_child_peersocket_fd != -1) { 1.293 - { 1.294 - int clonedfd; 1.295 - clonedfd = dup(moonbr_child_peersocket_fd); 1.296 - if (!clonedfd) { 1.297 - moonbr_child_log_errno_fatal("Could not duplicate file descriptor for input stream"); 1.298 - } 1.299 - moonbr_child_peersocket_inputstream = lua_newuserdata(L, sizeof(luaL_Stream)); 1.300 - if (!moonbr_child_peersocket_inputstream) { 1.301 - moonbr_child_log_fatal("Memory allocation error"); 1.302 - } 1.303 - moonbr_child_peersocket_inputstream->f = fdopen(clonedfd, "rb"); 1.304 - if (!moonbr_child_peersocket_inputstream->f) { 1.305 - moonbr_child_log_errno_fatal("Could not open input stream for remote connection"); 1.306 - } 1.307 - moonbr_child_peersocket_inputstream->closef = moonbr_child_lua_close_stream; 1.308 - if (luaL_newmetatable(L, LUA_FILEHANDLE)) { 1.309 - moonbr_child_log_fatal("Lua metatable LUA_FILEHANDLE does not exist"); 1.310 - } 1.311 - lua_setmetatable(L, -2); 1.312 - } 1.313 - { 1.314 - int clonedfd; 1.315 - clonedfd = dup(moonbr_child_peersocket_fd); 1.316 - if (!clonedfd) { 1.317 - moonbr_child_log_errno_fatal("Could not duplicate file descriptor for output stream"); 1.318 - } 1.319 - moonbr_child_peersocket_outputstream = lua_newuserdata(L, sizeof(luaL_Stream)); 1.320 - if (!moonbr_child_peersocket_outputstream) { 1.321 - moonbr_child_log_fatal("Memory allocation error"); 1.322 - } 1.323 - moonbr_child_peersocket_outputstream->f = fdopen(clonedfd, "wb"); 1.324 - if (!moonbr_child_peersocket_outputstream->f) { 1.325 - moonbr_child_log_errno_fatal("Could not open output stream for remote connection"); 1.326 - } 1.327 - moonbr_child_peersocket_outputstream->closef = moonbr_child_lua_close_stream; 1.328 - if (luaL_newmetatable(L, LUA_FILEHANDLE)) { 1.329 - moonbr_child_log_fatal("Lua metatable LUA_FILEHANDLE does not exist"); 1.330 - } 1.331 - lua_setmetatable(L, -2); 1.332 - } 1.333 - } 1.334 + if (fd) moonbr_io_pushhandle(L, fd, 1, controlmsg == MOONBR_SOCKETTYPE_NETWORK); 1.335 lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); 1.336 - if (listener->proto == MOONBR_PROTO_INTERVAL) { 1.337 + if (!fd) { 1.338 lua_newtable(L); 1.339 lua_pushstring(L, 1.340 listener->proto_specific.interval.name ? 1.341 @@ -1143,16 +852,11 @@ 1.342 ); 1.343 lua_setfield(L, -2, "interval"); 1.344 } else { 1.345 - lua_newtable(L); 1.346 - lua_pushvalue(L, -4); 1.347 - lua_setfield(L, -2, "input"); 1.348 - lua_pushvalue(L, -3); 1.349 - lua_setfield(L, -2, "output"); 1.350 - luaL_setfuncs(L, moonbr_child_lua_socket_functions, 0); 1.351 + lua_pushvalue(L, -2); 1.352 if (listener->proto == MOONBR_PROTO_TCP6) { 1.353 struct sockaddr_in6 addr; 1.354 socklen_t addr_len = sizeof(struct sockaddr_in6); 1.355 - if (getsockname(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) { 1.356 + if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) { 1.357 moonbr_child_log_errno("Could not get local IP address/port"); 1.358 } else { 1.359 lua_pushlstring(L, (char *)addr.sin6_addr.s6_addr, 16); 1.360 @@ -1160,7 +864,7 @@ 1.361 lua_pushinteger(L, ntohs(addr.sin6_port)); 1.362 lua_setfield(L, -2, "local_tcpport"); 1.363 } 1.364 - if (getpeername(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) { 1.365 + if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) { 1.366 moonbr_child_log_errno("Could not get remote IP address/port"); 1.367 } else { 1.368 lua_pushlstring(L, (char *)addr.sin6_addr.s6_addr, 16); 1.369 @@ -1171,7 +875,7 @@ 1.370 } else if (listener->proto == MOONBR_PROTO_TCP4) { 1.371 struct sockaddr_in addr; 1.372 socklen_t addr_len = sizeof(struct sockaddr_in); 1.373 - if (getsockname(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) { 1.374 + if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) { 1.375 moonbr_child_log_errno("Could not get local IP address/port"); 1.376 } else { 1.377 lua_pushlstring(L, (char *)&addr.sin_addr.s_addr, 4); 1.378 @@ -1179,7 +883,7 @@ 1.379 lua_pushinteger(L, ntohs(addr.sin_port)); 1.380 lua_setfield(L, -2, "local_tcpport"); 1.381 } 1.382 - if (getpeername(moonbr_child_peersocket_fd, (struct sockaddr *)&addr, &addr_len)) { 1.383 + if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) { 1.384 moonbr_child_log_errno("Could not get remote IP address/port"); 1.385 } else { 1.386 lua_pushlstring(L, (char *)&addr.sin_addr.s_addr, 4); 1.387 @@ -1193,9 +897,7 @@ 1.388 fprintf(stderr, "Error in \"connect\" function: %s\n", lua_tostring(L, -1)); 1.389 exit(1); 1.390 } 1.391 - if (moonbr_child_close_peersocket(0)) { 1.392 - moonbr_child_log_errno("Could not close socket connection with peer"); 1.393 - } 1.394 + if (fd) moonbr_io_closehandle(L, -2, -1); /* attemt clean close */ 1.395 if (lua_type(L, -1) != LUA_TBOOLEAN || !lua_toboolean(L, -1)) break; 1.396 #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND 1.397 lua_settop(L, 2);
2.1 --- a/moonbridge_http.lua Tue Apr 07 01:17:55 2015 +0200 2.2 +++ b/moonbridge_http.lua Tue Apr 07 02:15:17 2015 +0200 2.3 @@ -238,7 +238,7 @@ 2.4 io.stderr:write(errmsg, "\n") 2.5 if not socket_closed then 2.6 socket_closed = true 2.7 - socket:cancel() 2.8 + socket:reset() 2.9 end 2.10 error("Could not send data to client: " .. errmsg) 2.11 end 2.12 @@ -270,7 +270,7 @@ 2.13 else 2.14 if not socket_closed then 2.15 socket_closed = true 2.16 - socket:cancel() 2.17 + socket:reset() 2.18 end 2.19 end 2.20 if throw_error then 2.21 @@ -309,10 +309,10 @@ 2.22 local function finish_response() 2.23 if connection_close_responded then 2.24 -- close output stream: 2.25 - assert_output(socket.output:close()) 2.26 + assert_output(socket:finish()) 2.27 -- wait for EOF of peer to avoid immediate TCP RST condition: 2.28 timeout(2, function() 2.29 - while socket.input:read(input_chunk_size) do end 2.30 + socket:drain() 2.31 end) 2.32 -- fully close socket: 2.33 socket_closed = true -- avoid double close on error 2.34 @@ -832,7 +832,7 @@ 2.35 end 2.36 if request.headers_flags["Transfer-Encoding"]["chunked"] then 2.37 while true do 2.38 - local line = socket:readuntil("\n", 32 + remaining_body_size_limit) 2.39 + local line = socket:read(32 + remaining_body_size_limit, "\n") 2.40 if not line then 2.41 request_error(true, "400 Bad Request", "Unexpected EOF while reading next chunk of request body") 2.42 end 2.43 @@ -853,13 +853,13 @@ 2.44 end 2.45 if len == 0 then break end 2.46 read_body_bytes(len, callback) 2.47 - local term = socket:readuntil("\n", 2) 2.48 + local term = socket:read(2, "\n") 2.49 if term ~= "\r\n" and term ~= "\n" then 2.50 request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body") 2.51 end 2.52 end 2.53 while true do 2.54 - local line = socket:readuntil("\n", 2 + remaining_body_size_limit) 2.55 + local line = socket:read(2 + remaining_body_size_limit, "\n") 2.56 if line == "\r\n" or line == "\n" then break end 2.57 remaining_body_size_limit = remaining_body_size_limit - #line 2.58 if remaining_body_size_limit < 0 then 2.59 @@ -894,7 +894,7 @@ 2.60 end 2.61 }) 2.62 -- read and parse request line: 2.63 - local line = socket:readuntil("\n", remaining_header_size_limit) 2.64 + local line = socket:read(remaining_header_size_limit, "\n") 2.65 if not line then return survive end 2.66 remaining_header_size_limit = remaining_header_size_limit - #line 2.67 if remaining_header_size_limit == 0 then 2.68 @@ -910,7 +910,7 @@ 2.69 end 2.70 -- read and parse headers: 2.71 while true do 2.72 - local line = socket:readuntil("\n", remaining_header_size_limit); 2.73 + local line = socket:read(remaining_header_size_limit, "\n"); 2.74 remaining_header_size_limit = remaining_header_size_limit - #line 2.75 if not line then 2.76 return request_error(false, "400 Bad Request")
3.1 --- a/moonbridge_io.c Tue Apr 07 01:17:55 2015 +0200 3.2 +++ b/moonbridge_io.c Tue Apr 07 02:15:17 2015 +0200 3.3 @@ -26,6 +26,8 @@ 3.4 typedef struct { 3.5 int fd; 3.6 int issocket; 3.7 + int canshutdown; 3.8 + int shutwr; 3.9 int nonblocking; 3.10 int readerr; 3.11 int readbufcnt; 3.12 @@ -167,6 +169,7 @@ 3.13 ssize_t result; 3.14 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 3.15 if (handle->fd < 0) luaL_error(L, "Attempt to write to a closed I/O handle"); 3.16 + if (handle->shutwr) luaL_error(L, "Attempt to write to a finished I/O handle"); 3.17 if (handle->writeerr) { 3.18 lua_pushnil(L); 3.19 lua_pushliteral(L, "Previous write error"); 3.20 @@ -277,6 +280,30 @@ 3.21 return moonbr_io_write_impl(L, 1, 1); 3.22 } 3.23 3.24 +static int moonbr_io_finish(lua_State *L) { 3.25 + moonbr_io_handle_t *handle; 3.26 + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 3.27 + if (handle->fd < 0) luaL_error(L, "Attempt to finish a closed I/O handle"); 3.28 + if (handle->shutwr) luaL_error(L, "Attempt to finish a finished I/O handle"); 3.29 + handle->shutwr = 1; 3.30 + if (handle->canshutdown) { 3.31 + if (handle->writeleft) { 3.32 + lua_pushcfunction(L, moonbr_io_flush); 3.33 + lua_pushvalue(L, 1); 3.34 + lua_call(L, 1, 2); 3.35 + if (!lua_toboolean(L, -2)) return 2; 3.36 + } 3.37 + if (shutdown(handle->fd, SHUT_WR)) { 3.38 + moonbr_io_errmsg(); 3.39 + lua_pushnil(L); 3.40 + lua_pushstring(L, errmsg); 3.41 + return 2; 3.42 + } 3.43 + } 3.44 + lua_pushboolean(L, 1); 3.45 + return 1; 3.46 +} 3.47 + 3.48 static int moonbr_io_close(lua_State *L) { 3.49 moonbr_io_handle_t *handle; 3.50 int timeout; 3.51 @@ -319,11 +346,36 @@ 3.52 return lua_gettop(L); 3.53 } 3.54 3.55 -void moonbr_io_pushhandle(lua_State *L, int fd, int issocket) { 3.56 +static int moonbr_io_gc(lua_State *L) { 3.57 + moonbr_io_handle_t *handle; 3.58 + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 3.59 + if (handle->fd >= 0) { 3.60 + lua_pushcfunction(L, moonbr_io_close); 3.61 + lua_pushvalue(L, 1); 3.62 + lua_pushinteger(L, 0); 3.63 + lua_call(L, 2, 0); 3.64 + } 3.65 + return 0; 3.66 +} 3.67 + 3.68 +void moonbr_io_closehandle(lua_State *L, int idx, int timeout) { 3.69 + moonbr_io_handle_t *handle; 3.70 + handle = luaL_checkudata(L, idx, MOONBR_IO_HANDLE_MT_REGKEY); 3.71 + if (handle->fd >= 0) { 3.72 + lua_pushcfunction(L, moonbr_io_close); 3.73 + lua_pushvalue(L, idx); 3.74 + lua_pushinteger(L, timeout); 3.75 + lua_call(L, 2, 0); 3.76 + } 3.77 +} 3.78 + 3.79 +void moonbr_io_pushhandle(lua_State *L, int fd, int issocket, int canshutdown) { 3.80 moonbr_io_handle_t *handle; 3.81 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); 3.82 handle->fd = fd; 3.83 handle->issocket = issocket; 3.84 + handle->canshutdown = canshutdown; 3.85 + handle->shutwr = 0; 3.86 handle->nonblocking = -1; 3.87 handle->readerr = 0; 3.88 handle->readbufcnt = 0; 3.89 @@ -374,6 +426,7 @@ 3.90 {"write_nb", moonbr_io_write_nb}, 3.91 {"flush", moonbr_io_flush}, 3.92 {"flush_nb", moonbr_io_flush_nb}, 3.93 + {"finish", moonbr_io_finish}, 3.94 {"close", moonbr_io_close}, 3.95 {"reset", moonbr_io_reset}, 3.96 {NULL, NULL} 3.97 @@ -382,7 +435,7 @@ 3.98 static const struct luaL_Reg moonbr_io_handle_metamethods[] = { 3.99 {"__index", moonbr_io_handleindex}, 3.100 {"__newindex", moonbr_io_handlenewindex}, 3.101 - {"__gc", moonbr_io_reset}, 3.102 + {"__gc", moonbr_io_gc}, 3.103 {NULL, NULL} 3.104 }; 3.105
4.1 --- a/moonbridge_io.h Tue Apr 07 01:17:55 2015 +0200 4.2 +++ b/moonbridge_io.h Tue Apr 07 02:15:17 2015 +0200 4.3 @@ -1,4 +1,5 @@ 4.4 4.5 -void moonbr_io_pushhandle(lua_State *L, int fd, int issocket); 4.6 +void moonbr_io_pushhandle(lua_State *L, int fd, int issocket, int canshutdown); 4.7 +void moonbr_io_closehandle(lua_State *L, int idx, int timeout); 4.8 int luaopen_moonbridge_io(lua_State *L); 4.9