moonbridge
diff moonbridge.c @ 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 | 22dbb9d09f02 |
children | c4fd976d9537 |
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);