Parcourir la source

Updated FTP to use data-xfer API.

tags/v0.9.3
Michael Brown il y a 17 ans
Parent
révision
0dfd5b84fd
2 fichiers modifiés avec 206 ajouts et 230 suppressions
  1. 0
    56
      src/include/gpxe/ftp.h
  2. 206
    174
      src/net/tcp/ftp.c

+ 0
- 56
src/include/gpxe/ftp.h Voir le fichier

@@ -7,63 +7,7 @@
7 7
  *
8 8
  */
9 9
 
10
-#include <stdint.h>
11
-#include <gpxe/async.h>
12
-#include <gpxe/stream.h>
13
-
14
-struct buffer;
15
-
16 10
 /** FTP default port */
17 11
 #define FTP_PORT 21
18 12
 
19
-/**
20
- * FTP states
21
- *
22
- * These @b must be sequential, i.e. a successful FTP session must
23
- * pass through each of these states in order.
24
- */
25
-enum ftp_state {
26
-	FTP_CONNECT = 0,
27
-	FTP_USER,
28
-	FTP_PASS,
29
-	FTP_TYPE,
30
-	FTP_PASV,
31
-	FTP_RETR,
32
-	FTP_QUIT,
33
-	FTP_DONE,
34
-};
35
-
36
-/**
37
- * An FTP request
38
- *
39
- */
40
-struct ftp_request {
41
-	/** URI being fetched */
42
-	struct uri *uri;
43
-	/** Data buffer to fill */
44
-	struct buffer *buffer;
45
-	/** Asynchronous operation */
46
-	struct async async;
47
-
48
-	/** Current state */
49
-	enum ftp_state state;
50
-	/** Amount of current message already transmitted */
51
-	size_t already_sent;
52
-	/** Buffer to be filled with data received via the control channel */
53
-	char *recvbuf;
54
-	/** Remaining size of recvbuf */
55
-	size_t recvsize;
56
-	/** FTP status code, as text */
57
-	char status_text[4];
58
-	/** Passive-mode parameters, as text */
59
-	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
60
-	/** Stream application for the control channel */
61
-	struct stream_application stream;
62
-	/** Stream application for the data channel */
63
-	struct stream_application stream_data;
64
-};
65
-
66
-extern int ftp_get ( struct uri *uri, struct buffer *buffer,
67
-		     struct async *parent );
68
-
69 13
 #endif /* _GPXE_FTP_H */

+ 206
- 174
src/net/tcp/ftp.c Voir le fichier

@@ -1,15 +1,16 @@
1
-#include <stddef.h>
1
+#include <stdint.h>
2 2
 #include <stdlib.h>
3 3
 #include <stdio.h>
4 4
 #include <string.h>
5 5
 #include <assert.h>
6 6
 #include <errno.h>
7 7
 #include <byteswap.h>
8
-#include <gpxe/async.h>
9
-#include <gpxe/buffer.h>
8
+#include <gpxe/socket.h>
9
+#include <gpxe/tcpip.h>
10
+#include <gpxe/in.h>
11
+#include <gpxe/xfer.h>
12
+#include <gpxe/open.h>
10 13
 #include <gpxe/uri.h>
11
-#include <gpxe/download.h>
12
-#include <gpxe/tcp.h>
13 14
 #include <gpxe/ftp.h>
14 15
 
15 16
 /** @file
@@ -18,13 +19,94 @@
18 19
  *
19 20
  */
20 21
 
22
+/**
23
+ * FTP states
24
+ *
25
+ * These @b must be sequential, i.e. a successful FTP session must
26
+ * pass through each of these states in order.
27
+ */
28
+enum ftp_state {
29
+	FTP_CONNECT = 0,
30
+	FTP_USER,
31
+	FTP_PASS,
32
+	FTP_TYPE,
33
+	FTP_PASV,
34
+	FTP_RETR,
35
+	FTP_QUIT,
36
+	FTP_DONE,
37
+};
38
+
39
+/**
40
+ * An FTP request
41
+ *
42
+ */
43
+struct ftp_request {
44
+	/** Reference counter */
45
+	struct refcnt refcnt;
46
+	/** Data transfer interface */
47
+	struct xfer_interface xfer;
48
+
49
+	/** URI being fetched */
50
+	struct uri *uri;
51
+	/** FTP control channel interface */
52
+	struct xfer_interface control;
53
+	/** FTP data channel interface */
54
+	struct xfer_interface data;
55
+
56
+	/** Current state */
57
+	enum ftp_state state;
58
+	/** Buffer to be filled with data received via the control channel */
59
+	char *recvbuf;
60
+	/** Remaining size of recvbuf */
61
+	size_t recvsize;
62
+	/** FTP status code, as text */
63
+	char status_text[5];
64
+	/** Passive-mode parameters, as text */
65
+	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
66
+};
67
+
68
+/**
69
+ * Free FTP request
70
+ *
71
+ * @v refcnt		Reference counter
72
+ */
73
+static void ftp_free ( struct refcnt *refcnt ) {
74
+	struct ftp_request *ftp =
75
+		container_of ( refcnt, struct ftp_request, refcnt );
76
+
77
+	DBGC ( ftp, "FTP %p freed\n", ftp );
78
+
79
+	uri_put ( ftp->uri );
80
+	free ( ftp );
81
+}
82
+
83
+/**
84
+ * Mark FTP operation as complete
85
+ *
86
+ * @v ftp		FTP request
87
+ * @v rc		Return status code
88
+ */
89
+static void ftp_done ( struct ftp_request *ftp, int rc ) {
90
+
91
+	DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) );
92
+
93
+	/* Close all data transfer interfaces */
94
+	xfer_nullify ( &ftp->xfer );
95
+	xfer_close ( &ftp->xfer, rc );
96
+	xfer_nullify ( &ftp->control );
97
+	xfer_close ( &ftp->control, rc );
98
+	xfer_nullify ( &ftp->data );
99
+	xfer_close ( &ftp->data, rc );
100
+}
101
+
21 102
 /*****************************************************************************
22 103
  *
23 104
  * FTP control channel
24 105
  *
25 106
  */
26 107
 
27
-/** FTP control channel strings
108
+/**
109
+ * FTP control channel strings
28 110
  *
29 111
  * These are used as printf() format strings.  Since only one of them
30 112
  * (RETR) takes an argument, we always supply that argument to the
@@ -42,32 +124,23 @@ static const char * ftp_strings[] = {
42 124
 };
43 125
 
44 126
 /**
45
- * Get FTP request from control stream application
127
+ * Handle control channel being closed
46 128
  *
47
- * @v app		Stream application
48
- * @ret ftp		FTP request
49
- */
50
-static inline struct ftp_request *
51
-stream_to_ftp ( struct stream_application *app ) {
52
-	return container_of ( app, struct ftp_request, stream );
53
-}
54
-
55
-/**
56
- * Mark FTP operation as complete
129
+ * @v control		FTP control channel interface
130
+ * @v rc		Reason for close
57 131
  *
58
- * @v ftp		FTP request
59
- * @v rc		Return status code
132
+ * When the control channel is closed, the data channel must also be
133
+ * closed, if it is currently open.
60 134
  */
61
-static void ftp_done ( struct ftp_request *ftp, int rc ) {
62
-
63
-	DBGC ( ftp, "FTP %p completed with status %d\n", ftp, rc );
135
+static void ftp_control_close ( struct xfer_interface *control, int rc ) {
136
+	struct ftp_request *ftp =
137
+		container_of ( control, struct ftp_request, control );
64 138
 
65
-	/* Close both stream connections */
66
-	stream_close ( &ftp->stream );
67
-	stream_close ( &ftp->stream_data );
139
+	DBGC ( ftp, "FTP %p control connection closed: %s\n",
140
+	       ftp, strerror ( rc ) );
68 141
 
69
-	/* Mark asynchronous operation as complete */
70
-	async_done ( &ftp->async, rc );
142
+	/* Complete FTP operation */
143
+	ftp_done ( ftp, rc );
71 144
 }
72 145
 
73 146
 /**
@@ -102,9 +175,14 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
102 175
  */
103 176
 static void ftp_reply ( struct ftp_request *ftp ) {
104 177
 	char status_major = ftp->status_text[0];
178
+	char separator = ftp->status_text[3];
105 179
 
106 180
 	DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text );
107 181
 
182
+	/* Ignore malformed lines */
183
+	if ( separator != ' ' )
184
+		return;
185
+
108 186
 	/* Ignore "intermediate" responses (1xx codes) */
109 187
 	if ( status_major == '1' )
110 188
 		return;
@@ -133,47 +211,42 @@ static void ftp_reply ( struct ftp_request *ftp ) {
133 211
 				  sizeof ( sa.sin.sin_addr ) );
134 212
 		ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port,
135 213
 				  sizeof ( sa.sin.sin_port ) );
136
-		if ( ( rc = tcp_open ( &ftp->stream_data ) ) != 0 ) {
214
+		if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM,
215
+					       &sa.sa, NULL ) ) != 0 ) {
137 216
 			DBGC ( ftp, "FTP %p could not open data connection\n",
138 217
 			       ftp );
139 218
 			ftp_done ( ftp, rc );
140 219
 			return;
141 220
 		}
142
-		if ( ( rc = stream_connect ( &ftp->stream_data,
143
-					     &sa.sa ) ) != 0 ){
144
-			DBGC ( ftp, "FTP %p could not make data connection\n",
145
-			       ftp );
146
-			ftp_done ( ftp, rc );
147
-			return;
148
-		}
149 221
 	}
150 222
 
151 223
 	/* Move to next state */
152 224
 	if ( ftp->state < FTP_DONE )
153 225
 		ftp->state++;
154
-	ftp->already_sent = 0;
155 226
 
227
+	/* Send control string */
156 228
 	if ( ftp->state < FTP_DONE ) {
157 229
 		DBGC ( ftp, "FTP %p sending ", ftp );
158 230
 		DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
231
+		xfer_printf ( &ftp->control, ftp_strings[ftp->state],
232
+			      ftp->uri->path );
159 233
 	}
160
-
161
-	return;
162 234
 }
163 235
 
164 236
 /**
165 237
  * Handle new data arriving on FTP control channel
166 238
  *
167
- * @v app		Stream application
239
+ * @v control		FTP control channel interface
168 240
  * @v data		New data
169 241
  * @v len		Length of new data
170 242
  *
171 243
  * Data is collected until a complete line is received, at which point
172 244
  * its information is passed to ftp_reply().
173 245
  */
174
-static void ftp_newdata ( struct stream_application *app,
175
-			  void *data, size_t len ) {
176
-	struct ftp_request *ftp = stream_to_ftp ( app );
246
+static int ftp_control_deliver_raw ( struct xfer_interface *control,
247
+				     const void *data, size_t len ) {
248
+	struct ftp_request *ftp =
249
+		container_of ( control, struct ftp_request, control );
177 250
 	char *recvbuf = ftp->recvbuf;
178 251
 	size_t recvsize = ftp->recvsize;
179 252
 	char c;
@@ -215,62 +288,19 @@ static void ftp_newdata ( struct stream_application *app,
215 288
 	/* Store for next invocation */
216 289
 	ftp->recvbuf = recvbuf;
217 290
 	ftp->recvsize = recvsize;
218
-}
219 291
 
220
-/**
221
- * Handle acknowledgement of data sent on FTP control channel
222
- *
223
- * @v app		Stream application
224
- */
225
-static void ftp_acked ( struct stream_application *app, size_t len ) {
226
-	struct ftp_request *ftp = stream_to_ftp ( app );
227
-	
228
-	/* Mark off ACKed portion of the currently-transmitted data */
229
-	ftp->already_sent += len;
230
-}
231
-
232
-/**
233
- * Construct data to send on FTP control channel
234
- *
235
- * @v app		Stream application
236
- * @v buf		Temporary data buffer
237
- * @v len		Length of temporary data buffer
238
- */
239
-static void ftp_senddata ( struct stream_application *app,
240
-			   void *buf, size_t len ) {
241
-	struct ftp_request *ftp = stream_to_ftp ( app );
242
-
243
-	/* Send the as-yet-unACKed portion of the string for the
244
-	 * current state.
245
-	 */
246
-	len = snprintf ( buf, len, ftp_strings[ftp->state], ftp->uri->path );
247
-	stream_send ( app, buf + ftp->already_sent, len - ftp->already_sent );
248
-}
249
-
250
-/**
251
- * Handle control channel being closed
252
- *
253
- * @v app		Stream application
254
- *
255
- * When the control channel is closed, the data channel must also be
256
- * closed, if it is currently open.
257
- */
258
-static void ftp_closed ( struct stream_application *app, int rc ) {
259
-	struct ftp_request *ftp = stream_to_ftp ( app );
260
-
261
-	DBGC ( ftp, "FTP %p control connection closed: %s\n",
262
-	       ftp, strerror ( rc ) );
263
-
264
-	/* Complete FTP operation */
265
-	ftp_done ( ftp, rc );
292
+	return 0;
266 293
 }
267 294
 
268 295
 /** FTP control channel operations */
269
-static struct stream_application_operations ftp_stream_operations = {
270
-	.closed		= ftp_closed,
271
-	.acked		= ftp_acked,
272
-	.newdata	= ftp_newdata,
273
-	.senddata	= ftp_senddata,
296
+static struct xfer_interface_operations ftp_control_operations = {
297
+	.close		= ftp_control_close,
298
+	.vredirect	= xfer_vopen,
299
+	.request	= ignore_xfer_request,
300
+	.seek		= ignore_xfer_seek,
301
+	.alloc_iob	= default_xfer_alloc_iob,
302
+	.deliver_iob	= xfer_deliver_as_raw,
303
+	.deliver_raw	= ftp_control_deliver_raw,
274 304
 };
275 305
 
276 306
 /*****************************************************************************
@@ -280,20 +310,10 @@ static struct stream_application_operations ftp_stream_operations = {
280 310
  */
281 311
 
282 312
 /**
283
- * Get FTP request from data stream application
313
+ * Handle FTP data channel being closed
284 314
  *
285
- * @v app		Stream application
286
- * @ret ftp		FTP request
287
- */
288
-static inline struct ftp_request *
289
-stream_to_ftp_data ( struct stream_application *app ) {
290
-	return container_of ( app, struct ftp_request, stream_data );
291
-}
292
-
293
-/**
294
- * Handle data channel being closed
295
- *
296
- * @v app		Stream application
315
+ * @v data		FTP data channel interface
316
+ * @v rc		Reason for closure
297 317
  *
298 318
  * When the data channel is closed, the control channel should be left
299 319
  * alone; the server will send a completion message via the control
@@ -301,8 +321,9 @@ stream_to_ftp_data ( struct stream_application *app ) {
301 321
  *
302 322
  * If the data channel is closed due to an error, we abort the request.
303 323
  */
304
-static void ftp_data_closed ( struct stream_application *app, int rc ) {
305
-	struct ftp_request *ftp = stream_to_ftp_data ( app );
324
+static void ftp_data_closed ( struct xfer_interface *data, int rc ) {
325
+	struct ftp_request *ftp =
326
+		container_of ( data, struct ftp_request, data );
306 327
 
307 328
 	DBGC ( ftp, "FTP %p data connection closed: %s\n",
308 329
 	       ftp, strerror ( rc ) );
@@ -313,121 +334,132 @@ static void ftp_data_closed ( struct stream_application *app, int rc ) {
313 334
 }
314 335
 
315 336
 /**
316
- * Handle new data arriving on the FTP data channel
337
+ * Handle data delivery via FTP data channel
317 338
  *
318
- * @v app		Stream application
319
- * @v data		New data
320
- * @v len		Length of new data
339
+ * @v xfer		FTP data channel interface
340
+ * @v iobuf		I/O buffer
341
+ * @ret rc		Return status code
321 342
  */
322
-static void ftp_data_newdata ( struct stream_application *app,
323
-			       void *data, size_t len ) {
324
-	struct ftp_request *ftp = stream_to_ftp_data ( app );
343
+static int ftp_data_deliver_iob ( struct xfer_interface *data,
344
+				  struct io_buffer *iobuf ) {
345
+	struct ftp_request *ftp =
346
+		container_of ( data, struct ftp_request, data );
325 347
 	int rc;
326 348
 
327
-	/* Fill data buffer */
328
-	if ( ( rc = fill_buffer ( ftp->buffer, data,
329
-				  ftp->buffer->fill, len ) ) != 0 ){
330
-		DBGC ( ftp, "FTP %p failed to fill data buffer: %s\n",
349
+	if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
350
+		DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
331 351
 		       ftp, strerror ( rc ) );
332
-		ftp_done ( ftp, rc );
333
-		return;
352
+		return rc;
334 353
 	}
354
+
355
+	return 0;
335 356
 }
336 357
 
337 358
 /** FTP data channel operations */
338
-static struct stream_application_operations ftp_data_stream_operations = {
339
-	.closed		= ftp_data_closed,
340
-	.newdata	= ftp_data_newdata,
359
+static struct xfer_interface_operations ftp_data_operations = {
360
+	.close		= ftp_data_closed,
361
+	.vredirect	= xfer_vopen,
362
+	.request	= ignore_xfer_request,
363
+	.seek		= ignore_xfer_seek,
364
+	.alloc_iob	= default_xfer_alloc_iob,
365
+	.deliver_iob	= ftp_data_deliver_iob,
366
+	.deliver_raw	= xfer_deliver_as_iob,
341 367
 };
342 368
 
343 369
 /*****************************************************************************
344 370
  *
345
- * API
371
+ * Data transfer interface
346 372
  *
347 373
  */
348 374
 
349 375
 /**
350
- * Reap asynchronous operation
376
+ * Close FTP data transfer interface
351 377
  *
352
- * @v async		Asynchronous operation
378
+ * @v xfer		FTP data transfer interface
379
+ * @v rc		Reason for close
353 380
  */
354
-static void ftp_reap ( struct async *async ) {
381
+static void ftp_xfer_closed ( struct xfer_interface *xfer, int rc ) {
355 382
 	struct ftp_request *ftp =
356
-		container_of ( async, struct ftp_request, async );
383
+		container_of ( xfer, struct ftp_request, xfer );
357 384
 
358
-	free ( ftp );
385
+	DBGC ( ftp, "FTP %p data transfer interface closed: %s\n",
386
+	       ftp, strerror ( rc ) );
387
+	
388
+	ftp_done ( ftp, rc );
359 389
 }
360 390
 
361
-/** FTP asynchronous operations */
362
-static struct async_operations ftp_async_operations = {
363
-	.reap = ftp_reap,
391
+/** FTP data transfer interface operations */
392
+static struct xfer_interface_operations ftp_xfer_operations = {
393
+	.close		= ftp_xfer_closed,
394
+	.vredirect	= ignore_xfer_vredirect,
395
+	.request	= ignore_xfer_request,
396
+	.seek		= ignore_xfer_seek,
397
+	.alloc_iob	= default_xfer_alloc_iob,
398
+	.deliver_iob	= xfer_deliver_as_raw,
399
+	.deliver_raw	= ignore_xfer_deliver_raw,
364 400
 };
365 401
 
402
+/*****************************************************************************
403
+ *
404
+ * URI opener
405
+ *
406
+ */
407
+
366 408
 /**
367 409
  * Initiate an FTP connection
368 410
  *
411
+ * @v xfer		Data transfer interface
369 412
  * @v uri		Uniform Resource Identifier
370
- * @v buffer		Buffer into which to download file
371
- * @v parent		Parent asynchronous operation
372 413
  * @ret rc		Return status code
373 414
  */
374
-int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
375
-	struct ftp_request *ftp = NULL;
415
+static int ftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
416
+	struct ftp_request *ftp;
417
+	struct sockaddr_tcpip server;
376 418
 	int rc;
377 419
 
378 420
 	/* Sanity checks */
379
-	if ( ! uri->path ) {
380
-		rc = -EINVAL;
381
-		goto err;
382
-	}
421
+	if ( ! uri->path )
422
+		return -EINVAL;
423
+	if ( ! uri->host )
424
+		return -EINVAL;
383 425
 
384
-	/* Allocate and populate FTP structure */
426
+	/* Allocate and populate structure */
385 427
 	ftp = malloc ( sizeof ( *ftp ) );
386
-	if ( ! ftp ) {
387
-		rc = -ENOMEM;
388
-		goto err;
389
-	}
428
+	if ( ! ftp )
429
+		return -ENOMEM;
390 430
 	memset ( ftp, 0, sizeof ( *ftp ) );
391
-	ftp->uri = uri;
392
-	ftp->buffer = buffer;
393
-	ftp->state = FTP_CONNECT;
394
-	ftp->already_sent = 0;
431
+	ftp->refcnt.free = ftp_free;
432
+	xfer_init ( &ftp->xfer, &ftp_xfer_operations, &ftp->refcnt );
433
+	ftp->uri = uri_get ( uri );
434
+	xfer_init ( &ftp->control, &ftp_control_operations, &ftp->refcnt );
435
+	xfer_init ( &ftp->data, &ftp_data_operations, &ftp->refcnt );
395 436
 	ftp->recvbuf = ftp->status_text;
396 437
 	ftp->recvsize = sizeof ( ftp->status_text ) - 1;
397
-	ftp->stream.op = &ftp_stream_operations;
398
-	ftp->stream_data.op = &ftp_data_stream_operations;
399
-
400
-#warning "Quick name resolution hack"
401
-	union {
402
-		struct sockaddr sa;
403
-		struct sockaddr_in sin;
404
-	} server;
405
-	server.sin.sin_port = htons ( FTP_PORT );
406
-	server.sin.sin_family = AF_INET;
407
-	if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
408
-		rc = -EINVAL;
409
-		goto err;
410
-	}
411 438
 
412 439
 	DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
413 440
 
414
-	if ( ( rc = tcp_open ( &ftp->stream ) ) != 0 )
415
-		goto err;
416
-	if ( ( rc = stream_connect ( &ftp->stream, &server.sa ) ) != 0 )
441
+	/* Open control connection */
442
+	memset ( &server, 0, sizeof ( server ) );
443
+	server.st_port = htons ( uri_port ( uri, FTP_PORT ) );
444
+	if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM,
445
+					     ( struct sockaddr * ) &server,
446
+					     uri->host, NULL ) ) != 0 )
417 447
 		goto err;
418 448
 
419
-	async_init ( &ftp->async, &ftp_async_operations, parent );
449
+	/* Attach to parent interface, mortalise self, and return */
450
+	xfer_plug_plug ( &ftp->xfer, xfer );
451
+	ref_put ( &ftp->refcnt );
420 452
 	return 0;
421 453
 
422 454
  err:
423 455
 	DBGC ( ftp, "FTP %p could not create request: %s\n", 
424 456
 	       ftp, strerror ( rc ) );
425
-	free ( ftp );
457
+	ref_put ( &ftp->refcnt );
426 458
 	return rc;
427 459
 }
428 460
 
429
-/** HTTP download protocol */
430
-struct download_protocol ftp_download_protocol __download_protocol = {
431
-	.name = "ftp",
432
-	.start_download = ftp_get,
461
+/** FTP URI opener */
462
+struct uri_opener ftp_uri_opener __uri_opener = {
463
+	.scheme	= "ftp",
464
+	.open	= ftp_open,
433 465
 };

Chargement…
Annuler
Enregistrer