components/proftpd/patches/004.proftpd-retry.patch
author Jiri Sasek <Jiri.Sasek@Oracle.COM>
Thu, 23 Jun 2016 06:21:51 -0700
changeset 6413 3d1d422367d4
permissions -rw-r--r--
23536514 ftp randomly could not build data connection

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);