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