summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2007-01-15 10:58:26 +0100
committerMichael Brown2007-01-15 10:58:26 +0100
commitdf0397f33469f9e3ed1d54cedd5fe6282881e3fc (patch)
tree91bef77876d4799fcd0cdaa260fb11805a72baa6
parentProtocol's get() method no longer takes ownership of the URI. HTTP is the (diff)
downloadipxe-df0397f33469f9e3ed1d54cedd5fe6282881e3fc.tar.gz
ipxe-df0397f33469f9e3ed1d54cedd5fe6282881e3fc.tar.xz
ipxe-df0397f33469f9e3ed1d54cedd5fe6282881e3fc.zip
Update TFTP and FTP to take the same temporary URI scheme as HTTP
-rw-r--r--src/include/gpxe/ftp.h15
-rw-r--r--src/include/gpxe/tftp.h17
-rw-r--r--src/net/tcp/ftp.c130
-rw-r--r--src/net/udp/tftp.c82
-rw-r--r--src/usr/fetch.c21
5 files changed, 174 insertions, 91 deletions
diff --git a/src/include/gpxe/ftp.h b/src/include/gpxe/ftp.h
index 06799d24..64e8d4e4 100644
--- a/src/include/gpxe/ftp.h
+++ b/src/include/gpxe/ftp.h
@@ -38,12 +38,12 @@ enum ftp_state {
*
*/
struct ftp_request {
- /** Server address */
- struct sockaddr_tcpip server;
- /** File to download */
- const char *filename;
+ /** URI being fetched */
+ struct uri *uri;
/** Data buffer to fill */
struct buffer *buffer;
+ /** Asynchronous operation */
+ struct async async;
/** Current state */
enum ftp_state state;
@@ -57,16 +57,13 @@ struct ftp_request {
char status_text[4];
/** Passive-mode parameters, as text */
char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
-
/** TCP application for the control channel */
struct tcp_application tcp;
/** TCP application for the data channel */
struct tcp_application tcp_data;
-
- /** Asynchronous operation for this FTP operation */
- struct async async;
};
-struct async_operation * ftp_get ( struct ftp_request *ftp );
+extern int ftp_get ( struct uri *uri, struct buffer *buffer,
+ struct async *parent );
#endif /* _GPXE_FTP_H */
diff --git a/src/include/gpxe/tftp.h b/src/include/gpxe/tftp.h
index 551a6fc9..cb643d9c 100644
--- a/src/include/gpxe/tftp.h
+++ b/src/include/gpxe/tftp.h
@@ -86,12 +86,13 @@ union tftp_any {
* This data structure holds the state for an ongoing TFTP transfer.
*/
struct tftp_session {
- /** UDP connection */
- struct udp_connection udp;
- /** Filename */
- const char *filename;
+ /** URI being fetched */
+ struct uri *uri;
/** Data buffer to fill */
struct buffer *buffer;
+ /** Asynchronous operation */
+ struct async async;
+
/** Requested data block size
*
* This is the "blksize" option requested from the TFTP
@@ -133,15 +134,15 @@ struct tftp_session {
* (i.e. that no blocks have yet been received).
*/
int state;
-
- /** Asynchronous operation for this session */
- struct async async;
+ /** UDP connection */
+ struct udp_connection udp;
/** Retransmission timer */
struct retry_timer timer;
};
/* Function prototypes */
-extern struct async_operation * tftp_get ( struct tftp_session *tftp );
+extern int tftp_get ( struct uri *uri, struct buffer *buffer,
+ struct async *parent );
#endif /* _GPXE_TFTP_H */
diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c
index 8a27f8cb..f3921ab7 100644
--- a/src/net/tcp/ftp.c
+++ b/src/net/tcp/ftp.c
@@ -6,6 +6,7 @@
#include <errno.h>
#include <gpxe/async.h>
#include <gpxe/buffer.h>
+#include <gpxe/uri.h>
#include <gpxe/ftp.h>
/** @file
@@ -20,43 +21,22 @@
*
*/
-/** An FTP control channel string */
-struct ftp_string {
- /** String format */
- const char *format;
- /** Offset to string data
- *
- * This is the offset within the struct ftp_request to the
- * pointer to the string data. Use ftp_string_data() to get a
- * pointer to the actual data.
- */
- off_t data_offset;
-};
-
-/** FTP control channel strings */
-static const struct ftp_string ftp_strings[] = {
- [FTP_CONNECT] = { "", 0 },
- [FTP_USER] = { "USER anonymous\r\n", 0 },
- [FTP_PASS] = { "PASS etherboot@etherboot.org\r\n", 0 },
- [FTP_TYPE] = { "TYPE I\r\n", 0 },
- [FTP_PASV] = { "PASV\r\n", 0 },
- [FTP_RETR] = { "RETR %s\r\n",
- offsetof ( struct ftp_request, filename ) },
- [FTP_QUIT] = { "QUIT\r\n", 0 },
- [FTP_DONE] = { "", 0 },
-};
-
-/**
- * Get data associated with an FTP control channel string
+/** FTP control channel strings
*
- * @v ftp FTP request
- * @v data_offset Data offset field from ftp_string structure
- * @ret data Pointer to data
+ * These are used as printf() format strings. Since only one of them
+ * (RETR) takes an argument, we always supply that argument to the
+ * snprintf() call.
*/
-static inline const void * ftp_string_data ( struct ftp_request *ftp,
- off_t data_offset ) {
- return * ( ( void ** ) ( ( ( void * ) ftp ) + data_offset ) );
-}
+static const char * ftp_strings[] = {
+ [FTP_CONNECT] = "",
+ [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_QUIT] = "QUIT\r\n",
+ [FTP_DONE] = "",
+};
/**
* Get FTP request from control TCP application
@@ -163,10 +143,8 @@ static void ftp_reply ( struct ftp_request *ftp ) {
ftp->already_sent = 0;
if ( ftp->state < FTP_DONE ) {
- const struct ftp_string *string = &ftp_strings[ftp->state];
DBGC ( ftp, "FTP %p sending ", ftp );
- DBGC ( ftp, string->format,
- ftp_string_data ( ftp, string->data_offset ) );
+ DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
}
return;
@@ -250,14 +228,11 @@ static void ftp_acked ( struct tcp_application *app, size_t len ) {
static void ftp_senddata ( struct tcp_application *app,
void *buf, size_t len ) {
struct ftp_request *ftp = tcp_to_ftp ( app );
- const struct ftp_string *string;
/* Send the as-yet-unACKed portion of the string for the
* current state.
*/
- string = &ftp_strings[ftp->state];
- len = snprintf ( buf, len, string->format,
- ftp_string_data ( ftp, string->data_offset ) );
+ len = snprintf ( buf, len, ftp_strings[ftp->state], ftp->uri->path );
tcp_send ( app, buf + ftp->already_sent, len - ftp->already_sent );
}
@@ -361,23 +336,82 @@ static struct tcp_operations ftp_data_tcp_operations = {
*/
/**
+ * Reap asynchronous operation
+ *
+ * @v async Asynchronous operation
+ */
+static void ftp_reap ( struct async *async ) {
+ struct ftp_request *ftp =
+ container_of ( async, struct ftp_request, async );
+
+ free ( ftp );
+}
+
+/** FTP asynchronous operations */
+static struct async_operations ftp_async_operations = {
+ .reap = ftp_reap,
+};
+
+#warning "Quick name resolution hack"
+#include <byteswap.h>
+
+/**
* Initiate an FTP connection
*
- * @v ftp FTP request
+ * @v uri Uniform Resource Identifier
+ * @v buffer Buffer into which to download file
+ * @v parent Parent asynchronous operation
+ * @ret rc Return status code
*/
-struct async_operation * ftp_get ( struct ftp_request *ftp ) {
+int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
+ struct ftp_request *ftp = NULL;
int rc;
- DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->filename );
+ /* Sanity checks */
+ if ( ! uri->path ) {
+ rc = -EINVAL;
+ goto err;
+ }
+ /* Allocate and populate FTP structure */
+ ftp = malloc ( sizeof ( *ftp ) );
+ if ( ! ftp ) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ memset ( ftp, 0, sizeof ( *ftp ) );
+ ftp->uri = uri;
+ ftp->buffer = buffer;
ftp->state = FTP_CONNECT;
ftp->already_sent = 0;
ftp->recvbuf = ftp->status_text;
ftp->recvsize = sizeof ( ftp->status_text ) - 1;
ftp->tcp.tcp_op = &ftp_tcp_operations;
ftp->tcp_data.tcp_op = &ftp_data_tcp_operations;
- if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
- ftp_done ( ftp, rc );
- return &ftp->async;
+#warning "Quick name resolution hack"
+ union {
+ struct sockaddr_tcpip st;
+ struct sockaddr_in sin;
+ } server;
+ server.sin.sin_port = htons ( FTP_PORT );
+ server.sin.sin_family = AF_INET;
+ if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
+
+ if ( ( rc = tcp_connect ( &ftp->tcp, &server.st, 0 ) ) != 0 )
+ goto err;
+
+ async_init ( &ftp->async, &ftp_async_operations, parent );
+ return 0;
+
+ err:
+ DBGC ( ftp, "FTP %p could not create request: %s\n",
+ ftp, strerror ( rc ) );
+ free ( ftp );
+ return rc;
}
diff --git a/src/net/udp/tftp.c b/src/net/udp/tftp.c
index 69650ab0..992b82ba 100644
--- a/src/net/udp/tftp.c
+++ b/src/net/udp/tftp.c
@@ -26,6 +26,7 @@
#include <vsprintf.h>
#include <gpxe/async.h>
#include <gpxe/tftp.h>
+#include <gpxe/uri.h>
/** @file
*
@@ -203,7 +204,7 @@ static int tftp_send_rrq ( struct tftp_session *tftp, void *buf, size_t len ) {
void *data;
void *end;
- DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->filename );
+ DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->uri->path );
data = rrq->data;
end = ( buf + len );
@@ -211,7 +212,7 @@ static int tftp_send_rrq ( struct tftp_session *tftp, void *buf, size_t len ) {
goto overflow;
data += ( snprintf ( data, ( end - data ),
"%s%coctet%cblksize%c%d%ctsize%c0",
- tftp->filename, 0, 0, 0,
+ tftp->uri->path, 0, 0, 0,
tftp->request_blksize, 0, 0 ) + 1 );
if ( data > end )
goto overflow;
@@ -453,37 +454,84 @@ static struct udp_operations tftp_udp_operations = {
};
/**
+ * Reap asynchronous operation
+ *
+ * @v async Asynchronous operation
+ */
+static void tftp_reap ( struct async *async ) {
+ struct tftp_session *tftp =
+ container_of ( async, struct tftp_session, async );
+
+ free ( tftp );
+}
+
+/** TFTP asynchronous operations */
+static struct async_operations tftp_async_operations = {
+ .reap = tftp_reap,
+};
+
+/**
* Initiate TFTP download
*
- * @v tftp TFTP session
- * @ret aop Asynchronous operation
+ * @v uri Uniform Resource Identifier
+ * @v buffer Buffer into which to download file
+ * @v parent Parent asynchronous operation
+ * @ret rc Return status code
*/
-struct async_operation * tftp_get ( struct tftp_session *tftp ) {
+int tftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
+ struct tftp_session *tftp = NULL;
int rc;
- assert ( tftp->filename != NULL );
- assert ( tftp->buffer != NULL );
- assert ( tftp->udp.peer.st_family != 0 );
+ /* Sanity checks */
+ if ( ! uri->path ) {
+ rc = -EINVAL;
+ goto err;
+ }
- /* Initialise TFTP session */
+ /* Allocate and populate TFTP structure */
+ tftp = malloc ( sizeof ( *tftp ) );
+ if ( ! tftp ) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ memset ( tftp, 0, sizeof ( *tftp ) );
+ tftp->uri = uri;
+ tftp->buffer = buffer;
if ( ! tftp->request_blksize )
tftp->request_blksize = TFTP_MAX_BLKSIZE;
tftp->blksize = TFTP_DEFAULT_BLKSIZE;
- tftp->tsize = 0;
- tftp->tid = 0;
tftp->state = -1;
tftp->udp.udp_op = &tftp_udp_operations;
tftp->timer.expired = tftp_timer_expired;
- /* Open UDP connection */
- if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
- async_done ( &tftp->async, rc );
- goto out;
+
+#warning "Quick name resolution hack"
+ union {
+ struct sockaddr_tcpip st;
+ struct sockaddr_in sin;
+ } server;
+ server.sin.sin_port = htons ( TFTP_PORT );
+ server.sin.sin_family = AF_INET;
+ if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
+ rc = -EINVAL;
+ goto err;
}
+ udp_connect ( &tftp->udp, &server.st );
+
+
+ /* Open UDP connection */
+ if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 )
+ goto err;
/* Transmit initial RRQ */
tftp_send_packet ( tftp );
- out:
- return &tftp->async;
+ async_init ( &tftp->async, &tftp_async_operations, parent );
+ return 0;
+
+ err:
+ DBGC ( tftp, "TFTP %p could not create session: %s\n",
+ tftp, strerror ( rc ) );
+ free ( tftp );
+ return rc;
}
diff --git a/src/usr/fetch.c b/src/usr/fetch.c
index 71304bb2..45031049 100644
--- a/src/usr/fetch.c
+++ b/src/usr/fetch.c
@@ -35,6 +35,7 @@
#include <gpxe/dhcp.h>
#include <gpxe/tftp.h>
#include <gpxe/http.h>
+#include <gpxe/ftp.h>
/**
* Fetch file
@@ -73,15 +74,17 @@ int fetch ( const char *uri_string, userptr_t *data, size_t *len ) {
int ( * download ) ( struct uri *uri, struct buffer *buffer,
struct async *parent );
-#if 0
- server.sin.sin_port = htons ( TFTP_PORT );
- udp_connect ( &tftp.udp, &server.st );
- tftp.filename = filename;
- tftp.buffer = &buffer;
- aop = tftp_get ( &tftp );
-#else
- download = http_get;
-#endif
+ if ( ! uri->scheme ) {
+ download = tftp_get;
+ } else {
+ if ( strcmp ( uri->scheme, "http" ) == 0 ) {
+ download = http_get;
+ } else if ( strcmp ( uri->scheme, "ftp" ) == 0 ) {
+ download = ftp_get;
+ } else {
+ download = tftp_get;
+ }
+ }
async_init_orphan ( &async );
if ( ( rc = download ( uri, &buffer, &async ) ) != 0 )