moonbridge
changeset 208:77dc29ce7948
Ensure that socket handles always get closed, even in case of an error while creating the socket handle
author | jbe |
---|---|
date | Mon Jun 22 00:19:19 2015 +0200 (2015-06-22) |
parents | 2dd0eea2f5f8 |
children | 5f529cb9b5c1 |
files | moonbridge_io.c |
line diff
1.1 --- a/moonbridge_io.c Sun Jun 21 23:38:53 2015 +0200 1.2 +++ b/moonbridge_io.c Mon Jun 22 00:19:19 2015 +0200 1.3 @@ -79,9 +79,6 @@ 1.4 1.5 typedef struct { 1.6 pid_t pid; 1.7 - int uninitialized_in; 1.8 - int uninitialized_out; 1.9 - int uninitialized_err; 1.10 } moonbr_io_child_t; 1.11 1.12 static int moonbr_io_yield(lua_State *L) { 1.13 @@ -742,14 +739,16 @@ 1.14 } 1.15 } 1.16 1.17 -void moonbr_io_pushhandle(lua_State *L, int fd) { 1.18 +static int moonbr_io_pushhandle_impl(lua_State *L) { 1.19 + int *fd; 1.20 moonbr_io_handle_t *handle; 1.21 struct sockaddr addr; 1.22 socklen_t addrlen; 1.23 + fd = lua_touserdata(L, 1); 1.24 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); 1.25 - handle->fd = fd; 1.26 + handle->fd = -1; /* avoid closing incomplete handle */ 1.27 addrlen = sizeof(addr); 1.28 - if (getsockname(fd, &addr, &addrlen)) { 1.29 + if (getsockname(*fd, &addr, &addrlen)) { 1.30 if (errno != ENOTSOCK) { 1.31 moonbr_io_errmsg(); 1.32 luaL_error(L, "Unexpected error when examining socket: %s", errmsg); 1.33 @@ -774,7 +773,9 @@ 1.34 handle->writeqoff = 0; 1.35 handle->writebufin = 0; 1.36 handle->writebufout = 0; 1.37 + handle->fd = *fd; /* required for set_linger call */ 1.38 moonbr_io_handle_set_linger(L, handle, 0); 1.39 + handle->fd = -1; /* avoid closing incomplete handle */ 1.40 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); 1.41 lua_setmetatable(L, -2); 1.42 lua_newtable(L); // uservalue 1.43 @@ -786,7 +787,7 @@ 1.44 char addrstrbuf[INET6_ADDRSTRLEN]; 1.45 const char *addrstr; 1.46 addrlen = sizeof(addr_in6); 1.47 - if (getsockname(fd, (struct sockaddr *)&addr_in6, &addrlen)) { 1.48 + if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) { 1.49 moonbr_io_errmsg(); 1.50 luaL_error(L, "Could not determine local IP address/port: %s", errmsg); 1.51 } 1.52 @@ -803,7 +804,7 @@ 1.53 } 1.54 lua_pushinteger(L, ntohs(addr_in6.sin6_port)); 1.55 lua_setfield(L, -2, "local_tcpport"); 1.56 - if (getpeername(fd, (struct sockaddr *)&addr_in6, &addrlen)) { 1.57 + if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) { 1.58 moonbr_io_errmsg(); 1.59 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg); 1.60 } 1.61 @@ -825,7 +826,7 @@ 1.62 char addrstrbuf[INET_ADDRSTRLEN]; 1.63 const char *addrstr; 1.64 addrlen = sizeof(addr_in); 1.65 - if (getsockname(fd, (struct sockaddr *)&addr_in, &addrlen)) { 1.66 + if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) { 1.67 moonbr_io_errmsg(); 1.68 luaL_error(L, "Could not determine local IP address/port: %s", errmsg); 1.69 } 1.70 @@ -842,7 +843,7 @@ 1.71 } 1.72 lua_pushinteger(L, ntohs(addr_in.sin_port)); 1.73 lua_setfield(L, -2, "local_tcpport"); 1.74 - if (getpeername(fd, (struct sockaddr *)&addr_in, &addrlen)) { 1.75 + if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) { 1.76 moonbr_io_errmsg(); 1.77 luaL_error(L, "Could not determine remote IP address/port: %s", errmsg); 1.78 } 1.79 @@ -864,6 +865,18 @@ 1.80 lua_setmetatable(L, -2); 1.81 lua_setfield(L, -2, "public"); 1.82 lua_setuservalue(L, -2); 1.83 + handle->fd = *fd; 1.84 + *fd = -1; /* closing is now handled by garbage collection */ 1.85 + return 1; 1.86 +} 1.87 + 1.88 +void moonbr_io_pushhandle(lua_State *L, int fd) { 1.89 + lua_pushcfunction(L, moonbr_io_pushhandle_impl); 1.90 + lua_pushlightuserdata(L, &fd); 1.91 + if (lua_pcall(L, 1, 1, 0)) { 1.92 + if (fd != -1) close(fd); 1.93 + lua_error(L); 1.94 + } 1.95 } 1.96 1.97 static int moonbr_io_handleindex(lua_State *L) { 1.98 @@ -1242,6 +1255,12 @@ 1.99 argv = lua_newuserdata(L, (argc + 1) * sizeof(char *)); 1.100 for (i=0; i<argc; i++) argv[i] = (char *)luaL_checkstring(L, i+1); 1.101 argv[argc] = NULL; 1.102 + child = lua_newuserdata(L, sizeof(moonbr_io_child_t)); 1.103 + child->pid = 0; 1.104 + lua_newtable(L); 1.105 + lua_setuservalue(L, -2); 1.106 + luaL_getmetatable(L, MOONBR_IO_CHILD_MT_REGKEY); 1.107 + lua_setmetatable(L, -2); 1.108 if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sockin)) { 1.109 moonbr_io_errmsg(); 1.110 lua_pushnil(L); 1.111 @@ -1266,7 +1285,6 @@ 1.112 lua_pushfstring(L, "Could not create socket pair: %s", errmsg); 1.113 return 2; 1.114 } 1.115 - child = lua_newuserdata(L, sizeof(moonbr_io_child_t)); 1.116 child->pid = vfork(); 1.117 if (child->pid == -1) { 1.118 moonbr_io_errmsg(); 1.119 @@ -1281,19 +1299,19 @@ 1.120 return 2; 1.121 } 1.122 if (!child->pid) { 1.123 - if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error; 1.124 - if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error; 1.125 - if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error; 1.126 + if (dup2(sockin[1], 0) == -1) goto moonbr_io_exec_error1; 1.127 + if (dup2(sockout[1], 1) == -1) goto moonbr_io_exec_error1; 1.128 + if (dup2(sockerr[1], 2) == -1) goto moonbr_io_exec_error1; 1.129 closefrom(4); 1.130 - if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error; 1.131 - if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error; 1.132 - if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error; 1.133 + if (fcntl(0, F_SETFD, 0) == -1) goto moonbr_io_exec_error1; 1.134 + if (fcntl(1, F_SETFD, 0) == -1) goto moonbr_io_exec_error1; 1.135 + if (fcntl(2, F_SETFD, 0) == -1) goto moonbr_io_exec_error1; 1.136 if (execvp(argv[0], argv)) { 1.137 errorcond = 2; 1.138 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN); 1.139 _exit(0); 1.140 } 1.141 - moonbr_io_exec_error: 1.142 + moonbr_io_exec_error1: 1.143 errorcond = 1; 1.144 strerror_r(errno, (char *)errmsgbuf, MOONBR_IO_MAXSTRERRORLEN); 1.145 _exit(0); 1.146 @@ -1312,29 +1330,49 @@ 1.147 luaL_error(L, "Error in waitpid call after unsuccessful exec: %s", errmsg); 1.148 } 1.149 } 1.150 + child->pid = 0; 1.151 lua_pushnil(L); 1.152 if (errorcond == 2) lua_pushfstring(L, "Could not execute: %s", errmsgbuf); 1.153 else lua_pushfstring(L, "Error in fork: %s", errmsgbuf); 1.154 return 2; 1.155 } 1.156 - /* close sockets during garbage collection in case a Lua error is raised */ 1.157 - child->uninitialized_in = sockin[0]; 1.158 - child->uninitialized_out = sockout[0]; 1.159 - child->uninitialized_err = sockerr[0]; 1.160 - lua_newtable(L); 1.161 - lua_setuservalue(L, -2); 1.162 - luaL_getmetatable(L, MOONBR_IO_CHILD_MT_REGKEY); 1.163 - lua_setmetatable(L, -2); 1.164 - moonbr_io_pushhandle(L, sockin[0]); 1.165 + lua_pushcfunction(L, moonbr_io_pushhandle_impl); 1.166 + lua_pushlightuserdata(L, &sockin[0]); 1.167 + if (lua_pcall(L, 1, 1, 0)) { 1.168 + if (sockin[0] != -1) close(sockin[0]); 1.169 + close(sockout[0]); 1.170 + close(sockerr[0]); 1.171 + goto moonbr_io_exec_error2; 1.172 + } 1.173 lua_setfield(L, -2, "stdin"); 1.174 - child->uninitialized_in = -1; 1.175 - moonbr_io_pushhandle(L, sockout[0]); 1.176 + lua_pushcfunction(L, moonbr_io_pushhandle_impl); 1.177 + lua_pushlightuserdata(L, &sockout[0]); 1.178 + if (lua_pcall(L, 1, 1, 0)) { 1.179 + if (sockout[0] != -1) close(sockout[0]); 1.180 + close(sockerr[0]); 1.181 + goto moonbr_io_exec_error2; 1.182 + } 1.183 lua_setfield(L, -2, "stdout"); 1.184 - child->uninitialized_out = -1; 1.185 - moonbr_io_pushhandle(L, sockerr[0]); 1.186 + lua_pushcfunction(L, moonbr_io_pushhandle_impl); 1.187 + lua_pushlightuserdata(L, &sockerr[0]); 1.188 + if (lua_pcall(L, 1, 1, 0)) { 1.189 + if (sockerr[0] != -1) close(sockerr[0]); 1.190 + goto moonbr_io_exec_error2; 1.191 + } 1.192 lua_setfield(L, -2, "stderr"); 1.193 - child->uninitialized_err = -1; 1.194 return 1; 1.195 + moonbr_io_exec_error2: 1.196 + { 1.197 + int status; 1.198 + while (waitpid(child->pid, &status, 0) == -1) { 1.199 + if (errno != EINTR) { 1.200 + moonbr_io_errmsg(); 1.201 + luaL_error(L, "Error in waitpid call after error creating socket handles: %s", errmsg); 1.202 + } 1.203 + } 1.204 + } 1.205 + child->pid = 0; 1.206 + return lua_error(L); 1.207 } 1.208 1.209 static int moonbr_io_childindex(lua_State *L) { 1.210 @@ -1378,9 +1416,6 @@ 1.211 } 1.212 } 1.213 } 1.214 - if (child->uninitialized_in != -1) close(child->uninitialized_in); 1.215 - if (child->uninitialized_out != -1) close(child->uninitialized_out); 1.216 - if (child->uninitialized_err != -1) close(child->uninitialized_err); 1.217 return 0; 1.218 } 1.219