moonbridge
diff moonbridge_io.c @ 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 | e4e1ad8d5ab8 |
children | 334ea1f13b0b |
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