Explorar el Código

[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 hace 16 años
padre
commit
8f4c2b4a4c
Se han modificado 1 ficheros con 33 adiciones y 15 borrados
  1. 33
    15
      src/net/tcp/ftp.c

+ 33
- 15
src/net/tcp/ftp.c Ver fichero

@@ -35,6 +35,7 @@ enum ftp_state {
35 35
 	FTP_TYPE,
36 36
 	FTP_PASV,
37 37
 	FTP_RETR,
38
+	FTP_WAIT,
38 39
 	FTP_QUIT,
39 40
 	FTP_DONE,
40 41
 };
@@ -116,14 +117,15 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
116 117
  * snprintf() call.
117 118
  */
118 119
 static const char * ftp_strings[] = {
119
-	[FTP_CONNECT]	= "",
120
+	[FTP_CONNECT]	= NULL,
120 121
 	[FTP_USER]	= "USER anonymous\r\n",
121 122
 	[FTP_PASS]	= "PASS etherboot@etherboot.org\r\n",
122 123
 	[FTP_TYPE]	= "TYPE I\r\n",
123 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 127
 	[FTP_QUIT]	= "QUIT\r\n",
126
-	[FTP_DONE]	= "",
128
+	[FTP_DONE]	= NULL,
127 129
 };
128 130
 
129 131
 /**
@@ -169,6 +171,27 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
169 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 196
  * Handle an FTP control channel response
174 197
  *
@@ -223,17 +246,9 @@ static void ftp_reply ( struct ftp_request *ftp ) {
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,8 +346,11 @@ static void ftp_data_closed ( struct xfer_interface *data, int rc ) {
331 346
 	       ftp, strerror ( rc ) );
332 347
 	
333 348
 	/* If there was an error, close control channel and record status */
334
-	if ( rc )
349
+	if ( rc ) {
335 350
 		ftp_done ( ftp, rc );
351
+	} else {
352
+		ftp_next_state ( ftp );
353
+	}
336 354
 }
337 355
 
338 356
 /**

Loading…
Cancelar
Guardar