2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <gpxe/umalloc.h>
30 #include <gpxe/ebuffer.h>
31 #include <gpxe/download.h>
33 static struct async_operations download_async_operations;
35 /** Registered download protocols */
36 static struct download_protocol download_protocols[0]
37 __table_start ( struct download_protocol, download_protocols );
38 static struct download_protocol download_protocols_end[0]
39 __table_end ( struct download_protocol, download_protocols );
42 * Identify download protocol
44 * @v name Download protocol name
45 * @ret protocol Download protocol, or NULL
47 static struct download_protocol * find_protocol ( const char *name ) {
48 struct download_protocol *protocol;
50 for ( protocol = download_protocols; protocol < download_protocols_end;
52 if ( strcmp ( name, protocol->name ) == 0 )
61 * @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
62 * @v parent Parent asynchronous operation
63 * @ret data Loaded file
64 * @ret len Length of loaded file
65 * @ret rc Return status code
67 * Starts download of a file to a user buffer. The user buffer is
68 * allocated with umalloc(). The parent asynchronous operation will
69 * be notified via SIGCHLD when the download completes. If the
70 * download completes successfully, the @c data and @c len fields will
71 * have been filled in, and the parent takes ownership of the buffer,
72 * which must eventually be freed with ufree().
74 * The uri_string does not need to remain persistent for the duration
75 * of the download; the parent may discard it as soon as
76 * start_download returns.
78 int start_download ( const char *uri_string, struct async *parent,
79 userptr_t *data, size_t *len ) {
80 struct download *download;
83 /* Allocate and populate download structure */
84 download = malloc ( sizeof ( *download ) );
87 memset ( download, 0, sizeof ( *download ) );
88 download->data = data;
90 async_init ( &download->async, &download_async_operations, parent );
93 download->uri = parse_uri ( uri_string );
94 if ( ! download->uri ) {
99 /* Allocate an expandable buffer to hold the file */
100 if ( ( rc = ebuffer_alloc ( &download->buffer, 0 ) ) != 0 )
103 /* Identify the download protocol */
104 download->protocol = find_protocol ( download->uri->scheme );
105 if ( ! download->protocol ) {
106 DBG ( "No such protocol \"%s\"\n", download->uri->scheme );
111 /* Start the actual download */
112 if ( ( rc = download->protocol->start_download ( download->uri,
113 &download->buffer, &download->async ) ) != 0 ) {
114 DBG ( "Could not start \"%s\" download: %s\n",
115 download->uri->scheme, strerror ( rc ) );
122 async_uninit ( &download->async );
123 ufree ( download->buffer.addr );
124 free_uri ( download->uri );
130 * Handle download termination
132 * @v async Download asynchronous operation
135 static void download_sigchld ( struct async *async,
136 enum signal signal __unused ) {
137 struct download *download =
138 container_of ( async, struct download, async );
142 async_wait ( async, &rc, 1 );
146 /* Transfer ownership of buffer to parent */
147 *(download->data) = download->buffer.addr;
148 *(download->len) = download->buffer.fill;
150 /* Discard the buffer */
151 ufree ( download->buffer.addr );
153 free_uri ( download->uri );
154 download->uri = NULL;
156 /* Terminate ourselves */
157 async_done ( async, rc );
161 * Free download resources
163 * @v async Download asynchronous operation
165 static void download_reap ( struct async *async ) {
166 free ( container_of ( async, struct download, async ) );
169 /** Download asynchronous operations */
170 static struct async_operations download_async_operations = {
171 .reap = download_reap,
173 [SIGCHLD] = download_sigchld,