xref: /openbmc/qemu/block/curl.c (revision 228aa992)
1 /*
2  * QEMU Block driver for CURL images
3  *
4  * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "qemu-common.h"
25 #include "block/block_int.h"
26 #include "qapi/qmp/qbool.h"
27 #include <curl/curl.h>
28 
29 // #define DEBUG_CURL
30 // #define DEBUG_VERBOSE
31 
32 #ifdef DEBUG_CURL
33 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
34 #else
35 #define DPRINTF(fmt, ...) do { } while (0)
36 #endif
37 
38 #if LIBCURL_VERSION_NUM >= 0x071000
39 /* The multi interface timer callback was introduced in 7.16.0 */
40 #define NEED_CURL_TIMER_CALLBACK
41 #define HAVE_SOCKET_ACTION
42 #endif
43 
44 #ifndef HAVE_SOCKET_ACTION
45 /* If curl_multi_socket_action isn't available, define it statically here in
46  * terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
47  * less efficient but still safe. */
48 static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
49                                             curl_socket_t sockfd,
50                                             int ev_bitmask,
51                                             int *running_handles)
52 {
53     return curl_multi_socket(multi_handle, sockfd, running_handles);
54 }
55 #define curl_multi_socket_action __curl_multi_socket_action
56 #endif
57 
58 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
59                    CURLPROTO_FTP | CURLPROTO_FTPS | \
60                    CURLPROTO_TFTP)
61 
62 #define CURL_NUM_STATES 8
63 #define CURL_NUM_ACB    8
64 #define SECTOR_SIZE     512
65 #define READ_AHEAD_DEFAULT (256 * 1024)
66 #define CURL_TIMEOUT_DEFAULT 5
67 #define CURL_TIMEOUT_MAX 10000
68 
69 #define FIND_RET_NONE   0
70 #define FIND_RET_OK     1
71 #define FIND_RET_WAIT   2
72 
73 #define CURL_BLOCK_OPT_URL       "url"
74 #define CURL_BLOCK_OPT_READAHEAD "readahead"
75 #define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
76 #define CURL_BLOCK_OPT_TIMEOUT "timeout"
77 #define CURL_BLOCK_OPT_COOKIE    "cookie"
78 
79 struct BDRVCURLState;
80 
81 typedef struct CURLAIOCB {
82     BlockAIOCB common;
83     QEMUBH *bh;
84     QEMUIOVector *qiov;
85 
86     int64_t sector_num;
87     int nb_sectors;
88 
89     size_t start;
90     size_t end;
91 } CURLAIOCB;
92 
93 typedef struct CURLState
94 {
95     struct BDRVCURLState *s;
96     CURLAIOCB *acb[CURL_NUM_ACB];
97     CURL *curl;
98     curl_socket_t sock_fd;
99     char *orig_buf;
100     size_t buf_start;
101     size_t buf_off;
102     size_t buf_len;
103     char range[128];
104     char errmsg[CURL_ERROR_SIZE];
105     char in_use;
106 } CURLState;
107 
108 typedef struct BDRVCURLState {
109     CURLM *multi;
110     QEMUTimer timer;
111     size_t len;
112     CURLState states[CURL_NUM_STATES];
113     char *url;
114     size_t readahead_size;
115     bool sslverify;
116     uint64_t timeout;
117     char *cookie;
118     bool accept_range;
119     AioContext *aio_context;
120 } BDRVCURLState;
121 
122 static void curl_clean_state(CURLState *s);
123 static void curl_multi_do(void *arg);
124 static void curl_multi_read(void *arg);
125 
126 #ifdef NEED_CURL_TIMER_CALLBACK
127 static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
128 {
129     BDRVCURLState *s = opaque;
130 
131     DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
132     if (timeout_ms == -1) {
133         timer_del(&s->timer);
134     } else {
135         int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
136         timer_mod(&s->timer,
137                   qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
138     }
139     return 0;
140 }
141 #endif
142 
143 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
144                         void *userp, void *sp)
145 {
146     BDRVCURLState *s;
147     CURLState *state = NULL;
148     curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
149     state->sock_fd = fd;
150     s = state->s;
151 
152     DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
153     switch (action) {
154         case CURL_POLL_IN:
155             aio_set_fd_handler(s->aio_context, fd, curl_multi_read,
156                                NULL, state);
157             break;
158         case CURL_POLL_OUT:
159             aio_set_fd_handler(s->aio_context, fd, NULL, curl_multi_do, state);
160             break;
161         case CURL_POLL_INOUT:
162             aio_set_fd_handler(s->aio_context, fd, curl_multi_read,
163                                curl_multi_do, state);
164             break;
165         case CURL_POLL_REMOVE:
166             aio_set_fd_handler(s->aio_context, fd, NULL, NULL, NULL);
167             break;
168     }
169 
170     return 0;
171 }
172 
173 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
174 {
175     BDRVCURLState *s = opaque;
176     size_t realsize = size * nmemb;
177     const char *accept_line = "Accept-Ranges: bytes";
178 
179     if (realsize >= strlen(accept_line)
180         && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
181         s->accept_range = true;
182     }
183 
184     return realsize;
185 }
186 
187 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
188 {
189     CURLState *s = ((CURLState*)opaque);
190     size_t realsize = size * nmemb;
191     int i;
192 
193     DPRINTF("CURL: Just reading %zd bytes\n", realsize);
194 
195     if (!s || !s->orig_buf)
196         return 0;
197 
198     if (s->buf_off >= s->buf_len) {
199         /* buffer full, read nothing */
200         return 0;
201     }
202     realsize = MIN(realsize, s->buf_len - s->buf_off);
203     memcpy(s->orig_buf + s->buf_off, ptr, realsize);
204     s->buf_off += realsize;
205 
206     for(i=0; i<CURL_NUM_ACB; i++) {
207         CURLAIOCB *acb = s->acb[i];
208 
209         if (!acb)
210             continue;
211 
212         if ((s->buf_off >= acb->end)) {
213             qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
214                                 acb->end - acb->start);
215             acb->common.cb(acb->common.opaque, 0);
216             qemu_aio_unref(acb);
217             s->acb[i] = NULL;
218         }
219     }
220 
221     return realsize;
222 }
223 
224 static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
225                          CURLAIOCB *acb)
226 {
227     int i;
228     size_t end = start + len;
229 
230     for (i=0; i<CURL_NUM_STATES; i++) {
231         CURLState *state = &s->states[i];
232         size_t buf_end = (state->buf_start + state->buf_off);
233         size_t buf_fend = (state->buf_start + state->buf_len);
234 
235         if (!state->orig_buf)
236             continue;
237         if (!state->buf_off)
238             continue;
239 
240         // Does the existing buffer cover our section?
241         if ((start >= state->buf_start) &&
242             (start <= buf_end) &&
243             (end >= state->buf_start) &&
244             (end <= buf_end))
245         {
246             char *buf = state->orig_buf + (start - state->buf_start);
247 
248             qemu_iovec_from_buf(acb->qiov, 0, buf, len);
249             acb->common.cb(acb->common.opaque, 0);
250 
251             return FIND_RET_OK;
252         }
253 
254         // Wait for unfinished chunks
255         if (state->in_use &&
256             (start >= state->buf_start) &&
257             (start <= buf_fend) &&
258             (end >= state->buf_start) &&
259             (end <= buf_fend))
260         {
261             int j;
262 
263             acb->start = start - state->buf_start;
264             acb->end = acb->start + len;
265 
266             for (j=0; j<CURL_NUM_ACB; j++) {
267                 if (!state->acb[j]) {
268                     state->acb[j] = acb;
269                     return FIND_RET_WAIT;
270                 }
271             }
272         }
273     }
274 
275     return FIND_RET_NONE;
276 }
277 
278 static void curl_multi_check_completion(BDRVCURLState *s)
279 {
280     int msgs_in_queue;
281 
282     /* Try to find done transfers, so we can free the easy
283      * handle again. */
284     for (;;) {
285         CURLMsg *msg;
286         msg = curl_multi_info_read(s->multi, &msgs_in_queue);
287 
288         /* Quit when there are no more completions */
289         if (!msg)
290             break;
291 
292         if (msg->msg == CURLMSG_DONE) {
293             CURLState *state = NULL;
294             curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
295                               (char **)&state);
296 
297             /* ACBs for successful messages get completed in curl_read_cb */
298             if (msg->data.result != CURLE_OK) {
299                 int i;
300                 for (i = 0; i < CURL_NUM_ACB; i++) {
301                     CURLAIOCB *acb = state->acb[i];
302 
303                     if (acb == NULL) {
304                         continue;
305                     }
306 
307                     acb->common.cb(acb->common.opaque, -EIO);
308                     qemu_aio_unref(acb);
309                     state->acb[i] = NULL;
310                 }
311             }
312 
313             curl_clean_state(state);
314             break;
315         }
316     }
317 }
318 
319 static void curl_multi_do(void *arg)
320 {
321     CURLState *s = (CURLState *)arg;
322     int running;
323     int r;
324 
325     if (!s->s->multi) {
326         return;
327     }
328 
329     do {
330         r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
331     } while(r == CURLM_CALL_MULTI_PERFORM);
332 
333 }
334 
335 static void curl_multi_read(void *arg)
336 {
337     CURLState *s = (CURLState *)arg;
338 
339     curl_multi_do(arg);
340     curl_multi_check_completion(s->s);
341 }
342 
343 static void curl_multi_timeout_do(void *arg)
344 {
345 #ifdef NEED_CURL_TIMER_CALLBACK
346     BDRVCURLState *s = (BDRVCURLState *)arg;
347     int running;
348 
349     if (!s->multi) {
350         return;
351     }
352 
353     curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
354 
355     curl_multi_check_completion(s);
356 #else
357     abort();
358 #endif
359 }
360 
361 static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
362 {
363     CURLState *state = NULL;
364     int i, j;
365 
366     do {
367         for (i=0; i<CURL_NUM_STATES; i++) {
368             for (j=0; j<CURL_NUM_ACB; j++)
369                 if (s->states[i].acb[j])
370                     continue;
371             if (s->states[i].in_use)
372                 continue;
373 
374             state = &s->states[i];
375             state->in_use = 1;
376             break;
377         }
378         if (!state) {
379             aio_poll(bdrv_get_aio_context(bs), true);
380         }
381     } while(!state);
382 
383     if (!state->curl) {
384         state->curl = curl_easy_init();
385         if (!state->curl) {
386             return NULL;
387         }
388         curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
389         curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
390                          (long) s->sslverify);
391         if (s->cookie) {
392             curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie);
393         }
394         curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout);
395         curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
396                          (void *)curl_read_cb);
397         curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
398         curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
399         curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
400         curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
401         curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
402         curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
403         curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
404 
405         /* Restrict supported protocols to avoid security issues in the more
406          * obscure protocols.  For example, do not allow POP3/SMTP/IMAP see
407          * CVE-2013-0249.
408          *
409          * Restricting protocols is only supported from 7.19.4 upwards.
410          */
411 #if LIBCURL_VERSION_NUM >= 0x071304
412         curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
413         curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
414 #endif
415 
416 #ifdef DEBUG_VERBOSE
417         curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
418 #endif
419     }
420 
421     state->s = s;
422 
423     return state;
424 }
425 
426 static void curl_clean_state(CURLState *s)
427 {
428     if (s->s->multi)
429         curl_multi_remove_handle(s->s->multi, s->curl);
430     s->in_use = 0;
431 }
432 
433 static void curl_parse_filename(const char *filename, QDict *options,
434                                 Error **errp)
435 {
436     qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
437 }
438 
439 static void curl_detach_aio_context(BlockDriverState *bs)
440 {
441     BDRVCURLState *s = bs->opaque;
442     int i;
443 
444     for (i = 0; i < CURL_NUM_STATES; i++) {
445         if (s->states[i].in_use) {
446             curl_clean_state(&s->states[i]);
447         }
448         if (s->states[i].curl) {
449             curl_easy_cleanup(s->states[i].curl);
450             s->states[i].curl = NULL;
451         }
452         g_free(s->states[i].orig_buf);
453         s->states[i].orig_buf = NULL;
454     }
455     if (s->multi) {
456         curl_multi_cleanup(s->multi);
457         s->multi = NULL;
458     }
459 
460     timer_del(&s->timer);
461 }
462 
463 static void curl_attach_aio_context(BlockDriverState *bs,
464                                     AioContext *new_context)
465 {
466     BDRVCURLState *s = bs->opaque;
467 
468     aio_timer_init(new_context, &s->timer,
469                    QEMU_CLOCK_REALTIME, SCALE_NS,
470                    curl_multi_timeout_do, s);
471 
472     assert(!s->multi);
473     s->multi = curl_multi_init();
474     s->aio_context = new_context;
475     curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
476 #ifdef NEED_CURL_TIMER_CALLBACK
477     curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
478     curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
479 #endif
480 }
481 
482 static QemuOptsList runtime_opts = {
483     .name = "curl",
484     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
485     .desc = {
486         {
487             .name = CURL_BLOCK_OPT_URL,
488             .type = QEMU_OPT_STRING,
489             .help = "URL to open",
490         },
491         {
492             .name = CURL_BLOCK_OPT_READAHEAD,
493             .type = QEMU_OPT_SIZE,
494             .help = "Readahead size",
495         },
496         {
497             .name = CURL_BLOCK_OPT_SSLVERIFY,
498             .type = QEMU_OPT_BOOL,
499             .help = "Verify SSL certificate"
500         },
501         {
502             .name = CURL_BLOCK_OPT_TIMEOUT,
503             .type = QEMU_OPT_NUMBER,
504             .help = "Curl timeout"
505         },
506         {
507             .name = CURL_BLOCK_OPT_COOKIE,
508             .type = QEMU_OPT_STRING,
509             .help = "Pass the cookie or list of cookies with each request"
510         },
511         { /* end of list */ }
512     },
513 };
514 
515 static int curl_open(BlockDriverState *bs, QDict *options, int flags,
516                      Error **errp)
517 {
518     BDRVCURLState *s = bs->opaque;
519     CURLState *state = NULL;
520     QemuOpts *opts;
521     Error *local_err = NULL;
522     const char *file;
523     const char *cookie;
524     double d;
525 
526     static int inited = 0;
527 
528     if (flags & BDRV_O_RDWR) {
529         error_setg(errp, "curl block device does not support writes");
530         return -EROFS;
531     }
532 
533     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
534     qemu_opts_absorb_qdict(opts, options, &local_err);
535     if (local_err) {
536         error_propagate(errp, local_err);
537         goto out_noclean;
538     }
539 
540     s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
541                                           READ_AHEAD_DEFAULT);
542     if ((s->readahead_size & 0x1ff) != 0) {
543         error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
544                    s->readahead_size);
545         goto out_noclean;
546     }
547 
548     s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
549                                      CURL_TIMEOUT_DEFAULT);
550     if (s->timeout > CURL_TIMEOUT_MAX) {
551         error_setg(errp, "timeout parameter is too large or negative");
552         goto out_noclean;
553     }
554 
555     s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
556 
557     cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
558     s->cookie = g_strdup(cookie);
559 
560     file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
561     if (file == NULL) {
562         error_setg(errp, "curl block driver requires an 'url' option");
563         goto out_noclean;
564     }
565 
566     if (!inited) {
567         curl_global_init(CURL_GLOBAL_ALL);
568         inited = 1;
569     }
570 
571     DPRINTF("CURL: Opening %s\n", file);
572     s->aio_context = bdrv_get_aio_context(bs);
573     s->url = g_strdup(file);
574     state = curl_init_state(bs, s);
575     if (!state)
576         goto out_noclean;
577 
578     // Get file size
579 
580     s->accept_range = false;
581     curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
582     curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION,
583                      curl_header_cb);
584     curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
585     if (curl_easy_perform(state->curl))
586         goto out;
587     curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
588     if (d)
589         s->len = (size_t)d;
590     else if(!s->len)
591         goto out;
592     if ((!strncasecmp(s->url, "http://", strlen("http://"))
593         || !strncasecmp(s->url, "https://", strlen("https://")))
594         && !s->accept_range) {
595         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
596                 "Server does not support 'range' (byte ranges).");
597         goto out;
598     }
599     DPRINTF("CURL: Size = %zd\n", s->len);
600 
601     curl_clean_state(state);
602     curl_easy_cleanup(state->curl);
603     state->curl = NULL;
604 
605     curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
606 
607     qemu_opts_del(opts);
608     return 0;
609 
610 out:
611     error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
612     curl_easy_cleanup(state->curl);
613     state->curl = NULL;
614 out_noclean:
615     g_free(s->cookie);
616     g_free(s->url);
617     qemu_opts_del(opts);
618     return -EINVAL;
619 }
620 
621 static const AIOCBInfo curl_aiocb_info = {
622     .aiocb_size         = sizeof(CURLAIOCB),
623 };
624 
625 
626 static void curl_readv_bh_cb(void *p)
627 {
628     CURLState *state;
629     int running;
630 
631     CURLAIOCB *acb = p;
632     BDRVCURLState *s = acb->common.bs->opaque;
633 
634     qemu_bh_delete(acb->bh);
635     acb->bh = NULL;
636 
637     size_t start = acb->sector_num * SECTOR_SIZE;
638     size_t end;
639 
640     // In case we have the requested data already (e.g. read-ahead),
641     // we can just call the callback and be done.
642     switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
643         case FIND_RET_OK:
644             qemu_aio_unref(acb);
645             // fall through
646         case FIND_RET_WAIT:
647             return;
648         default:
649             break;
650     }
651 
652     // No cache found, so let's start a new request
653     state = curl_init_state(acb->common.bs, s);
654     if (!state) {
655         acb->common.cb(acb->common.opaque, -EIO);
656         qemu_aio_unref(acb);
657         return;
658     }
659 
660     acb->start = 0;
661     acb->end = (acb->nb_sectors * SECTOR_SIZE);
662 
663     state->buf_off = 0;
664     g_free(state->orig_buf);
665     state->buf_start = start;
666     state->buf_len = acb->end + s->readahead_size;
667     end = MIN(start + state->buf_len, s->len) - 1;
668     state->orig_buf = g_try_malloc(state->buf_len);
669     if (state->buf_len && state->orig_buf == NULL) {
670         curl_clean_state(state);
671         acb->common.cb(acb->common.opaque, -ENOMEM);
672         qemu_aio_unref(acb);
673         return;
674     }
675     state->acb[0] = acb;
676 
677     snprintf(state->range, 127, "%zd-%zd", start, end);
678     DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
679             (acb->nb_sectors * SECTOR_SIZE), start, state->range);
680     curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
681 
682     curl_multi_add_handle(s->multi, state->curl);
683 
684     /* Tell curl it needs to kick things off */
685     curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
686 }
687 
688 static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
689         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
690         BlockCompletionFunc *cb, void *opaque)
691 {
692     CURLAIOCB *acb;
693 
694     acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque);
695 
696     acb->qiov = qiov;
697     acb->sector_num = sector_num;
698     acb->nb_sectors = nb_sectors;
699 
700     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
701     qemu_bh_schedule(acb->bh);
702     return &acb->common;
703 }
704 
705 static void curl_close(BlockDriverState *bs)
706 {
707     BDRVCURLState *s = bs->opaque;
708 
709     DPRINTF("CURL: Close\n");
710     curl_detach_aio_context(bs);
711 
712     g_free(s->cookie);
713     g_free(s->url);
714 }
715 
716 static int64_t curl_getlength(BlockDriverState *bs)
717 {
718     BDRVCURLState *s = bs->opaque;
719     return s->len;
720 }
721 
722 static BlockDriver bdrv_http = {
723     .format_name                = "http",
724     .protocol_name              = "http",
725 
726     .instance_size              = sizeof(BDRVCURLState),
727     .bdrv_parse_filename        = curl_parse_filename,
728     .bdrv_file_open             = curl_open,
729     .bdrv_close                 = curl_close,
730     .bdrv_getlength             = curl_getlength,
731 
732     .bdrv_aio_readv             = curl_aio_readv,
733 
734     .bdrv_detach_aio_context    = curl_detach_aio_context,
735     .bdrv_attach_aio_context    = curl_attach_aio_context,
736 };
737 
738 static BlockDriver bdrv_https = {
739     .format_name                = "https",
740     .protocol_name              = "https",
741 
742     .instance_size              = sizeof(BDRVCURLState),
743     .bdrv_parse_filename        = curl_parse_filename,
744     .bdrv_file_open             = curl_open,
745     .bdrv_close                 = curl_close,
746     .bdrv_getlength             = curl_getlength,
747 
748     .bdrv_aio_readv             = curl_aio_readv,
749 
750     .bdrv_detach_aio_context    = curl_detach_aio_context,
751     .bdrv_attach_aio_context    = curl_attach_aio_context,
752 };
753 
754 static BlockDriver bdrv_ftp = {
755     .format_name                = "ftp",
756     .protocol_name              = "ftp",
757 
758     .instance_size              = sizeof(BDRVCURLState),
759     .bdrv_parse_filename        = curl_parse_filename,
760     .bdrv_file_open             = curl_open,
761     .bdrv_close                 = curl_close,
762     .bdrv_getlength             = curl_getlength,
763 
764     .bdrv_aio_readv             = curl_aio_readv,
765 
766     .bdrv_detach_aio_context    = curl_detach_aio_context,
767     .bdrv_attach_aio_context    = curl_attach_aio_context,
768 };
769 
770 static BlockDriver bdrv_ftps = {
771     .format_name                = "ftps",
772     .protocol_name              = "ftps",
773 
774     .instance_size              = sizeof(BDRVCURLState),
775     .bdrv_parse_filename        = curl_parse_filename,
776     .bdrv_file_open             = curl_open,
777     .bdrv_close                 = curl_close,
778     .bdrv_getlength             = curl_getlength,
779 
780     .bdrv_aio_readv             = curl_aio_readv,
781 
782     .bdrv_detach_aio_context    = curl_detach_aio_context,
783     .bdrv_attach_aio_context    = curl_attach_aio_context,
784 };
785 
786 static BlockDriver bdrv_tftp = {
787     .format_name                = "tftp",
788     .protocol_name              = "tftp",
789 
790     .instance_size              = sizeof(BDRVCURLState),
791     .bdrv_parse_filename        = curl_parse_filename,
792     .bdrv_file_open             = curl_open,
793     .bdrv_close                 = curl_close,
794     .bdrv_getlength             = curl_getlength,
795 
796     .bdrv_aio_readv             = curl_aio_readv,
797 
798     .bdrv_detach_aio_context    = curl_detach_aio_context,
799     .bdrv_attach_aio_context    = curl_attach_aio_context,
800 };
801 
802 static void curl_block_init(void)
803 {
804     bdrv_register(&bdrv_http);
805     bdrv_register(&bdrv_https);
806     bdrv_register(&bdrv_ftp);
807     bdrv_register(&bdrv_ftps);
808     bdrv_register(&bdrv_tftp);
809 }
810 
811 block_init(curl_block_init);
812