16191277 problem in SERVICE/FTP-SERVER
16761173 proftpd in inetd mode, randomly fails to accept connections
--- a/src/data.c
+++ b/src/data.c
@@ -333,6 +333,7 @@ static int data_pasv_open(char *reason, off_t size) {
static int data_active_open(char *reason, off_t size) {
conn_t *c;
int rev;
+ int retries = 0;
pr_netaddr_t *bind_addr;
if (!reason && session.xfer.filename)
@@ -348,45 +349,55 @@ static int data_active_open(char *reason, off_t size) {
bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr);
}
- session.d = pr_inet_create_conn(session.pool, -1, bind_addr,
- session.c->local_port-1, TRUE);
+ for (;;) {
+ session.d = pr_inet_create_conn(session.pool, -1, bind_addr,
+ session.c->local_port-1, TRUE);
- /* Set the "stalled" timer, if any, to prevent the connection
- * open from taking too long
- */
- if (timeout_stalled) {
- pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
- "TimeoutStalled");
- }
+ /* Set the "stalled" timer, if any, to prevent the connection
+ * open from taking too long
+ */
+ if (timeout_stalled) {
+ pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
+ "TimeoutStalled");
+ }
- rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);
+ rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);
- /* Protocol and socket options should be set before handshaking. */
+ /* Protocol and socket options should be set before handshaking. */
- if (session.xfer.direction == PR_NETIO_IO_RD) {
- pr_inet_set_socket_opts(session.d->pool, session.d,
- (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0);
+ if (session.xfer.direction == PR_NETIO_IO_RD) {
+ pr_inet_set_socket_opts(session.d->pool, session.d,
+ (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0);
- } else {
- pr_inet_set_socket_opts(session.d->pool, session.d,
- 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0));
- }
+ } else {
+ pr_inet_set_socket_opts(session.d->pool, session.d,
+ 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0));
+ }
- /* Make sure that the necessary socket options are set on the socket prior
- * to the call to connect(2).
- */
- pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0,
- IPTOS_THROUGHPUT, 1);
- pr_inet_generate_socket_event("core.data-connect", main_server,
- session.d->local_addr, session.d->listen_fd);
+ /* Make sure that the necessary socket options are set on the socket prior
+ * to the call to connect(2).
+ */
+ pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0,
+ IPTOS_THROUGHPUT, 1);
+ pr_inet_generate_socket_event("core.data-connect", main_server,
+ session.d->local_addr, session.d->listen_fd);
- if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
+ if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
session.data_port) == -1) {
- pr_response_add_err(R_425, _("Unable to build data connection: %s"),
- strerror(session.d->xerrno));
- destroy_pool(session.d->pool);
- session.d = NULL;
- return -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;
+ }
+ pr_response_add_err(R_425, _("Unable to build data connection: %s"),
+ strerror(session.d->xerrno));
+ destroy_pool(session.d->pool);
+ session.d = NULL;
+ return -1;
+ } else
+ break;
}
c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,