Kaynağa Gözat

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.
Nick Mathewson 13 yıl önce
ebeveyn
işleme
aba7bb705a
2 değiştirilmiş dosya ile 28 ekleme ve 11 silme
  1. 5 0
      changes/bug2850
  2. 23 11
      src/or/connection.c

+ 5 - 0
changes/bug2850

@@ -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.
+

+ 23 - 11
src/or/connection.c

@@ -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
  * by <b>listensockaddr</b>.
  *
@@ -873,9 +892,6 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
 
   if (listensockaddr->sa_family == AF_INET) {
     int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
-#ifndef MS_WINDOWS
-    int one=1;
-#endif
     if (is_tcp)
       start_reading = 1;
 
@@ -893,14 +909,7 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
       goto err;
     }
 
-#ifndef MS_WINDOWS
-    /* 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
+    make_socket_reuseable(s);
 
     if (bind(s,listensockaddr,socklen) < 0) {
       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).",
             news,conn->s);
 
+  make_socket_reuseable(news);
   set_socket_nonblocking(news);
 
   if (options->ConstrainedSockets)
@@ -1297,6 +1307,8 @@ connection_connect(connection_t *conn, const char *address,
   log_debug(LD_NET, "Connecting to %s:%u.",
             escaped_safe_str_client(address), port);
 
+  make_socket_reuseable(s);
+
   if (connect(s, dest_addr, dest_addr_len) < 0) {
     int e = tor_socket_errno(s);
     if (!ERRNO_IS_CONN_EINPROGRESS(e)) {