Browse Source

Update TFTP and FTP to take the same temporary URI scheme as HTTP

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
df0397f334
5 changed files with 174 additions and 91 deletions
  1. 6
    9
      src/include/gpxe/ftp.h
  2. 9
    8
      src/include/gpxe/tftp.h
  3. 82
    48
      src/net/tcp/ftp.c
  4. 65
    17
      src/net/udp/tftp.c
  5. 12
    9
      src/usr/fetch.c

+ 6
- 9
src/include/gpxe/ftp.h View File

38
  *
38
  *
39
  */
39
  */
40
 struct ftp_request {
40
 struct ftp_request {
41
-	/** Server address */
42
-	struct sockaddr_tcpip server;
43
-	/** File to download */
44
-	const char *filename;
41
+	/** URI being fetched */
42
+	struct uri *uri;
45
 	/** Data buffer to fill */
43
 	/** Data buffer to fill */
46
 	struct buffer *buffer;
44
 	struct buffer *buffer;
45
+	/** Asynchronous operation */
46
+	struct async async;
47
 
47
 
48
 	/** Current state */
48
 	/** Current state */
49
 	enum ftp_state state;
49
 	enum ftp_state state;
57
 	char status_text[4];
57
 	char status_text[4];
58
 	/** Passive-mode parameters, as text */
58
 	/** Passive-mode parameters, as text */
59
 	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
59
 	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
60
-
61
 	/** TCP application for the control channel */
60
 	/** TCP application for the control channel */
62
 	struct tcp_application tcp;
61
 	struct tcp_application tcp;
63
 	/** TCP application for the data channel */
62
 	/** TCP application for the data channel */
64
 	struct tcp_application tcp_data;
63
 	struct tcp_application tcp_data;
65
-
66
-	/** Asynchronous operation for this FTP operation */
67
-	struct async async;
68
 };
64
 };
69
 
65
 
70
-struct async_operation * ftp_get ( struct ftp_request *ftp );
66
+extern int ftp_get ( struct uri *uri, struct buffer *buffer,
67
+		     struct async *parent );
71
 
68
 
72
 #endif /* _GPXE_FTP_H */
69
 #endif /* _GPXE_FTP_H */

+ 9
- 8
src/include/gpxe/tftp.h View File

86
  * This data structure holds the state for an ongoing TFTP transfer.
86
  * This data structure holds the state for an ongoing TFTP transfer.
87
  */
87
  */
88
 struct tftp_session {
88
 struct tftp_session {
89
-	/** UDP connection */
90
-	struct udp_connection udp;
91
-	/** Filename */
92
-	const char *filename;
89
+	/** URI being fetched */
90
+	struct uri *uri;
93
 	/** Data buffer to fill */
91
 	/** Data buffer to fill */
94
 	struct buffer *buffer;
92
 	struct buffer *buffer;
93
+	/** Asynchronous operation */
94
+	struct async async;
95
+
95
 	/** Requested data block size
96
 	/** Requested data block size
96
 	 *
97
 	 *
97
 	 * This is the "blksize" option requested from the TFTP
98
 	 * This is the "blksize" option requested from the TFTP
133
 	 * (i.e. that no blocks have yet been received).
134
 	 * (i.e. that no blocks have yet been received).
134
 	 */
135
 	 */
135
 	int state;
136
 	int state;
136
-	
137
-	/** Asynchronous operation for this session */
138
-	struct async async;
137
+	/** UDP connection */
138
+	struct udp_connection udp;
139
 	/** Retransmission timer */
139
 	/** Retransmission timer */
140
 	struct retry_timer timer;
140
 	struct retry_timer timer;
141
 };
141
 };
142
 
142
 
143
 /* Function prototypes */
143
 /* Function prototypes */
144
 
144
 
145
-extern struct async_operation * tftp_get ( struct tftp_session *tftp );
145
+extern int tftp_get ( struct uri *uri, struct buffer *buffer,
146
+		      struct async *parent );
146
 
147
 
147
 #endif /* _GPXE_TFTP_H */
148
 #endif /* _GPXE_TFTP_H */

+ 82
- 48
src/net/tcp/ftp.c View File

6
 #include <errno.h>
6
 #include <errno.h>
7
 #include <gpxe/async.h>
7
 #include <gpxe/async.h>
8
 #include <gpxe/buffer.h>
8
 #include <gpxe/buffer.h>
9
+#include <gpxe/uri.h>
9
 #include <gpxe/ftp.h>
10
 #include <gpxe/ftp.h>
10
 
11
 
11
 /** @file
12
 /** @file
20
  *
21
  *
21
  */
22
  */
22
 
23
 
23
-/** An FTP control channel string */
24
-struct ftp_string {
25
-	/** String format */
26
-	const char *format;
27
-	/** Offset to string data
28
-	 *
29
-	 * This is the offset within the struct ftp_request to the
30
-	 * pointer to the string data.  Use ftp_string_data() to get a
31
-	 * pointer to the actual data.
32
-	 */
33
-	off_t data_offset;
34
-};
35
-
36
-/** FTP control channel strings */
37
-static const struct ftp_string ftp_strings[] = {
38
-	[FTP_CONNECT]	= { "", 0 },
39
-	[FTP_USER]	= { "USER anonymous\r\n", 0 },
40
-	[FTP_PASS]	= { "PASS etherboot@etherboot.org\r\n", 0 },
41
-	[FTP_TYPE]	= { "TYPE I\r\n", 0 },
42
-	[FTP_PASV]	= { "PASV\r\n", 0 },
43
-	[FTP_RETR]	= { "RETR %s\r\n", 
44
-			    offsetof ( struct ftp_request, filename ) },
45
-	[FTP_QUIT]	= { "QUIT\r\n", 0 },
46
-	[FTP_DONE]	= { "", 0 },
47
-};
48
-
49
-/**
50
- * Get data associated with an FTP control channel string
24
+/** FTP control channel strings
51
  *
25
  *
52
- * @v ftp		FTP request
53
- * @v data_offset	Data offset field from ftp_string structure
54
- * @ret data		Pointer to data
26
+ * These are used as printf() format strings.  Since only one of them
27
+ * (RETR) takes an argument, we always supply that argument to the
28
+ * snprintf() call.
55
  */
29
  */
56
-static inline const void * ftp_string_data ( struct ftp_request *ftp,
57
-					     off_t data_offset ) {
58
-	return * ( ( void ** ) ( ( ( void * ) ftp ) + data_offset ) );
59
-}
30
+static const char * ftp_strings[] = {
31
+	[FTP_CONNECT]	= "",
32
+	[FTP_USER]	= "USER anonymous\r\n",
33
+	[FTP_PASS]	= "PASS etherboot@etherboot.org\r\n",
34
+	[FTP_TYPE]	= "TYPE I\r\n",
35
+	[FTP_PASV]	= "PASV\r\n",
36
+	[FTP_RETR]	= "RETR %s\r\n", 
37
+	[FTP_QUIT]	= "QUIT\r\n",
38
+	[FTP_DONE]	= "",
39
+};
60
 
40
 
61
 /**
41
 /**
62
  * Get FTP request from control TCP application
42
  * Get FTP request from control TCP application
163
 	ftp->already_sent = 0;
143
 	ftp->already_sent = 0;
164
 
144
 
165
 	if ( ftp->state < FTP_DONE ) {
145
 	if ( ftp->state < FTP_DONE ) {
166
-		const struct ftp_string *string = &ftp_strings[ftp->state];
167
 		DBGC ( ftp, "FTP %p sending ", ftp );
146
 		DBGC ( ftp, "FTP %p sending ", ftp );
168
-		DBGC ( ftp, string->format,
169
-		       ftp_string_data ( ftp, string->data_offset ) );
147
+		DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
170
 	}
148
 	}
171
 
149
 
172
 	return;
150
 	return;
250
 static void ftp_senddata ( struct tcp_application *app,
228
 static void ftp_senddata ( struct tcp_application *app,
251
 			   void *buf, size_t len ) {
229
 			   void *buf, size_t len ) {
252
 	struct ftp_request *ftp = tcp_to_ftp ( app );
230
 	struct ftp_request *ftp = tcp_to_ftp ( app );
253
-	const struct ftp_string *string;
254
 
231
 
255
 	/* Send the as-yet-unACKed portion of the string for the
232
 	/* Send the as-yet-unACKed portion of the string for the
256
 	 * current state.
233
 	 * current state.
257
 	 */
234
 	 */
258
-	string = &ftp_strings[ftp->state];
259
-	len = snprintf ( buf, len, string->format,
260
-			 ftp_string_data ( ftp, string->data_offset ) );
235
+	len = snprintf ( buf, len, ftp_strings[ftp->state], ftp->uri->path );
261
 	tcp_send ( app, buf + ftp->already_sent, len - ftp->already_sent );
236
 	tcp_send ( app, buf + ftp->already_sent, len - ftp->already_sent );
262
 }
237
 }
263
 
238
 
360
  *
335
  *
361
  */
336
  */
362
 
337
 
338
+/**
339
+ * Reap asynchronous operation
340
+ *
341
+ * @v async		Asynchronous operation
342
+ */
343
+static void ftp_reap ( struct async *async ) {
344
+	struct ftp_request *ftp =
345
+		container_of ( async, struct ftp_request, async );
346
+
347
+	free ( ftp );
348
+}
349
+
350
+/** FTP asynchronous operations */
351
+static struct async_operations ftp_async_operations = {
352
+	.reap = ftp_reap,
353
+};
354
+
355
+#warning "Quick name resolution hack"
356
+#include <byteswap.h>
357
+
363
 /**
358
 /**
364
  * Initiate an FTP connection
359
  * Initiate an FTP connection
365
  *
360
  *
366
- * @v ftp	FTP request
361
+ * @v uri		Uniform Resource Identifier
362
+ * @v buffer		Buffer into which to download file
363
+ * @v parent		Parent asynchronous operation
364
+ * @ret rc		Return status code
367
  */
365
  */
368
-struct async_operation * ftp_get ( struct ftp_request *ftp ) {
366
+int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
367
+	struct ftp_request *ftp = NULL;
369
 	int rc;
368
 	int rc;
370
 
369
 
371
-	DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->filename );
370
+	/* Sanity checks */
371
+	if ( ! uri->path ) {
372
+		rc = -EINVAL;
373
+		goto err;
374
+	}
372
 
375
 
376
+	/* Allocate and populate FTP structure */
377
+	ftp = malloc ( sizeof ( *ftp ) );
378
+	if ( ! ftp ) {
379
+		rc = -ENOMEM;
380
+		goto err;
381
+	}
382
+	memset ( ftp, 0, sizeof ( *ftp ) );
383
+	ftp->uri = uri;
384
+	ftp->buffer = buffer;
373
 	ftp->state = FTP_CONNECT;
385
 	ftp->state = FTP_CONNECT;
374
 	ftp->already_sent = 0;
386
 	ftp->already_sent = 0;
375
 	ftp->recvbuf = ftp->status_text;
387
 	ftp->recvbuf = ftp->status_text;
376
 	ftp->recvsize = sizeof ( ftp->status_text ) - 1;
388
 	ftp->recvsize = sizeof ( ftp->status_text ) - 1;
377
 	ftp->tcp.tcp_op = &ftp_tcp_operations;
389
 	ftp->tcp.tcp_op = &ftp_tcp_operations;
378
 	ftp->tcp_data.tcp_op = &ftp_data_tcp_operations;
390
 	ftp->tcp_data.tcp_op = &ftp_data_tcp_operations;
379
-	if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
380
-		ftp_done ( ftp, rc );
381
 
391
 
382
-	return &ftp->async;
392
+#warning "Quick name resolution hack"
393
+	union {
394
+		struct sockaddr_tcpip st;
395
+		struct sockaddr_in sin;
396
+	} server;
397
+	server.sin.sin_port = htons ( FTP_PORT );
398
+	server.sin.sin_family = AF_INET;
399
+	if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
400
+		rc = -EINVAL;
401
+		goto err;
402
+	}
403
+
404
+	DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
405
+
406
+	if ( ( rc = tcp_connect ( &ftp->tcp, &server.st, 0 ) ) != 0 )
407
+		goto err;
408
+
409
+	async_init ( &ftp->async, &ftp_async_operations, parent );
410
+	return 0;
411
+
412
+ err:
413
+	DBGC ( ftp, "FTP %p could not create request: %s\n", 
414
+	       ftp, strerror ( rc ) );
415
+	free ( ftp );
416
+	return rc;
383
 }
417
 }

+ 65
- 17
src/net/udp/tftp.c View File

26
 #include <vsprintf.h>
26
 #include <vsprintf.h>
27
 #include <gpxe/async.h>
27
 #include <gpxe/async.h>
28
 #include <gpxe/tftp.h>
28
 #include <gpxe/tftp.h>
29
+#include <gpxe/uri.h>
29
 
30
 
30
 /** @file
31
 /** @file
31
  *
32
  *
203
 	void *data;
204
 	void *data;
204
 	void *end;
205
 	void *end;
205
 
206
 
206
-	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->filename );
207
+	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->uri->path );
207
 
208
 
208
 	data = rrq->data;
209
 	data = rrq->data;
209
 	end = ( buf + len );
210
 	end = ( buf + len );
211
 		goto overflow;
212
 		goto overflow;
212
 	data += ( snprintf ( data, ( end - data ),
213
 	data += ( snprintf ( data, ( end - data ),
213
 			     "%s%coctet%cblksize%c%d%ctsize%c0",
214
 			     "%s%coctet%cblksize%c%d%ctsize%c0",
214
-			     tftp->filename, 0, 0, 0,
215
+			     tftp->uri->path, 0, 0, 0,
215
 			     tftp->request_blksize, 0, 0 ) + 1 );
216
 			     tftp->request_blksize, 0, 0 ) + 1 );
216
 	if ( data > end )
217
 	if ( data > end )
217
 		goto overflow;
218
 		goto overflow;
452
 	.newdata = tftp_newdata,
453
 	.newdata = tftp_newdata,
453
 };
454
 };
454
 
455
 
456
+/**
457
+ * Reap asynchronous operation
458
+ *
459
+ * @v async		Asynchronous operation
460
+ */
461
+static void tftp_reap ( struct async *async ) {
462
+	struct tftp_session *tftp =
463
+		container_of ( async, struct tftp_session, async );
464
+
465
+	free ( tftp );
466
+}
467
+
468
+/** TFTP asynchronous operations */
469
+static struct async_operations tftp_async_operations = {
470
+	.reap = tftp_reap,
471
+};
472
+
455
 /**
473
 /**
456
  * Initiate TFTP download
474
  * Initiate TFTP download
457
  *
475
  *
458
- * @v tftp		TFTP session
459
- * @ret aop		Asynchronous operation
476
+ * @v uri		Uniform Resource Identifier
477
+ * @v buffer		Buffer into which to download file
478
+ * @v parent		Parent asynchronous operation
479
+ * @ret rc		Return status code
460
  */
480
  */
461
-struct async_operation * tftp_get ( struct tftp_session *tftp ) {
481
+int tftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
482
+	struct tftp_session *tftp = NULL;
462
 	int rc;
483
 	int rc;
463
 
484
 
464
-	assert ( tftp->filename != NULL );
465
-	assert ( tftp->buffer != NULL );
466
-	assert ( tftp->udp.peer.st_family != 0 );
485
+	/* Sanity checks */
486
+	if ( ! uri->path ) {
487
+		rc = -EINVAL;
488
+		goto err;
489
+	}
467
 
490
 
468
-	/* Initialise TFTP session */
491
+	/* Allocate and populate TFTP structure */
492
+	tftp = malloc ( sizeof ( *tftp ) );
493
+	if ( ! tftp ) {
494
+		rc = -ENOMEM;
495
+		goto err;
496
+	}
497
+	memset ( tftp, 0, sizeof ( *tftp ) );
498
+	tftp->uri = uri;
499
+	tftp->buffer = buffer;
469
 	if ( ! tftp->request_blksize )
500
 	if ( ! tftp->request_blksize )
470
 		tftp->request_blksize = TFTP_MAX_BLKSIZE;
501
 		tftp->request_blksize = TFTP_MAX_BLKSIZE;
471
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
502
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
472
-	tftp->tsize = 0;
473
-	tftp->tid = 0;
474
 	tftp->state = -1;
503
 	tftp->state = -1;
475
 	tftp->udp.udp_op = &tftp_udp_operations;
504
 	tftp->udp.udp_op = &tftp_udp_operations;
476
 	tftp->timer.expired = tftp_timer_expired;
505
 	tftp->timer.expired = tftp_timer_expired;
477
 
506
 
478
-	/* Open UDP connection */
479
-	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
480
-		async_done ( &tftp->async, rc );
481
-		goto out;
507
+
508
+#warning "Quick name resolution hack"
509
+	union {
510
+		struct sockaddr_tcpip st;
511
+		struct sockaddr_in sin;
512
+	} server;
513
+	server.sin.sin_port = htons ( TFTP_PORT );
514
+	server.sin.sin_family = AF_INET;
515
+	if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
516
+		rc = -EINVAL;
517
+		goto err;
482
 	}
518
 	}
519
+	udp_connect ( &tftp->udp, &server.st );
520
+
521
+
522
+	/* Open UDP connection */
523
+	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 )
524
+		goto err;
483
 
525
 
484
 	/* Transmit initial RRQ */
526
 	/* Transmit initial RRQ */
485
 	tftp_send_packet ( tftp );
527
 	tftp_send_packet ( tftp );
486
 
528
 
487
- out:
488
-	return &tftp->async;
529
+	async_init ( &tftp->async, &tftp_async_operations, parent );
530
+	return 0;
531
+
532
+ err:
533
+	DBGC ( tftp, "TFTP %p could not create session: %s\n",
534
+	       tftp, strerror ( rc ) );
535
+	free ( tftp );
536
+	return rc;
489
 }
537
 }

+ 12
- 9
src/usr/fetch.c View File

35
 #include <gpxe/dhcp.h>
35
 #include <gpxe/dhcp.h>
36
 #include <gpxe/tftp.h>
36
 #include <gpxe/tftp.h>
37
 #include <gpxe/http.h>
37
 #include <gpxe/http.h>
38
+#include <gpxe/ftp.h>
38
 
39
 
39
 /**
40
 /**
40
  * Fetch file
41
  * Fetch file
73
 	int ( * download ) ( struct uri *uri, struct buffer *buffer,
74
 	int ( * download ) ( struct uri *uri, struct buffer *buffer,
74
 			     struct async *parent );
75
 			     struct async *parent );
75
 
76
 
76
-#if 0
77
-	server.sin.sin_port = htons ( TFTP_PORT );
78
-	udp_connect ( &tftp.udp, &server.st );
79
-	tftp.filename = filename;
80
-	tftp.buffer = &buffer;
81
-	aop = tftp_get ( &tftp );
82
-#else
83
-	download = http_get;
84
-#endif
77
+	if ( ! uri->scheme ) {
78
+		download = tftp_get;
79
+	} else {
80
+		if ( strcmp ( uri->scheme, "http" ) == 0 ) {
81
+			download = http_get;
82
+		} else if ( strcmp ( uri->scheme, "ftp" ) == 0 ) {
83
+			download = ftp_get;
84
+		} else {
85
+			download = tftp_get;
86
+		}
87
+	}
85
 
88
 
86
 	async_init_orphan ( &async );
89
 	async_init_orphan ( &async );
87
 	if ( ( rc = download ( uri, &buffer, &async ) ) != 0 )
90
 	if ( ( rc = download ( uri, &buffer, &async ) ) != 0 )

Loading…
Cancel
Save