Bläddra i källkod

Initial sketch for a downloader object

tags/v0.9.3
Michael Brown 17 år sedan
förälder
incheckning
53da1f1402
2 ändrade filer med 293 tillägg och 0 borttagningar
  1. 276
    0
      src/core/downloader.c
  2. 17
    0
      src/include/gpxe/downloader.h

+ 276
- 0
src/core/downloader.c Visa fil

@@ -0,0 +1,276 @@
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
+#include <stdlib.h>
20
+#include <errno.h>
21
+#include <gpxe/xfer.h>
22
+#include <gpxe/open.h>
23
+#include <gpxe/job.h>
24
+#include <gpxe/uaccess.h>
25
+#include <gpxe/umalloc.h>
26
+#include <gpxe/image.h>
27
+#include <gpxe/downloader.h>
28
+
29
+/** @file
30
+ *
31
+ * Image downloader
32
+ *
33
+ */
34
+
35
+/** A downloader */
36
+struct downloader {
37
+	/** Reference count for this object */
38
+	struct refcnt refcnt;
39
+
40
+	/** Job control interface */
41
+	struct job_interface job;
42
+	/** Data transfer interface */
43
+	struct xfer_interface xfer;
44
+
45
+	/** Image to contain downloaded file */
46
+	struct image *image;
47
+	/** Current position within image buffer */
48
+	size_t pos;
49
+	/** Image registration routine */
50
+	int ( * register_image ) ( struct image *image );
51
+};
52
+
53
+/**
54
+ * Terminate download
55
+ *
56
+ * @v downloader	Downloader
57
+ * @v rc		Reason for termination
58
+ */
59
+static void downloader_finished ( struct downloader *downloader, int rc ) {
60
+
61
+	/* Block further incoming messages */
62
+	job_nullify ( &downloader->job );
63
+	xfer_nullify ( &downloader->xfer );
64
+
65
+	/* Free resources and close interfaces */
66
+	image_put ( downloader->image );
67
+	xfer_close ( &downloader->xfer, rc );
68
+	job_done ( &downloader->job, rc );
69
+
70
+	/* Drop reference to self */
71
+	ref_put ( &downloader->refcnt );
72
+}
73
+
74
+/**
75
+ * Ensure that download buffer is large enough for the specified size
76
+ *
77
+ * @v downloader	Downloader
78
+ * @v len		Required minimum size
79
+ * @ret rc		Return status code
80
+ */
81
+static int downloader_ensure_size ( struct downloader *downloader,
82
+				    size_t len ) {
83
+	userptr_t new_buffer;
84
+
85
+	/* If buffer is already large enough, do nothing */
86
+	if ( len <= downloader->image->len )
87
+		return 0;
88
+
89
+	/* Extend buffer */
90
+	new_buffer = urealloc ( downloader->image->data, len );
91
+	if ( ! new_buffer ) {
92
+		DBGC ( downloader, "Downloader %p could not extend buffer to "
93
+		       "%zd bytes\n", downloader, len );
94
+		return -ENOBUFS;
95
+	}
96
+	downloader->image->data = new_buffer;
97
+	downloader->image->len = len;
98
+
99
+	return 0;
100
+}
101
+
102
+/****************************************************************************
103
+ *
104
+ * Job control interface
105
+ *
106
+ */
107
+
108
+/**
109
+ * Handle start() event received via job control interface
110
+ *
111
+ * @v job		Downloader job control interface
112
+ */
113
+static void downloader_job_start ( struct job_interface *job ) {
114
+	struct downloader *downloader = 
115
+		container_of ( job, struct downloader, job );
116
+
117
+	/* Start data transfer */
118
+	xfer_start ( &downloader->xfer );
119
+}
120
+
121
+/**
122
+ * Handle kill() event received via job control interface
123
+ *
124
+ * @v job		Downloader job control interface
125
+ */
126
+static void downloader_job_kill ( struct job_interface *job ) {
127
+	struct downloader *downloader = 
128
+		container_of ( job, struct downloader, job );
129
+
130
+	/* Terminate download */
131
+	downloader_finished ( downloader, -ECANCELED );
132
+}
133
+
134
+/** Downloader job control interface operations */
135
+static struct job_interface_operations downloader_job_operations = {
136
+	.start		= downloader_job_start,
137
+	.done		= ignore_job_done,
138
+	.kill		= downloader_job_kill,
139
+	.progress	= ignore_job_progress,
140
+};
141
+
142
+/****************************************************************************
143
+ *
144
+ * Data transfer interface
145
+ *
146
+ */
147
+
148
+/**
149
+ * Handle seek() event received via data transfer interface
150
+ *
151
+ * @v xfer		Downloader data transfer interface
152
+ * @v pos		New position
153
+ * @ret rc		Return status code
154
+ */
155
+static int downloader_xfer_seek ( struct xfer_interface *xfer, size_t pos ) {
156
+	struct downloader *downloader =
157
+		container_of ( xfer, struct downloader, xfer );
158
+	int rc;
159
+
160
+	/* Ensure that we have enough buffer space for this buffer position */
161
+	if ( ( rc = downloader_ensure_size ( downloader, pos ) ) != 0 )
162
+		return rc;
163
+
164
+	/* Update current buffer position */
165
+	downloader->pos = pos;
166
+
167
+	return 0;
168
+}
169
+
170
+/**
171
+ * Handle deliver_raw() event received via data transfer interface
172
+ *
173
+ * @v xfer		Downloader data transfer interface
174
+ * @v data		Data buffer
175
+ * @v len		Length of data buffer
176
+ * @ret rc		Return status code
177
+ */
178
+static int downloader_xfer_deliver_raw ( struct xfer_interface *xfer,
179
+					 const void *data, size_t len ) {
180
+	struct downloader *downloader =
181
+		container_of ( xfer, struct downloader, xfer );
182
+	size_t max;
183
+	int rc;
184
+
185
+	/* Ensure that we have enough buffer space for this data */
186
+	max = ( downloader->pos + len );
187
+	if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
188
+		return rc;
189
+
190
+	/* Copy data to buffer */
191
+	copy_to_user ( downloader->image->data, downloader->pos, data, len );
192
+
193
+	/* Update current buffer position */
194
+	downloader->pos += len;
195
+
196
+	return 0;
197
+}
198
+
199
+/**
200
+ * Handle close() event received via data transfer interface
201
+ *
202
+ * @v xfer		Downloader data transfer interface
203
+ * @v rc		Reason for close
204
+ */
205
+static void downloader_xfer_close ( struct xfer_interface *xfer, int rc ) {
206
+	struct downloader *downloader =
207
+		container_of ( xfer, struct downloader, xfer );
208
+
209
+	/* Register image if download was successful */
210
+	if ( rc == 0 )
211
+		rc = downloader->register_image ( downloader->image );
212
+
213
+	/* Terminate download */
214
+	downloader_finished ( downloader, rc );
215
+}
216
+
217
+/** Downloader data transfer interface operations */
218
+static struct xfer_interface_operations downloader_xfer_operations = {
219
+	.start		= ignore_xfer_start,
220
+	.close		= downloader_xfer_close,
221
+	.vredirect	= default_xfer_vredirect,
222
+	.seek		= downloader_xfer_seek,
223
+	.deliver	= xfer_deliver_as_raw,
224
+	.deliver_raw	= downloader_xfer_deliver_raw,
225
+};
226
+
227
+/****************************************************************************
228
+ *
229
+ * Instantiator
230
+ *
231
+ */
232
+
233
+/**
234
+ * Instantiate a downloader
235
+ *
236
+ * @v job		Job control interface
237
+ * @v uri_string	URI string
238
+ * @v image		Image to fill with downloaded file
239
+ * @v register_image	Image registration routine
240
+ * @ret rc		Return status code
241
+ *
242
+ * Instantiates a downloader object to download the specified URI into
243
+ * the specified image object.  If the download is successful, the
244
+ * image registration routine @c register_image() will be called.
245
+ */
246
+int create_downloader ( struct job_interface *job, const char *uri_string,
247
+			struct image *image,
248
+			int ( * register_image ) ( struct image *image ) ) {
249
+	struct downloader *downloader;
250
+	int rc;
251
+
252
+	/* Allocate and initialise structure */
253
+	downloader = malloc ( sizeof ( *downloader ) );
254
+	if ( ! downloader )
255
+		return -ENOMEM;
256
+	memset ( downloader, 0, sizeof ( *downloader ) );
257
+	job_init ( &downloader->job, &downloader_job_operations,
258
+		   &downloader->refcnt );
259
+	xfer_init ( &downloader->xfer, &downloader_xfer_operations,
260
+		    &downloader->refcnt );
261
+	downloader->image = image_get ( image );
262
+	downloader->register_image = register_image;
263
+
264
+	/* Instantiate child objects and attach to our interfaces */
265
+	if ( ( rc = open ( &downloader->xfer, LOCATION_URI,
266
+			   uri_string ) ) != 0 )
267
+		goto err;
268
+
269
+	/* Attach parent interface and return */
270
+	job_plug_plug ( &downloader->job, job );
271
+	return 0;
272
+
273
+ err:
274
+	downloader_finished ( downloader, rc );
275
+	return rc;
276
+}

+ 17
- 0
src/include/gpxe/downloader.h Visa fil

@@ -0,0 +1,17 @@
1
+#ifndef _GPXE_DOWNLOADER_H
2
+#define _GPXE_DOWNLOADER_H
3
+
4
+/** @file
5
+ *
6
+ * Image downloader
7
+ *
8
+ */
9
+
10
+struct job_interface;
11
+struct image;
12
+
13
+extern int create_downloader ( struct job_interface *job,
14
+			       const char *uri_string, struct image *image,
15
+			       int ( * register_image ) ( struct image * ) );
16
+
17
+#endif /* _GPXE_DOWNLOADER_H */

Laddar…
Avbryt
Spara