Browse Source

Replacement for fetch() which operates asynchronously and identifies

protocols by URI scheme.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
0b11733b75
2 changed files with 231 additions and 0 deletions
  1. 172
    0
      src/core/download.c
  2. 59
    0
      src/include/gpxe/download.h

+ 172
- 0
src/core/download.c View File

@@ -0,0 +1,172 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
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.
8
+ *
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.
13
+ *
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.
17
+ */
18
+
19
+/**
20
+ * @file
21
+ *
22
+ * Download protocols
23
+ *
24
+ */
25
+
26
+#include <stdint.h>
27
+#include <stdlib.h>
28
+#include <errno.h>
29
+#include <gpxe/umalloc.h>
30
+#include <gpxe/ebuffer.h>
31
+#include <gpxe/download.h>
32
+
33
+/** Registered download protocols */
34
+static struct download_protocol download_protocols[0]
35
+	__table_start ( struct download_protocol, download_protocols );
36
+static struct download_protocol download_protocols_end[0]
37
+	__table_end ( struct download_protocol, download_protocols );
38
+
39
+/**
40
+ * Identify download protocol
41
+ *
42
+ * @v name		Download protocol name
43
+ * @ret protocol	Download protocol, or NULL
44
+ */
45
+static struct download_protocol * find_protocol ( const char *name ) {
46
+	struct download_protocol *protocol;
47
+
48
+	for ( protocol = download_protocols; protocol < download_protocols_end;
49
+	      protocol++ ) {
50
+		if ( strcmp ( name, protocol->name ) == 0 )
51
+			return protocol;
52
+	}
53
+	return NULL;
54
+}
55
+
56
+/** Free download resources */
57
+static void download_reap ( struct async *async ) {
58
+	struct download *download =
59
+		container_of ( async, struct download, async );
60
+
61
+	free ( download );
62
+}
63
+
64
+/**
65
+ * Handle download termination
66
+ *
67
+ * @v async		Download asynchronous operation
68
+ * @v signal		SIGCHLD
69
+ */
70
+static void download_sigchld ( struct async *async,
71
+			       enum signal signal __unused ) {
72
+	struct download *download =
73
+		container_of ( async, struct download, async );
74
+	int rc;
75
+
76
+	/* Reap child */
77
+	async_wait ( async, &rc, 1 );
78
+
79
+	/* Clean up */
80
+	if ( rc == 0 ) {
81
+		/* Transfer ownership of buffer to parent */
82
+		*(download->data) = download->buffer.addr;
83
+		*(download->len) = download->buffer.fill;
84
+	} else {
85
+		/* Discard the buffer */
86
+		ufree ( download->buffer.addr );
87
+	}
88
+	free_uri ( download->uri );
89
+	download->uri = NULL;
90
+
91
+	/* Terminate ourselves */
92
+	async_done ( async, rc );
93
+}
94
+
95
+/** Download asynchronous operations */
96
+static struct async_operations download_async_operations = {
97
+	.reap = download_reap,
98
+	.signal = {
99
+		[SIGCHLD] = download_sigchld,
100
+	},
101
+};
102
+
103
+/**
104
+ * Start download
105
+ *
106
+ * @v uri_string	URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
107
+ * @v parent		Parent asynchronous operation
108
+ * @ret data		Loaded file
109
+ * @ret len		Length of loaded file
110
+ * @ret rc		Return status code
111
+ *
112
+ * Starts download of a file to a user buffer.  The user buffer is
113
+ * allocated with umalloc().  The parent asynchronous operation will
114
+ * be notified via SIGCHLD when the download completes.  If the
115
+ * download completes successfully, the @c data and @c len fields will
116
+ * have been filled in, and the parent takes ownership of the buffer,
117
+ * which must eventually be freed with ufree().
118
+ *
119
+ * The uri_string does not need to remain persistent for the duration
120
+ * of the download; the parent may discard it as soon as
121
+ * start_download returns.
122
+ */
123
+int start_download ( const char *uri_string, struct async *parent,
124
+		     userptr_t *data, size_t *len ) {
125
+	struct download *download;
126
+	int rc;
127
+
128
+	/* Allocate and populate download structure */
129
+	download = malloc ( sizeof ( *download ) );
130
+	if ( ! download )
131
+		return -ENOMEM;
132
+	memset ( download, 0, sizeof ( *download ) );
133
+	download->data = data;
134
+	download->len = len;
135
+	async_init ( &download->async, &download_async_operations, parent );
136
+
137
+	/* Parse the URI */
138
+	download->uri = parse_uri ( uri_string );
139
+	if ( ! download->uri ) {
140
+		rc = -ENOMEM;
141
+		goto err;
142
+	}
143
+
144
+	/* Allocate an expandable buffer to hold the file */
145
+	if ( ( rc = ebuffer_alloc ( &download->buffer, 0 ) ) != 0 )
146
+		goto err;
147
+
148
+	/* Identify the download protocol */
149
+	download->protocol = find_protocol ( download->uri->scheme );
150
+	if ( ! download->protocol ) {
151
+		DBG ( "No such protocol \"%s\"\n", download->uri->scheme );
152
+		rc = -ENOTSUP;
153
+		goto err;
154
+	}
155
+
156
+	/* Start the actual download */
157
+	if ( ( rc = download->protocol->start_download ( download->uri,
158
+			       &download->buffer, &download->async ) ) != 0 ) {
159
+		DBG ( "Could not start \"%s\" download: %s\n",
160
+		      download->uri->scheme, strerror ( rc ) );
161
+		goto err;
162
+	}
163
+
164
+	return 0;
165
+
166
+ err:
167
+	async_uninit ( &download->async );
168
+	ufree ( download->buffer.addr );
169
+	free_uri ( download->uri );
170
+	free ( download );
171
+	return rc;
172
+}

+ 59
- 0
src/include/gpxe/download.h View File

@@ -0,0 +1,59 @@
1
+#ifndef _GPXE_DOWNLOAD_H
2
+#define _GPXE_DOWNLOAD_H
3
+
4
+/** @file
5
+ *
6
+ * Download protocols
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
11
+#include <gpxe/uaccess.h>
12
+#include <gpxe/async.h>
13
+#include <gpxe/buffer.h>
14
+#include <gpxe/uri.h>
15
+#include <gpxe/tables.h>
16
+
17
+/** A download protocol */
18
+struct download_protocol {
19
+	/** Protocol name (e.g. "http") */ 
20
+	const char *name;
21
+	/** Start a download via this protocol
22
+	 *
23
+	 * @v uri		Uniform Resource Identifier
24
+	 * @v buffer		Buffer into which to download file
25
+	 * @v parent		Parent asynchronous operation
26
+	 * @ret rc		Return status code
27
+	 *
28
+	 * The @c uri and @c buffer will remain persistent for the
29
+	 * duration of the asynchronous operation.
30
+	 */
31
+	int ( * start_download ) ( struct uri *uri, struct buffer *buffer,
32
+				   struct async *parent );
33
+};
34
+
35
+/** Register a download protocol */
36
+#define __download_protocol __table ( struct download_protocol, \
37
+				      download_protocols, 01 )
38
+
39
+/** A download in progress */
40
+struct download {
41
+	/** User buffer allocated for the download */
42
+	userptr_t *data;
43
+	/** Size of the download */
44
+	size_t *len;
45
+
46
+	/** URI being downloaded */
47
+	struct uri *uri;
48
+	/** Expandable buffer for this download */
49
+	struct buffer buffer;
50
+	/** Download protocol */
51
+	struct download_protocol *protocol;
52
+	/** Asynchronous operation for this download */
53
+	struct async async;
54
+};
55
+
56
+extern int start_download ( const char *uri_string, struct async *parent,
57
+			    userptr_t *data, size_t *len );
58
+
59
+#endif /* _GPXE_DOWNLOAD_H */

Loading…
Cancel
Save