summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2008-07-30 21:22:49 +0200
committerMichael Brown2008-07-30 21:22:49 +0200
commit8f4c2b4a4c5c3a3d29a102a758e75b65cadf9946 (patch)
tree12303def603513d7ae85163a93c9988397845918 /src
parent[romprefix] Update PCI ROM structure to PCI 3.0 (diff)
downloadipxe-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.
Diffstat (limited to 'src')
-rw-r--r--src/net/tcp/ftp.c48
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 );
+ }
}
/**