diff options
author | Michael Brown | 2008-07-30 21:22:49 +0200 |
---|---|---|
committer | Michael Brown | 2008-07-30 21:22:49 +0200 |
commit | 8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946 (patch) | |
tree | 12303def603513d7ae85163a93c9988397845918 | |
parent | [romprefix] Update PCI ROM structure to PCI 3.0 (diff) | |
download | ipxe-8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946.tar.gz ipxe-8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946.tar.xz ipxe-8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946.zip |
[ftp] Cope with RETR completion prior to all data received
Based on a patch contributed by Sergey Vlasov <vsu@altlinux.ru> :
In my testing with "qemu -net user" the 226 response to RETR was
often received earlier than final packets of the data connection;
this caused the received file to become truncated without any error
indication. Fix this by adding an intermediate state FTP_TRANSFER
between FTP_RETR and FTP_QUIT, so that the transfer is considered to
be complete only when both the end of data connection is encountered
and the final reply to the RETR command is received.
-rw-r--r-- | src/net/tcp/ftp.c | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index ffb2fbff..9a12064e 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -35,6 +35,7 @@ enum ftp_state { FTP_TYPE, FTP_PASV, FTP_RETR, + FTP_WAIT, FTP_QUIT, FTP_DONE, }; @@ -116,14 +117,15 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) { * snprintf() call. */ static const char * ftp_strings[] = { - [FTP_CONNECT] = "", + [FTP_CONNECT] = NULL, [FTP_USER] = "USER anonymous\r\n", [FTP_PASS] = "PASS etherboot@etherboot.org\r\n", [FTP_TYPE] = "TYPE I\r\n", [FTP_PASV] = "PASV\r\n", - [FTP_RETR] = "RETR %s\r\n", + [FTP_RETR] = "RETR %s\r\n", + [FTP_WAIT] = NULL, [FTP_QUIT] = "QUIT\r\n", - [FTP_DONE] = "", + [FTP_DONE] = NULL, }; /** @@ -170,6 +172,27 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { } /** + * Move to next state and send the appropriate FTP control string + * + * @v ftp FTP request + * + */ +static void ftp_next_state ( struct ftp_request *ftp ) { + + /* Move to next state */ + if ( ftp->state < FTP_DONE ) + ftp->state++; + + /* Send control string if needed */ + if ( ftp_strings[ftp->state] != NULL ) { + DBGC ( ftp, "FTP %p sending ", ftp ); + DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path ); + xfer_printf ( &ftp->control, ftp_strings[ftp->state], + ftp->uri->path ); + } +} + +/** * Handle an FTP control channel response * * @v ftp FTP request @@ -223,17 +246,9 @@ static void ftp_reply ( struct ftp_request *ftp ) { } } - /* Move to next state */ - if ( ftp->state < FTP_DONE ) - ftp->state++; - - /* Send control string */ - if ( ftp->state < FTP_DONE ) { - DBGC ( ftp, "FTP %p sending ", ftp ); - DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path ); - xfer_printf ( &ftp->control, ftp_strings[ftp->state], - ftp->uri->path ); - } + /* Move to next state and send control string */ + ftp_next_state ( ftp ); + } /** @@ -331,8 +346,11 @@ static void ftp_data_closed ( struct xfer_interface *data, int rc ) { ftp, strerror ( rc ) ); /* If there was an error, close control channel and record status */ - if ( rc ) + if ( rc ) { ftp_done ( ftp, rc ); + } else { + ftp_next_state ( ftp ); + } } /** |