david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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.
This commit is contained in:
Michael Brown 2008-07-30 20:22:49 +01:00
parent fe1f017bde
commit 8f4c2b4a4c
1 changed files with 33 additions and 15 deletions

View File

@ -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 );
}
}
/**