moonbridge

changeset 311:930a43a0099a

Bugfix/workaround: Do not call getpeername() when opening TCP connections in non-blocking mode
author jbe
date Sat Jan 27 17:48:15 2018 +0100 (2018-01-27)
parents 426848ae6108
children c9fec96fe392
files moonbridge_io.c
line diff
     1.1 --- a/moonbridge_io.c	Fri Nov 24 01:32:23 2017 +0100
     1.2 +++ b/moonbridge_io.c	Sat Jan 27 17:48:15 2018 +0100
     1.3 @@ -873,10 +873,12 @@
     1.4  
     1.5  static int moonbr_io_pushhandle_impl(lua_State *L) {
     1.6    int *fd;
     1.7 +  int skip_peeraddr;
     1.8    moonbr_io_handle_t *handle;
     1.9    struct sockaddr addr;
    1.10    socklen_t addrlen;
    1.11    fd = lua_touserdata(L, 1);
    1.12 +  skip_peeraddr = lua_toboolean(L, 2);
    1.13    handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
    1.14    handle->fd = -1;  /* avoid closing incomplete handle */
    1.15    addrlen = sizeof(addr);
    1.16 @@ -928,6 +930,8 @@
    1.17      char addrstrbuf[INET6_ADDRSTRLEN];
    1.18      const char *addrstr;
    1.19      addrlen = sizeof(addr_in6);
    1.20 +    /* NOTE: According to documentation, getsockname() may fail if connection
    1.21 +     *       was reset. There seems to be no problem in practice though. */
    1.22      if (getsockname(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
    1.23        moonbr_io_prepare_errmsg();
    1.24        luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
    1.25 @@ -945,28 +949,34 @@
    1.26      }
    1.27      lua_pushinteger(L, ntohs(addr_in6.sin6_port));
    1.28      lua_setfield(L, -2, "local_tcpport");
    1.29 -    if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
    1.30 -      moonbr_io_prepare_errmsg();
    1.31 -      luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
    1.32 -    }
    1.33 -    if (addrlen > sizeof(addr_in6)) {
    1.34 -      luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
    1.35 +    if (!skip_peeraddr) {
    1.36 +      /* NOTE: According to documentation, getpeername() may fail if connection
    1.37 +       *       was reset. There seems to be no problem in practice though. */
    1.38 +      if (getpeername(*fd, (struct sockaddr *)&addr_in6, &addrlen)) {
    1.39 +        moonbr_io_prepare_errmsg();
    1.40 +        luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
    1.41 +      }
    1.42 +      if (addrlen > sizeof(addr_in6)) {
    1.43 +        luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
    1.44 +      }
    1.45 +      addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
    1.46 +      if (!addrstr) {
    1.47 +        moonbr_io_prepare_errmsg();
    1.48 +        luaL_error(L, "Could not format remote IP address: %s", errmsg);
    1.49 +      } else {
    1.50 +        lua_pushstring(L, addrstr);
    1.51 +        lua_setfield(L, -2, "remote_ip6");
    1.52 +      }
    1.53 +      lua_pushinteger(L, ntohs(addr_in6.sin6_port));
    1.54 +      lua_setfield(L, -2, "remote_tcpport");
    1.55      }
    1.56 -    addrstr = inet_ntop(AF_INET6, addr_in6.sin6_addr.s6_addr, addrstrbuf, sizeof(addrstrbuf));
    1.57 -    if (!addrstr) {
    1.58 -      moonbr_io_prepare_errmsg();
    1.59 -      luaL_error(L, "Could not format remote IP address: %s", errmsg);
    1.60 -    } else {
    1.61 -      lua_pushstring(L, addrstr);
    1.62 -      lua_setfield(L, -2, "remote_ip6");
    1.63 -    }
    1.64 -    lua_pushinteger(L, ntohs(addr_in6.sin6_port));
    1.65 -    lua_setfield(L, -2, "remote_tcpport");
    1.66    } else if (handle->addrfam == AF_INET) {
    1.67      struct sockaddr_in addr_in;
    1.68      char addrstrbuf[INET_ADDRSTRLEN];
    1.69      const char *addrstr;
    1.70      addrlen = sizeof(addr_in);
    1.71 +    /* NOTE: According to documentation, getsockname() may fail if connection
    1.72 +     *       was reset. There seems to be no problem in practice though. */
    1.73      if (getsockname(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
    1.74        moonbr_io_prepare_errmsg();
    1.75        luaL_error(L, "Could not determine local IP address/port: %s", errmsg);
    1.76 @@ -984,23 +994,27 @@
    1.77      }
    1.78      lua_pushinteger(L, ntohs(addr_in.sin_port));
    1.79      lua_setfield(L, -2, "local_tcpport");
    1.80 -    if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
    1.81 -      moonbr_io_prepare_errmsg();
    1.82 -      luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
    1.83 -    }
    1.84 -    if (addrlen > sizeof(addr_in)) {
    1.85 -      luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
    1.86 +    if (!skip_peeraddr) {
    1.87 +      /* NOTE: According to documentation, getpeername() may fail if connection
    1.88 +       *       was reset. There seems to be no problem in practice though. */
    1.89 +      if (getpeername(*fd, (struct sockaddr *)&addr_in, &addrlen)) {
    1.90 +        moonbr_io_prepare_errmsg();
    1.91 +        luaL_error(L, "Could not determine remote IP address/port: %s", errmsg);
    1.92 +      }
    1.93 +      if (addrlen > sizeof(addr_in)) {
    1.94 +        luaL_error(L, "Could not determine remote IP address/port: buffer size exceeded");
    1.95 +      }
    1.96 +      addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
    1.97 +      if (!addrstr) {
    1.98 +        moonbr_io_prepare_errmsg();
    1.99 +        luaL_error(L, "Could not format remote IP address: %s", errmsg);
   1.100 +      } else {
   1.101 +        lua_pushstring(L, addrstr);
   1.102 +        lua_setfield(L, -2, "remote_ip4");
   1.103 +      }
   1.104 +      lua_pushinteger(L, ntohs(addr_in.sin_port));
   1.105 +      lua_setfield(L, -2, "remote_tcpport");
   1.106      }
   1.107 -    addrstr = inet_ntop(AF_INET, &addr_in.sin_addr.s_addr, addrstrbuf, sizeof(addrstrbuf));
   1.108 -    if (!addrstr) {
   1.109 -      moonbr_io_prepare_errmsg();
   1.110 -      luaL_error(L, "Could not format remote IP address: %s", errmsg);
   1.111 -    } else {
   1.112 -      lua_pushstring(L, addrstr);
   1.113 -      lua_setfield(L, -2, "remote_ip4");
   1.114 -    }
   1.115 -    lua_pushinteger(L, ntohs(addr_in.sin_port));
   1.116 -    lua_setfield(L, -2, "remote_tcpport");
   1.117    }
   1.118    luaL_setmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
   1.119    lua_setfield(L, -2, "public");
   1.120 @@ -1019,6 +1033,16 @@
   1.121    }
   1.122  }
   1.123  
   1.124 +void moonbr_io_pushhandle_skip_peeraddr(lua_State *L, int fd) {
   1.125 +  lua_pushcfunction(L, moonbr_io_pushhandle_impl);
   1.126 +  lua_pushlightuserdata(L, &fd);
   1.127 +  lua_pushboolean(L, 1);
   1.128 +  if (lua_pcall(L, 2, 1, 0)) {
   1.129 +    if (fd != -1) close(fd);  // TODO: correct to close file descriptor here?
   1.130 +    lua_error(L);
   1.131 +  }
   1.132 +}
   1.133 +
   1.134  static int moonbr_io_handleindex(lua_State *L) {
   1.135    luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
   1.136    luaL_checkany(L, 2);
   1.137 @@ -1129,7 +1153,16 @@
   1.138    } else {
   1.139      freeaddrinfo(res);
   1.140    }
   1.141 -  moonbr_io_pushhandle(L, sock);
   1.142 +  if (nonblocking) {
   1.143 +    moonbr_io_pushhandle_skip_peeraddr(L, sock);
   1.144 +    if (addrinfo->ai_family == AF_INET6) {
   1.145 +      // TODO: fill remote_ip6 and remote_tcpport
   1.146 +    } else if (addrinfo->ai_family == AF_INET) {
   1.147 +      // TODO: fill remote_ip4 and remote_tcpport
   1.148 +    }
   1.149 +  } else {
   1.150 +    moonbr_io_pushhandle(L, sock);
   1.151 +  }
   1.152    return 1;
   1.153  }
   1.154  

Impressum / About Us