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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
29 #include <ipxe/iobuf.h>
30 #include <ipxe/xfer.h>
31 #include <ipxe/open.h>
33 #include <ipxe/uaccess.h>
34 #include <ipxe/umalloc.h>
35 #include <ipxe/image.h>
36 #include <ipxe/xferbuf.h>
37 #include <ipxe/downloader.h>
47 /** Reference count for this object */
50 /** Job control interface */
52 /** Data transfer interface */
53 struct interface xfer;
55 /** Image to contain downloaded file */
57 /** Data transfer buffer */
58 struct xfer_buffer buffer;
62 * Free downloader object
64 * @v refcnt Downloader reference counter
66 static void downloader_free ( struct refcnt *refcnt ) {
67 struct downloader *downloader =
68 container_of ( refcnt, struct downloader, refcnt );
70 image_put ( downloader->image );
77 * @v downloader Downloader
78 * @v rc Reason for termination
80 static void downloader_finished ( struct downloader *downloader, int rc ) {
82 /* Log download status */
84 syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
85 downloader->image->name );
87 syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
88 downloader->image->name, strerror ( rc ) );
91 /* Update image length */
92 downloader->image->len = downloader->buffer.len;
94 /* Shut down interfaces */
95 intf_shutdown ( &downloader->xfer, rc );
96 intf_shutdown ( &downloader->job, rc );
99 /****************************************************************************
101 * Job control interface
106 * Report progress of download job
108 * @v downloader Downloader
109 * @v progress Progress report to fill in
110 * @ret ongoing_rc Ongoing job status code (if known)
112 static int downloader_progress ( struct downloader *downloader,
113 struct job_progress *progress ) {
115 /* This is not entirely accurate, since downloaded data may
116 * arrive out of order (e.g. with multicast protocols), but
117 * it's a reasonable first approximation.
119 progress->completed = downloader->buffer.pos;
120 progress->total = downloader->buffer.len;
125 /****************************************************************************
127 * Data transfer interface
132 * Handle received data
134 * @v downloader Downloader
135 * @v iobuf Datagram I/O buffer
136 * @v meta Data transfer metadata
137 * @ret rc Return status code
139 static int downloader_xfer_deliver ( struct downloader *downloader,
140 struct io_buffer *iobuf,
141 struct xfer_metadata *meta ) {
144 /* Add data to buffer */
145 if ( ( rc = xferbuf_deliver ( &downloader->buffer, iob_disown ( iobuf ),
152 downloader_finished ( downloader, rc );
157 * Get underlying data transfer buffer
159 * @v downloader Downloader
160 * @ret xferbuf Data transfer buffer, or NULL on error
162 static struct xfer_buffer *
163 downloader_xfer_buffer ( struct downloader *downloader ) {
165 /* Provide direct access to underlying data transfer buffer */
166 return &downloader->buffer;
169 /** Downloader data transfer interface operations */
170 static struct interface_operation downloader_xfer_operations[] = {
171 INTF_OP ( xfer_deliver, struct downloader *, downloader_xfer_deliver ),
172 INTF_OP ( xfer_buffer, struct downloader *, downloader_xfer_buffer ),
173 INTF_OP ( intf_close, struct downloader *, downloader_finished ),
176 /** Downloader data transfer interface descriptor */
177 static struct interface_descriptor downloader_xfer_desc =
178 INTF_DESC ( struct downloader, xfer, downloader_xfer_operations );
180 /****************************************************************************
182 * Job control interface
186 /** Downloader job control interface operations */
187 static struct interface_operation downloader_job_op[] = {
188 INTF_OP ( job_progress, struct downloader *, downloader_progress ),
189 INTF_OP ( intf_close, struct downloader *, downloader_finished ),
192 /** Downloader job control interface descriptor */
193 static struct interface_descriptor downloader_job_desc =
194 INTF_DESC ( struct downloader, job, downloader_job_op );
196 /****************************************************************************
203 * Instantiate a downloader
205 * @v job Job control interface
206 * @v image Image to fill with downloaded file
207 * @ret rc Return status code
209 * Instantiates a downloader object to download the content of the
210 * specified image from its URI.
212 int create_downloader ( struct interface *job, struct image *image ) {
213 struct downloader *downloader;
216 /* Allocate and initialise structure */
217 downloader = zalloc ( sizeof ( *downloader ) );
220 ref_init ( &downloader->refcnt, downloader_free );
221 intf_init ( &downloader->job, &downloader_job_desc,
222 &downloader->refcnt );
223 intf_init ( &downloader->xfer, &downloader_xfer_desc,
224 &downloader->refcnt );
225 downloader->image = image_get ( image );
226 xferbuf_umalloc_init ( &downloader->buffer, &image->data );
228 /* Instantiate child objects and attach to our interfaces */
229 if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 )
232 /* Attach parent interface, mortalise self, and return */
233 intf_plug_plug ( &downloader->job, job );
234 ref_put ( &downloader->refcnt );
238 downloader_finished ( downloader, rc );
239 ref_put ( &downloader->refcnt );