diff options
-rw-r--r-- | libftpconn/xfer.c | 139 |
1 files changed, 72 insertions, 67 deletions
diff --git a/libftpconn/xfer.c b/libftpconn/xfer.c index ae4b3377..762fd6a7 100644 --- a/libftpconn/xfer.c +++ b/libftpconn/xfer.c @@ -31,84 +31,67 @@ static error_t ftp_conn_start_open_actv_data (struct ftp_conn *conn, int *data) { error_t err = 0; - - if (conn->actv_data_conn_queue < 0) + /* DCQ is a socket on which to listen for data connections from the server. */ + int dcq; + struct sockaddr *addr = conn->actv_data_addr; + size_t addr_len = sizeof *addr; + + if (! addr) + /* Generate an address for the data connection (which we must know, + so we can tell the server). */ { - /* DCQ is a socket on which we listen for data connections from the - server. */ - int dcq; - struct sockaddr *addr = conn->actv_data_addr; - size_t addr_len = sizeof *addr; - + addr = conn->actv_data_addr = malloc (sizeof (struct sockaddr_in)); if (! addr) - /* Generate an address for the data connection (which we must know, - so we can tell the server). */ - { - addr = conn->actv_data_addr = malloc (sizeof (struct sockaddr_in)); - if (! addr) - return ENOMEM; - - /* Get the local address chosen by the system. */ - if (conn->control < 0) - err = EBADF; - else if (getsockname (conn->control, addr, &addr_len) < 0) - err = errno; + return ENOMEM; - if (err == EBADF || err == EPIPE) - /* Control connection has closed; reopen it and try again. */ - { - err = ftp_conn_open (conn); - if (!err && getsockname (conn->control, addr, &addr_len) < 0) - err = errno; - } + /* Get the local address chosen by the system. */ + if (conn->control < 0) + err = EBADF; + else if (getsockname (conn->control, addr, &addr_len) < 0) + err = errno; - if (err) - { - free (addr); - conn->actv_data_addr = 0; - return err; - } + if (err == EBADF || err == EPIPE) + /* Control connection has closed; reopen it and try again. */ + { + err = ftp_conn_open (conn); + if (!err && getsockname (conn->control, addr, &addr_len) < 0) + err = errno; } - dcq = socket (AF_INET, SOCK_STREAM, 0); - if (dcq < 0) - return errno; - -#if 0 - if (setsockopt (dcq, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on) < 0) - err = errno; -#endif + if (err) + { + free (addr); + conn->actv_data_addr = 0; + return err; + } + } - /* Let the system choose a port for us. */ - ((struct sockaddr_in *)addr)->sin_port = 0; + dcq = socket (AF_INET, SOCK_STREAM, 0); + if (dcq < 0) + return errno; - /* Use ADDR as the data socket's local address. */ - if (!err && bind (dcq, addr, addr_len) < 0) - err = errno; + /* Let the system choose a port for us. */ + ((struct sockaddr_in *)addr)->sin_port = 0; - /* See what port was chosen by the system. */ - if (!err && getsockname (dcq, addr, &addr_len) < 0) - err = errno; + /* Use ADDR as the data socket's local address. */ + if (!err && bind (dcq, addr, addr_len) < 0) + err = errno; - /* Set the incoming connection queue length. */ - if (!err && listen (dcq, 1) < 0) - err = errno; + /* See what port was chosen by the system. */ + if (!err && getsockname (dcq, addr, &addr_len) < 0) + err = errno; - if (err) - close (dcq); - else - conn->actv_data_conn_queue = dcq; - } + /* Set the incoming connection queue length. */ + if (!err && listen (dcq, 1) < 0) + err = errno; - if (! err) - /* By my reading of rfc959, we shouldn't have to re-send the data - connection address to the server after the first time (the servers - should always use the last-specified address), but bsd-derived ftp - servers don't work unless this is done. Aren't standards wonderful? */ + if (err) + close (dcq); + else err = ftp_conn_send_actv_addr (conn, conn->actv_data_addr); if (! err) - *data = conn->actv_data_conn_queue; + *data = dcq; return err; } @@ -125,6 +108,8 @@ ftp_conn_finish_open_actv_data (struct ftp_conn *conn, int *data) size_t rmt_addr_len = sizeof rmt_addr; int real = accept (*data, &rmt_addr, &rmt_addr_len); + close (*data); + if (real < 0) return errno; @@ -132,6 +117,15 @@ ftp_conn_finish_open_actv_data (struct ftp_conn *conn, int *data) return 0; } + +/* Abort an active data connection open sequence; this function should be + called if ftp_conn_start_open_actv_data succeeds, but an error happens + before ftp_conn_finish_open_actv_data can be called. */ +static void +ftp_conn_abort_open_actv_data (struct ftp_conn *conn, int data) +{ + close (data); +} /* Return a data connection, which may not be in a completely open state; this call should be followed by the command that uses the connection, and @@ -193,6 +187,18 @@ ftp_conn_finish_open_data (struct ftp_conn *conn, int *data) else return ftp_conn_finish_open_actv_data (conn, data); } + +/* Abort a data connection open sequence; this function should be called if + ftp_conn_start_open_data succeeds, but an error happens before + ftp_conn_finish_open_data can be called. */ +static void +ftp_conn_abort_open_data (struct ftp_conn *conn, int data) +{ + if (conn->use_passive) + close (data); + else + return ftp_conn_abort_open_actv_data (conn, data); +} /* Start a transfer command CMD/ARG, returning a file descriptor in DATA. POSS_ERRS is a list of errnos to try matching against any resulting error @@ -214,11 +220,10 @@ ftp_conn_start_transfer (struct ftp_conn *conn, if (!err && !REPLY_IS_PRELIM (reply)) err = unexpected_reply (conn, reply, txt, poss_errs); - if (! err) - err = ftp_conn_finish_open_data (conn, data); - if (err) - close (*data); + ftp_conn_abort_open_data (conn, *data); + else + err = ftp_conn_finish_open_data (conn, data); } return err; |