Set SO_REUSEADDR on all sockets, not just listeners

See bug 2850 for rationale: it appears that on some busy exits, the OS
decides that every single port is now unusable because they have been
all used too recently.
This commit is contained in:
Nick Mathewson 2011-05-03 22:22:20 -04:00
parent 4126de6888
commit aba7bb705a
2 changed files with 28 additions and 11 deletions

5
changes/bug2850 Normal file
View File

@ -0,0 +1,5 @@
- Minor features
o Set SO_REUSEADDR on all sockets, not just listeners. This should
help busy exit nodes avoid running out of useable ports just because
all the ports have been used in the near past. Resolves issue 2850.

View File

@ -851,6 +851,25 @@ warn_too_many_conns(void)
} }
} }
/** Tell the TCP stack that it shouldn't wait for a long time after
* <b>sock</b> has closed before reusing its port. */
static void
make_socket_reuseable(int sock)
{
#ifdef MS_WINDOWS
(void) sock;
#else
int one=1;
/* REUSEADDR on normal places means you can rebind to the port
* right after somebody else has let it go. But REUSEADDR on win32
* means you can bind to the port _even when somebody else
* already has it bound_. So, don't do that on Win32. */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
(socklen_t)sizeof(one));
#endif
}
/** Bind a new non-blocking socket listening to the socket described /** Bind a new non-blocking socket listening to the socket described
* by <b>listensockaddr</b>. * by <b>listensockaddr</b>.
* *
@ -873,9 +892,6 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
if (listensockaddr->sa_family == AF_INET) { if (listensockaddr->sa_family == AF_INET) {
int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
#ifndef MS_WINDOWS
int one=1;
#endif
if (is_tcp) if (is_tcp)
start_reading = 1; start_reading = 1;
@ -893,14 +909,7 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
goto err; goto err;
} }
#ifndef MS_WINDOWS make_socket_reuseable(s);
/* REUSEADDR on normal places means you can rebind to the port
* right after somebody else has let it go. But REUSEADDR on win32
* means you can bind to the port _even when somebody else
* already has it bound_. So, don't do that on Win32. */
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
(socklen_t)sizeof(one));
#endif
if (bind(s,listensockaddr,socklen) < 0) { if (bind(s,listensockaddr,socklen) < 0) {
const char *helpfulhint = ""; const char *helpfulhint = "";
@ -1088,6 +1097,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
"Connection accepted on socket %d (child of fd %d).", "Connection accepted on socket %d (child of fd %d).",
news,conn->s); news,conn->s);
make_socket_reuseable(news);
set_socket_nonblocking(news); set_socket_nonblocking(news);
if (options->ConstrainedSockets) if (options->ConstrainedSockets)
@ -1297,6 +1307,8 @@ connection_connect(connection_t *conn, const char *address,
log_debug(LD_NET, "Connecting to %s:%u.", log_debug(LD_NET, "Connecting to %s:%u.",
escaped_safe_str_client(address), port); escaped_safe_str_client(address), port);
make_socket_reuseable(s);
if (connect(s, dest_addr, dest_addr_len) < 0) { if (connect(s, dest_addr, dest_addr_len) < 0) {
int e = tor_socket_errno(s); int e = tor_socket_errno(s);
if (!ERRNO_IS_CONN_EINPROGRESS(e)) { if (!ERRNO_IS_CONN_EINPROGRESS(e)) {