These changes are the raw update to qemu-2.6.
[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  * 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.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <syslog.h>
29 #include <ipxe/iobuf.h>
30 #include <ipxe/xfer.h>
31 #include <ipxe/open.h>
32 #include <ipxe/job.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>
38
39 /** @file
40  *
41  * Image downloader
42  *
43  */
44
45 /** A downloader */
46 struct downloader {
47         /** Reference count for this object */
48         struct refcnt refcnt;
49
50         /** Job control interface */
51         struct interface job;
52         /** Data transfer interface */
53         struct interface xfer;
54
55         /** Image to contain downloaded file */
56         struct image *image;
57         /** Data transfer buffer */
58         struct xfer_buffer buffer;
59 };
60
61 /**
62  * Free downloader object
63  *
64  * @v refcnt            Downloader reference counter
65  */
66 static void downloader_free ( struct refcnt *refcnt ) {
67         struct downloader *downloader =
68                 container_of ( refcnt, struct downloader, refcnt );
69
70         image_put ( downloader->image );
71         free ( downloader );
72 }
73
74 /**
75  * Terminate download
76  *
77  * @v downloader        Downloader
78  * @v rc                Reason for termination
79  */
80 static void downloader_finished ( struct downloader *downloader, int rc ) {
81
82         /* Log download status */
83         if ( rc == 0 ) {
84                 syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
85                          downloader->image->name );
86         } else {
87                 syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
88                          downloader->image->name, strerror ( rc ) );
89         }
90
91         /* Update image length */
92         downloader->image->len = downloader->buffer.len;
93
94         /* Shut down interfaces */
95         intf_shutdown ( &downloader->xfer, rc );
96         intf_shutdown ( &downloader->job, rc );
97 }
98
99 /****************************************************************************
100  *
101  * Job control interface
102  *
103  */
104
105 /**
106  * Report progress of download job
107  *
108  * @v downloader        Downloader
109  * @v progress          Progress report to fill in
110  * @ret ongoing_rc      Ongoing job status code (if known)
111  */
112 static int downloader_progress ( struct downloader *downloader,
113                                  struct job_progress *progress ) {
114
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.
118          */
119         progress->completed = downloader->buffer.pos;
120         progress->total = downloader->buffer.len;
121
122         return 0;
123 }
124
125 /****************************************************************************
126  *
127  * Data transfer interface
128  *
129  */
130
131 /**
132  * Handle received data
133  *
134  * @v downloader        Downloader
135  * @v iobuf             Datagram I/O buffer
136  * @v meta              Data transfer metadata
137  * @ret rc              Return status code
138  */
139 static int downloader_xfer_deliver ( struct downloader *downloader,
140                                      struct io_buffer *iobuf,
141                                      struct xfer_metadata *meta ) {
142         int rc;
143
144         /* Add data to buffer */
145         if ( ( rc = xferbuf_deliver ( &downloader->buffer, iob_disown ( iobuf ),
146                                       meta ) ) != 0 )
147                 goto err_deliver;
148
149         return 0;
150
151  err_deliver:
152         downloader_finished ( downloader, rc );
153         return rc;
154 }
155
156 /**
157  * Get underlying data transfer buffer
158  *
159  * @v downloader        Downloader
160  * @ret xferbuf         Data transfer buffer, or NULL on error
161  */
162 static struct xfer_buffer *
163 downloader_xfer_buffer ( struct downloader *downloader ) {
164
165         /* Provide direct access to underlying data transfer buffer */
166         return &downloader->buffer;
167 }
168
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 ),
174 };
175
176 /** Downloader data transfer interface descriptor */
177 static struct interface_descriptor downloader_xfer_desc =
178         INTF_DESC ( struct downloader, xfer, downloader_xfer_operations );
179
180 /****************************************************************************
181  *
182  * Job control interface
183  *
184  */
185
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 ),
190 };
191
192 /** Downloader job control interface descriptor */
193 static struct interface_descriptor downloader_job_desc =
194         INTF_DESC ( struct downloader, job, downloader_job_op );
195
196 /****************************************************************************
197  *
198  * Instantiator
199  *
200  */
201
202 /**
203  * Instantiate a downloader
204  *
205  * @v job               Job control interface
206  * @v image             Image to fill with downloaded file
207  * @ret rc              Return status code
208  *
209  * Instantiates a downloader object to download the content of the
210  * specified image from its URI.
211  */
212 int create_downloader ( struct interface *job, struct image *image ) {
213         struct downloader *downloader;
214         int rc;
215
216         /* Allocate and initialise structure */
217         downloader = zalloc ( sizeof ( *downloader ) );
218         if ( ! downloader )
219                 return -ENOMEM;
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 );
227
228         /* Instantiate child objects and attach to our interfaces */
229         if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 )
230                 goto err;
231
232         /* Attach parent interface, mortalise self, and return */
233         intf_plug_plug ( &downloader->job, job );
234         ref_put ( &downloader->refcnt );
235         return 0;
236
237  err:
238         downloader_finished ( downloader, rc );
239         ref_put ( &downloader->refcnt );
240         return rc;
241 }