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  

Impressum / About Us