Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / downloader.c
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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <syslog.h>
25 #include <ipxe/iobuf.h>
26 #include <ipxe/xfer.h>
27 #include <ipxe/open.h>
28 #include <ipxe/job.h>
29 #include <ipxe/uaccess.h>
30 #include <ipxe/umalloc.h>
31 #include <ipxe/image.h>
32 #include <ipxe/profile.h>
33 #include <ipxe/downloader.h>
34
35 /** @file
36  *
37  * Image downloader
38  *
39  */
40
41 /** Receive profiler */
42 static struct profiler downloader_rx_profiler __profiler =
43         { .name = "downloader.rx" };
44
45 /** Data copy profiler */
46 static struct profiler downloader_copy_profiler __profiler =
47         { .name = "downloader.copy" };
48
49 /** A downloader */
50 struct downloader {
51         /** Reference count for this object */
52         struct refcnt refcnt;
53
54         /** Job control interface */
55         struct interface job;
56         /** Data transfer interface */
57         struct interface xfer;
58
59         /** Image to contain downloaded file */
60         struct image *image;
61         /** Current position within image buffer */
62         size_t pos;
63 };
64
65 /**
66  * Free downloader object
67  *
68  * @v refcnt            Downloader reference counter
69  */
70 static void downloader_free ( struct refcnt *refcnt ) {
71         struct downloader *downloader =
72                 container_of ( refcnt, struct downloader, refcnt );
73
74         image_put ( downloader->image );
75         free ( downloader );
76 }
77
78 /**
79  * Terminate download
80  *
81  * @v downloader        Downloader
82  * @v rc                Reason for termination
83  */
84 static void downloader_finished ( struct downloader *downloader, int rc ) {
85
86         /* Log download status */
87         if ( rc == 0 ) {
88                 syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
89                          downloader->image->name );
90         } else {
91                 syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
92                          downloader->image->name, strerror ( rc ) );
93         }
94
95         /* Shut down interfaces */
96         intf_shutdown ( &downloader->xfer, rc );
97         intf_shutdown ( &downloader->job, rc );
98 }
99
100 /**
101  * Ensure that download buffer is large enough for the specified size
102  *
103  * @v downloader        Downloader
104  * @v len               Required minimum size
105  * @ret rc              Return status code
106  */
107 static int downloader_ensure_size ( struct downloader *downloader,
108                                     size_t len ) {
109         userptr_t new_buffer;
110
111         /* If buffer is already large enough, do nothing */
112         if ( len <= downloader->image->len )
113                 return 0;
114
115         DBGC ( downloader, "Downloader %p extending to %zd bytes\n",
116                downloader, len );
117
118         /* Extend buffer */
119         new_buffer = urealloc ( downloader->image->data, len );
120         if ( ! new_buffer ) {
121                 DBGC ( downloader, "Downloader %p could not extend buffer to "
122                        "%zd bytes\n", downloader, len );
123                 return -ENOSPC;
124         }
125         downloader->image->data = new_buffer;
126         downloader->image->len = len;
127
128         return 0;
129 }
130
131 /****************************************************************************
132  *
133  * Job control interface
134  *
135  */
136
137 /**
138  * Report progress of download job
139  *
140  * @v downloader        Downloader
141  * @v progress          Progress report to fill in
142  * @ret ongoing_rc      Ongoing job status code (if known)
143  */
144 static int downloader_progress ( struct downloader *downloader,
145                                  struct job_progress *progress ) {
146
147         /* This is not entirely accurate, since downloaded data may
148          * arrive out of order (e.g. with multicast protocols), but
149          * it's a reasonable first approximation.
150          */
151         progress->completed = downloader->pos;
152         progress->total = downloader->image->len;
153
154         return 0;
155 }
156
157 /****************************************************************************
158  *
159  * Data transfer interface
160  *
161  */
162
163 /**
164  * Handle received data
165  *
166  * @v downloader        Downloader
167  * @v iobuf             Datagram I/O buffer
168  * @v meta              Data transfer metadata
169  * @ret rc              Return status code
170  */
171 static int downloader_xfer_deliver ( struct downloader *downloader,
172                                      struct io_buffer *iobuf,
173                                      struct xfer_metadata *meta ) {
174         size_t len;
175         size_t max;
176         int rc;
177
178         /* Start profiling */
179         profile_start ( &downloader_rx_profiler );
180
181         /* Calculate new buffer position */
182         if ( meta->flags & XFER_FL_ABS_OFFSET )
183                 downloader->pos = 0;
184         downloader->pos += meta->offset;
185
186         /* Ensure that we have enough buffer space for this data */
187         len = iob_len ( iobuf );
188         max = ( downloader->pos + len );
189         if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
190                 goto done;
191
192         /* Copy data to buffer */
193         profile_start ( &downloader_copy_profiler );
194         copy_to_user ( downloader->image->data, downloader->pos,
195                        iobuf->data, len );
196         profile_stop ( &downloader_copy_profiler );
197
198         /* Update current buffer position */
199         downloader->pos += len;
200
201  done:
202         free_iob ( iobuf );
203         if ( rc != 0 )
204                 downloader_finished ( downloader, rc );
205         profile_stop ( &downloader_rx_profiler );
206         return rc;
207 }
208
209 /** Downloader data transfer interface operations */
210 static struct interface_operation downloader_xfer_operations[] = {
211         INTF_OP ( xfer_deliver, struct downloader *, downloader_xfer_deliver ),
212         INTF_OP ( intf_close, struct downloader *, downloader_finished ),
213 };
214
215 /** Downloader data transfer interface descriptor */
216 static struct interface_descriptor downloader_xfer_desc =
217         INTF_DESC ( struct downloader, xfer, downloader_xfer_operations );
218
219 /****************************************************************************
220  *
221  * Job control interface
222  *
223  */
224
225 /** Downloader job control interface operations */
226 static struct interface_operation downloader_job_op[] = {
227         INTF_OP ( job_progress, struct downloader *, downloader_progress ),
228         INTF_OP ( intf_close, struct downloader *, downloader_finished ),
229 };
230
231 /** Downloader job control interface descriptor */
232 static struct interface_descriptor downloader_job_desc =
233         INTF_DESC ( struct downloader, job, downloader_job_op );
234
235 /****************************************************************************
236  *
237  * Instantiator
238  *
239  */
240
241 /**
242  * Instantiate a downloader
243  *
244  * @v job               Job control interface
245  * @v image             Image to fill with downloaded file
246  * @ret rc              Return status code
247  *
248  * Instantiates a downloader object to download the content of the
249  * specified image from its URI.
250  */
251 int create_downloader ( struct interface *job, struct image *image ) {
252         struct downloader *downloader;
253         int rc;
254
255         /* Allocate and initialise structure */
256         downloader = zalloc ( sizeof ( *downloader ) );
257         if ( ! downloader )
258                 return -ENOMEM;
259         ref_init ( &downloader->refcnt, downloader_free );
260         intf_init ( &downloader->job, &downloader_job_desc,
261                     &downloader->refcnt );
262         intf_init ( &downloader->xfer, &downloader_xfer_desc,
263                     &downloader->refcnt );
264         downloader->image = image_get ( image );
265
266         /* Instantiate child objects and attach to our interfaces */
267         if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 )
268                 goto err;
269
270         /* Attach parent interface, mortalise self, and return */
271         intf_plug_plug ( &downloader->job, job );
272         ref_put ( &downloader->refcnt );
273         return 0;
274
275  err:
276         downloader_finished ( downloader, rc );
277         ref_put ( &downloader->refcnt );
278         return rc;
279 }