components/proftpd/patches/004.proftpd-retry.patch
author Channappa BV<channappa.vakkalad@oracle.com>
Wed, 20 Jul 2016 03:28:41 -0700
branchs11u3-sru
changeset 6435 c1b087ff0a7e
parent 6417 3b844274a14e
permissions -rw-r--r--
23759117 Update timezone data to 2016f

Source: In-House
Reason: Solaris leave socket in TIME_WAIT status
Reasonable to upstream?: Not much for Linux.

Note: This patch do not look "pretty" but its code
is re-used from the original patch which colided
with the proftpd-1.3.6 code. During proftpd update
the binaries were tested on huge # of small files
(!passive) it looked good so the original patch was
removed.
Now it has returned as regression from supercluster
testing.
Final fix of this problem on Solaris will need further
discussion with community then it will be probably fixed
by a proftpd update.

--- a//src/data.c	2016-03-10 17:04:32.000000000 -0800
+++ b/src/data.c	2016-06-23 05:41:37.547107933 -0700
@@ -337,6 +337,7 @@
 static int data_active_open(char *reason, off_t size) {
   conn_t *c;
   int bind_port, rev;
+  int retries = 0;
   pr_netaddr_t *bind_addr;
   unsigned char *root_revoke = NULL;
 
@@ -384,6 +385,7 @@
     }
   }
 
+  for(;;) { /* begin of endless loop */
   session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE);
   if (session.d == NULL) {
     int xerrno = errno;
@@ -425,7 +427,7 @@
     pr_inet_set_socket_opts(session.d->pool, session.d,
       (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0,
       main_server->tcp_keepalive);
-    
+
   } else {
     pr_inet_set_socket_opts(session.d->pool, session.d,
       0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0),
@@ -442,6 +444,13 @@
 
   if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
       session.data_port) == -1) {
+    if (session.d->xerrno == EADDRINUSE && retries < 16) {
+      destroy_pool(session.d->pool);
+      pr_signals_handle();
+      /* Wait up to MSL to avoid TIME_WAIT. */
+      sleep(retries++);
+      continue; /* continue in endless loop */
+    }
     pr_log_debug(DEBUG6,
       "Error connecting to %s#%u for active data transfer: %s",
       pr_netaddr_get_ipstr(&session.data_addr), session.data_port,
@@ -453,7 +462,8 @@
     destroy_pool(session.d->pool);
     session.d = NULL;
     return -1;
-  }
+  } else break; /* finish the endless loop */
+  } /* end of endless loop */
 
   c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,
     session.d->listen_fd, -1, -1, TRUE);