Browse Source

[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.
tags/v0.9.4
Michael Brown 16 years ago
parent
commit
8f4c2b4a4c
1 changed files with 33 additions and 15 deletions
  1. 33
    15
      src/net/tcp/ftp.c

+ 33
- 15
src/net/tcp/ftp.c View File

35
 	FTP_TYPE,
35
 	FTP_TYPE,
36
 	FTP_PASV,
36
 	FTP_PASV,
37
 	FTP_RETR,
37
 	FTP_RETR,
38
+	FTP_WAIT,
38
 	FTP_QUIT,
39
 	FTP_QUIT,
39
 	FTP_DONE,
40
 	FTP_DONE,
40
 };
41
 };
116
  * snprintf() call.
117
  * snprintf() call.
117
  */
118
  */
118
 static const char * ftp_strings[] = {
119
 static const char * ftp_strings[] = {
119
-	[FTP_CONNECT]	= "",
120
+	[FTP_CONNECT]	= NULL,
120
 	[FTP_USER]	= "USER anonymous\r\n",
121
 	[FTP_USER]	= "USER anonymous\r\n",
121
 	[FTP_PASS]	= "PASS etherboot@etherboot.org\r\n",
122
 	[FTP_PASS]	= "PASS etherboot@etherboot.org\r\n",
122
 	[FTP_TYPE]	= "TYPE I\r\n",
123
 	[FTP_TYPE]	= "TYPE I\r\n",
123
 	[FTP_PASV]	= "PASV\r\n",
124
 	[FTP_PASV]	= "PASV\r\n",
124
-	[FTP_RETR]	= "RETR %s\r\n", 
125
+	[FTP_RETR]	= "RETR %s\r\n",
126
+	[FTP_WAIT]	= NULL,
125
 	[FTP_QUIT]	= "QUIT\r\n",
127
 	[FTP_QUIT]	= "QUIT\r\n",
126
-	[FTP_DONE]	= "",
128
+	[FTP_DONE]	= NULL,
127
 };
129
 };
128
 
130
 
129
 /**
131
 /**
169
 	} while ( --len );
171
 	} while ( --len );
170
 }
172
 }
171
 
173
 
174
+/**
175
+ * Move to next state and send the appropriate FTP control string
176
+ *
177
+ * @v ftp		FTP request
178
+ *
179
+ */
180
+static void ftp_next_state ( struct ftp_request *ftp ) {
181
+
182
+	/* Move to next state */
183
+	if ( ftp->state < FTP_DONE )
184
+		ftp->state++;
185
+
186
+	/* Send control string if needed */
187
+	if ( ftp_strings[ftp->state] != NULL ) {
188
+		DBGC ( ftp, "FTP %p sending ", ftp );
189
+		DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
190
+		xfer_printf ( &ftp->control, ftp_strings[ftp->state],
191
+			      ftp->uri->path );
192
+	}	
193
+}
194
+
172
 /**
195
 /**
173
  * Handle an FTP control channel response
196
  * Handle an FTP control channel response
174
  *
197
  *
223
 		}
246
 		}
224
 	}
247
 	}
225
 
248
 
226
-	/* Move to next state */
227
-	if ( ftp->state < FTP_DONE )
228
-		ftp->state++;
229
-
230
-	/* Send control string */
231
-	if ( ftp->state < FTP_DONE ) {
232
-		DBGC ( ftp, "FTP %p sending ", ftp );
233
-		DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
234
-		xfer_printf ( &ftp->control, ftp_strings[ftp->state],
235
-			      ftp->uri->path );
236
-	}
249
+	/* Move to next state and send control string */
250
+	ftp_next_state ( ftp );
251
+	
237
 }
252
 }
238
 
253
 
239
 /**
254
 /**
331
 	       ftp, strerror ( rc ) );
346
 	       ftp, strerror ( rc ) );
332
 	
347
 	
333
 	/* If there was an error, close control channel and record status */
348
 	/* If there was an error, close control channel and record status */
334
-	if ( rc )
349
+	if ( rc ) {
335
 		ftp_done ( ftp, rc );
350
 		ftp_done ( ftp, rc );
351
+	} else {
352
+		ftp_next_state ( ftp );
353
+	}
336
 }
354
 }
337
 
355
 
338
 /**
356
 /**

Loading…
Cancel
Save