From dd6d94004f2cd33401978a91353f5c352caa1313 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Jan 2007 03:39:45 +0000 Subject: [PATCH] HTTP/DNS now working fully asynchronously. HTTP/IP addresses and any other protocol won't work at the moment. --- src/include/gpxe/http.h | 2 + src/include/usr/fetch.h | 16 ------ src/net/tcp/ftp.c | 7 +++ src/net/tcp/http.c | 89 +++++++++++++++++++------------- src/usr/fetch.c | 109 ---------------------------------------- src/usr/imgmgmt.c | 13 +++-- 6 files changed, 72 insertions(+), 164 deletions(-) delete mode 100644 src/include/usr/fetch.h delete mode 100644 src/usr/fetch.c diff --git a/src/include/gpxe/http.h b/src/include/gpxe/http.h index 49922e50..3cfc888a 100644 --- a/src/include/gpxe/http.h +++ b/src/include/gpxe/http.h @@ -41,6 +41,8 @@ struct http_request { /** HTTP Content-Length */ size_t content_length; + /** Server address */ + struct sockaddr server; /** TCP application for this request */ struct tcp_application tcp; /** Number of bytes already sent */ diff --git a/src/include/usr/fetch.h b/src/include/usr/fetch.h deleted file mode 100644 index 85b85634..00000000 --- a/src/include/usr/fetch.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _USR_FETCH_H -#define _USR_FETCH_H - -/** - * @file - * - * Fetch file - * - */ - -#include -#include - -extern int fetch ( const char *uri_string, userptr_t *data, size_t *len ); - -#endif /* _USR_FETCH_H */ diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index f3921ab7..7d10d855 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -7,6 +7,7 @@ #include #include #include +#include #include /** @file @@ -415,3 +416,9 @@ int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) { free ( ftp ); return rc; } + +/** HTTP download protocol */ +struct download_protocol ftp_download_protocol __download_protocol = { + .name = "ftp", + .start_download = ftp_get, +}; diff --git a/src/net/tcp/http.c b/src/net/tcp/http.c index 966351cb..6ae664ad 100644 --- a/src/net/tcp/http.c +++ b/src/net/tcp/http.c @@ -27,12 +27,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include static inline struct http_request * @@ -366,14 +368,46 @@ static void http_reap ( struct async *async ) { free ( http ); } +/** + * Handle name resolution completion + * + * @v async HTTP asynchronous operation + * @v signal SIGCHLD + */ +static void http_sigchld ( struct async *async, enum signal signal __unused ) { + struct http_request *http = + container_of ( async, struct http_request, async ); + struct sockaddr_tcpip *st = ( struct sockaddr_tcpip * ) &http->server; + int rc; + + /* Reap child */ + async_wait ( async, &rc, 1 ); + + /* If name resolution failed, abort now */ + if ( rc != 0 ) { + http_done ( http, rc ); + return; + } + + /* Otherwise, start the HTTP connection */ + http->tcp.tcp_op = &http_tcp_operations; + st->st_port = htons ( uri_port ( http->uri, HTTP_PORT ) ); + if ( ( rc = tcp_connect ( &http->tcp, st, 0 ) ) != 0 ) { + DBGC ( http, "HTTP %p could not open TCP connection: %s\n", + http, strerror ( rc ) ); + http_done ( http, rc ); + return; + } +} + /** HTTP asynchronous operations */ static struct async_operations http_async_operations = { - .reap = http_reap, + .reap = http_reap, + .signal = { + [SIGCHLD] = http_sigchld, + }, }; -#warning "Quick name resolution hack" -#include - /** * Initiate a HTTP connection * @@ -394,49 +428,36 @@ int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) { /* Allocate and populate HTTP structure */ http = malloc ( sizeof ( *http ) ); - if ( ! http ) { - rc = -ENOMEM; - goto err; - } + if ( ! http ) + return -ENOMEM; memset ( http, 0, sizeof ( *http ) ); http->uri = uri; http->buffer = buffer; - http->tcp.tcp_op = &http_tcp_operations; + async_init ( &http->async, &http_async_operations, parent ); + #warning "Quick name resolution hack" - union { - struct sockaddr_tcpip st; - struct sockaddr_in sin; - } server; - server.sin.sin_port = htons ( HTTP_PORT ); - server.sin.sin_family = AF_INET; - if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) { - /* Try DNS */ - struct async async; + extern int dns_resolv ( const char *name, + struct sockaddr *sa, + struct async *parent ); - extern int dns_resolv ( const char *name, - struct sockaddr_tcpip *st, - struct async *parent ); - - async_init_orphan ( &async ); - if ( ( rc = dns_resolv ( uri->host, &server.st, - &async ) ) != 0 ) - goto err; - async_wait ( &async, &rc, 1 ); - if ( rc != 0 ) - goto err; - } - - - if ( ( rc = tcp_connect ( &http->tcp, &server.st, 0 ) ) != 0 ) + if ( ( rc = dns_resolv ( uri->host, &http->server, + &http->async ) ) != 0 ) goto err; - async_init ( &http->async, &http_async_operations, parent ); + return 0; err: DBGC ( http, "HTTP %p could not create request: %s\n", http, strerror ( rc ) ); + async_uninit ( &http->async ); free ( http ); return rc; } + +/** HTTP download protocol */ +struct download_protocol http_download_protocol __download_protocol = { + .name = "http", + .start_download = http_get, +}; diff --git a/src/usr/fetch.c b/src/usr/fetch.c deleted file mode 100644 index 9260a48f..00000000 --- a/src/usr/fetch.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2007 Michael Brown . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/** - * @file - * - * Fetch file as executable/loadable image - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/** - * Fetch file - * - * @v filename Filename to fetch - * @ret data Loaded file - * @ret len Length of loaded file - * @ret rc Return status code - * - * Fetch file to an external buffer allocated with umalloc(). The - * caller is responsible for eventually freeing the buffer with - * ufree(). - */ -int fetch ( const char *uri_string, userptr_t *data, size_t *len ) { - struct uri *uri; - struct buffer buffer; - int rc; - - /* Parse the URI */ - uri = parse_uri ( uri_string ); - if ( ! uri ) { - rc = -ENOMEM; - goto err_parse_uri; - } - - /* Allocate an expandable buffer to hold the file */ - if ( ( rc = ebuffer_alloc ( &buffer, 0 ) ) != 0 ) { - goto err_ebuffer_alloc; - } - -#warning "Temporary pseudo-URL parsing code" - - /* Retrieve the file */ - struct async async; - - int ( * download ) ( struct uri *uri, struct buffer *buffer, - struct async *parent ); - - 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; - } - } - - if ( ( rc = async_block ( &async, - download ( uri, &buffer, &async ) ) ) != 0 ) - goto err; - - /* Fill in buffer address and length */ - *data = buffer.addr; - *len = buffer.fill; - - /* Release temporary resources. The ebuffer storage is now - * owned by our caller, so we don't free it. - */ - free_uri ( uri ); - return 0; - - err: - ufree ( buffer.addr ); - err_ebuffer_alloc: - free_uri ( uri ); - err_parse_uri: - return rc; -} diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index abd48bb3..06ae872e 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include /** @file @@ -34,14 +34,15 @@ /** * Fetch an image * - * @v filename Filename for image + * @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz") * @v name Name for image, or NULL * @ret new_image Newly created image * @ret rc Return status code */ -int imgfetch ( const char *filename, const char *name, +int imgfetch ( const char *uri_string, const char *name, struct image **new_image ) { struct image *image; + struct async async; int rc; /* Allocate new image */ @@ -54,8 +55,10 @@ int imgfetch ( const char *filename, const char *name, if ( name ) strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) ); - /* Fetch the file */ - if ( ( rc = fetch ( filename, &image->data, &image->len ) ) != 0 ) + /* Download the file */ + if ( ( rc = async_block ( &async, start_download ( uri_string, &async, + &image->data, + &image->len ))) !=0) goto err; /* Register the image */