From 8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 30 Jul 2008 20:22:49 +0100 Subject: [ftp] Cope with RETR completion prior to all data received Based on a patch contributed by Sergey Vlasov : 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. --- src/net/tcp/ftp.c | 48 +++++++++++++++++++++++++++++++++--------------- 1 file 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, }; /** @@ -169,6 +171,27 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { } while ( --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 * @@ -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 ); + } } /** -- cgit v1.2.3-55-g7522