components/proftpd/patches/004.proftpd-retry.patch
changeset 6413 3d1d422367d4
equal deleted inserted replaced
6412:4e700eaededa 6413:3d1d422367d4
       
     1 Source: In-House
       
     2 Reason: Solaris leave socket in TIME_WAIT status
       
     3 Reasonable to upstream?: Not much for Linux.
       
     4 
       
     5 Note: This patch do not look "pretty" but its code
       
     6 is re-used from the original patch which colided
       
     7 with the proftpd-1.3.6 code. During proftpd update
       
     8 the binaries were tested on huge # of small files
       
     9 (!passive) it looked good so the original patch was
       
    10 removed.
       
    11 Now it has returned as regression from supercluster
       
    12 testing.
       
    13 Final fix of this problem on Solaris will need further
       
    14 discussion with community then it will be probably fixed
       
    15 by a proftpd update.
       
    16 
       
    17 --- a//src/data.c	2016-03-10 17:04:32.000000000 -0800
       
    18 +++ b/src/data.c	2016-06-23 05:41:37.547107933 -0700
       
    19 @@ -337,6 +337,7 @@
       
    20  static int data_active_open(char *reason, off_t size) {
       
    21    conn_t *c;
       
    22    int bind_port, rev;
       
    23 +  int retries = 0;
       
    24    pr_netaddr_t *bind_addr;
       
    25    unsigned char *root_revoke = NULL;
       
    26  
       
    27 @@ -384,6 +385,7 @@
       
    28      }
       
    29    }
       
    30  
       
    31 +  for(;;) { /* begin of endless loop */
       
    32    session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE);
       
    33    if (session.d == NULL) {
       
    34      int xerrno = errno;
       
    35 @@ -425,7 +427,7 @@
       
    36      pr_inet_set_socket_opts(session.d->pool, session.d,
       
    37        (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0,
       
    38        main_server->tcp_keepalive);
       
    39 -    
       
    40 +
       
    41    } else {
       
    42      pr_inet_set_socket_opts(session.d->pool, session.d,
       
    43        0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0),
       
    44 @@ -442,6 +444,13 @@
       
    45  
       
    46    if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
       
    47        session.data_port) == -1) {
       
    48 +    if (session.d->xerrno == EADDRINUSE && retries < 16) {
       
    49 +      destroy_pool(session.d->pool);
       
    50 +      pr_signals_handle();
       
    51 +      /* Wait up to MSL to avoid TIME_WAIT. */
       
    52 +      sleep(retries++);
       
    53 +      continue; /* continue in endless loop */
       
    54 +    }
       
    55      pr_log_debug(DEBUG6,
       
    56        "Error connecting to %s#%u for active data transfer: %s",
       
    57        pr_netaddr_get_ipstr(&session.data_addr), session.data_port,
       
    58 @@ -453,7 +462,8 @@
       
    59      destroy_pool(session.d->pool);
       
    60      session.d = NULL;
       
    61      return -1;
       
    62 -  }
       
    63 +  } else break; /* finish the endless loop */
       
    64 +  } /* end of endless loop */
       
    65  
       
    66    c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,
       
    67      session.d->listen_fd, -1, -1, TRUE);