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
);