2 * QEMU Block driver for CURL images
4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu-common.h"
25 #include "block/block_int.h"
26 #include <curl/curl.h>
29 // #define DEBUG_VERBOSE
32 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
34 #define DPRINTF(fmt, ...) do { } while (0)
37 #if LIBCURL_VERSION_NUM >= 0x071000
38 /* The multi interface timer callback was introduced in 7.16.0 */
39 #define NEED_CURL_TIMER_CALLBACK
42 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
43 CURLPROTO_FTP | CURLPROTO_FTPS | \
46 #define CURL_NUM_STATES 8
47 #define CURL_NUM_ACB 8
48 #define SECTOR_SIZE 512
49 #define READ_AHEAD_SIZE (256 * 1024)
51 #define FIND_RET_NONE 0
53 #define FIND_RET_WAIT 2
57 typedef struct CURLAIOCB
{
58 BlockDriverAIOCB common
;
69 typedef struct CURLState
71 struct BDRVCURLState
*s
;
72 CURLAIOCB
*acb
[CURL_NUM_ACB
];
74 curl_socket_t sock_fd
;
80 char errmsg
[CURL_ERROR_SIZE
];
84 typedef struct BDRVCURLState
{
88 CURLState states
[CURL_NUM_STATES
];
90 size_t readahead_size
;
94 static void curl_clean_state(CURLState
*s
);
95 static void curl_multi_do(void *arg
);
96 static void curl_multi_read(void *arg
);
98 #ifdef NEED_CURL_TIMER_CALLBACK
99 static int curl_timer_cb(CURLM
*multi
, long timeout_ms
, void *opaque
)
101 BDRVCURLState
*s
= opaque
;
103 DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms
);
104 if (timeout_ms
== -1) {
105 timer_del(&s
->timer
);
107 int64_t timeout_ns
= (int64_t)timeout_ms
* 1000 * 1000;
109 qemu_clock_get_ns(QEMU_CLOCK_REALTIME
) + timeout_ns
);
115 static int curl_sock_cb(CURL
*curl
, curl_socket_t fd
, int action
,
118 CURLState
*state
= NULL
;
119 curl_easy_getinfo(curl
, CURLINFO_PRIVATE
, (char **)&state
);
122 DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action
, fd
);
125 qemu_aio_set_fd_handler(fd
, curl_multi_read
, NULL
, state
);
128 qemu_aio_set_fd_handler(fd
, NULL
, curl_multi_do
, state
);
130 case CURL_POLL_INOUT
:
131 qemu_aio_set_fd_handler(fd
, curl_multi_read
, curl_multi_do
, state
);
133 case CURL_POLL_REMOVE
:
134 qemu_aio_set_fd_handler(fd
, NULL
, NULL
, NULL
);
141 static size_t curl_header_cb(void *ptr
, size_t size
, size_t nmemb
, void *opaque
)
143 BDRVCURLState
*s
= opaque
;
144 size_t realsize
= size
* nmemb
;
145 const char *accept_line
= "Accept-Ranges: bytes";
147 if (realsize
>= strlen(accept_line
)
148 && strncmp((char *)ptr
, accept_line
, strlen(accept_line
)) == 0) {
149 s
->accept_range
= true;
155 static size_t curl_read_cb(void *ptr
, size_t size
, size_t nmemb
, void *opaque
)
157 CURLState
*s
= ((CURLState
*)opaque
);
158 size_t realsize
= size
* nmemb
;
161 DPRINTF("CURL: Just reading %zd bytes\n", realsize
);
163 if (!s
|| !s
->orig_buf
)
166 if (s
->buf_off
>= s
->buf_len
) {
167 /* buffer full, read nothing */
170 realsize
= MIN(realsize
, s
->buf_len
- s
->buf_off
);
171 memcpy(s
->orig_buf
+ s
->buf_off
, ptr
, realsize
);
172 s
->buf_off
+= realsize
;
174 for(i
=0; i
<CURL_NUM_ACB
; i
++) {
175 CURLAIOCB
*acb
= s
->acb
[i
];
180 if ((s
->buf_off
>= acb
->end
)) {
181 qemu_iovec_from_buf(acb
->qiov
, 0, s
->orig_buf
+ acb
->start
,
182 acb
->end
- acb
->start
);
183 acb
->common
.cb(acb
->common
.opaque
, 0);
184 qemu_aio_release(acb
);
192 static int curl_find_buf(BDRVCURLState
*s
, size_t start
, size_t len
,
196 size_t end
= start
+ len
;
198 for (i
=0; i
<CURL_NUM_STATES
; i
++) {
199 CURLState
*state
= &s
->states
[i
];
200 size_t buf_end
= (state
->buf_start
+ state
->buf_off
);
201 size_t buf_fend
= (state
->buf_start
+ state
->buf_len
);
203 if (!state
->orig_buf
)
208 // Does the existing buffer cover our section?
209 if ((start
>= state
->buf_start
) &&
210 (start
<= buf_end
) &&
211 (end
>= state
->buf_start
) &&
214 char *buf
= state
->orig_buf
+ (start
- state
->buf_start
);
216 qemu_iovec_from_buf(acb
->qiov
, 0, buf
, len
);
217 acb
->common
.cb(acb
->common
.opaque
, 0);
222 // Wait for unfinished chunks
224 (start
>= state
->buf_start
) &&
225 (start
<= buf_fend
) &&
226 (end
>= state
->buf_start
) &&
231 acb
->start
= start
- state
->buf_start
;
232 acb
->end
= acb
->start
+ len
;
234 for (j
=0; j
<CURL_NUM_ACB
; j
++) {
235 if (!state
->acb
[j
]) {
237 return FIND_RET_WAIT
;
243 return FIND_RET_NONE
;
246 static void curl_multi_check_completion(BDRVCURLState
*s
)
250 /* Try to find done transfers, so we can free the easy
254 msg
= curl_multi_info_read(s
->multi
, &msgs_in_queue
);
256 /* Quit when there are no more completions */
260 if (msg
->msg
== CURLMSG_DONE
) {
261 CURLState
*state
= NULL
;
262 curl_easy_getinfo(msg
->easy_handle
, CURLINFO_PRIVATE
,
265 /* ACBs for successful messages get completed in curl_read_cb */
266 if (msg
->data
.result
!= CURLE_OK
) {
268 for (i
= 0; i
< CURL_NUM_ACB
; i
++) {
269 CURLAIOCB
*acb
= state
->acb
[i
];
275 acb
->common
.cb(acb
->common
.opaque
, -EIO
);
276 qemu_aio_release(acb
);
277 state
->acb
[i
] = NULL
;
281 curl_clean_state(state
);
287 static void curl_multi_do(void *arg
)
289 CURLState
*s
= (CURLState
*)arg
;
298 r
= curl_multi_socket_action(s
->s
->multi
, s
->sock_fd
, 0, &running
);
299 } while(r
== CURLM_CALL_MULTI_PERFORM
);
303 static void curl_multi_read(void *arg
)
305 CURLState
*s
= (CURLState
*)arg
;
308 curl_multi_check_completion(s
->s
);
311 static void curl_multi_timeout_do(void *arg
)
313 #ifdef NEED_CURL_TIMER_CALLBACK
314 BDRVCURLState
*s
= (BDRVCURLState
*)arg
;
321 curl_multi_socket_action(s
->multi
, CURL_SOCKET_TIMEOUT
, 0, &running
);
323 curl_multi_check_completion(s
);
329 static CURLState
*curl_init_state(BDRVCURLState
*s
)
331 CURLState
*state
= NULL
;
335 for (i
=0; i
<CURL_NUM_STATES
; i
++) {
336 for (j
=0; j
<CURL_NUM_ACB
; j
++)
337 if (s
->states
[i
].acb
[j
])
339 if (s
->states
[i
].in_use
)
342 state
= &s
->states
[i
];
352 state
->curl
= curl_easy_init();
356 curl_easy_setopt(state
->curl
, CURLOPT_URL
, s
->url
);
357 curl_easy_setopt(state
->curl
, CURLOPT_TIMEOUT
, 5);
358 curl_easy_setopt(state
->curl
, CURLOPT_WRITEFUNCTION
,
359 (void *)curl_read_cb
);
360 curl_easy_setopt(state
->curl
, CURLOPT_WRITEDATA
, (void *)state
);
361 curl_easy_setopt(state
->curl
, CURLOPT_PRIVATE
, (void *)state
);
362 curl_easy_setopt(state
->curl
, CURLOPT_AUTOREFERER
, 1);
363 curl_easy_setopt(state
->curl
, CURLOPT_FOLLOWLOCATION
, 1);
364 curl_easy_setopt(state
->curl
, CURLOPT_NOSIGNAL
, 1);
365 curl_easy_setopt(state
->curl
, CURLOPT_ERRORBUFFER
, state
->errmsg
);
366 curl_easy_setopt(state
->curl
, CURLOPT_FAILONERROR
, 1);
368 /* Restrict supported protocols to avoid security issues in the more
369 * obscure protocols. For example, do not allow POP3/SMTP/IMAP see
372 * Restricting protocols is only supported from 7.19.4 upwards.
374 #if LIBCURL_VERSION_NUM >= 0x071304
375 curl_easy_setopt(state
->curl
, CURLOPT_PROTOCOLS
, PROTOCOLS
);
376 curl_easy_setopt(state
->curl
, CURLOPT_REDIR_PROTOCOLS
, PROTOCOLS
);
380 curl_easy_setopt(state
->curl
, CURLOPT_VERBOSE
, 1);
389 static void curl_clean_state(CURLState
*s
)
392 curl_multi_remove_handle(s
->s
->multi
, s
->curl
);
396 static void curl_parse_filename(const char *filename
, QDict
*options
,
400 #define RA_OPTSTR ":readahead="
406 file
= g_strdup(filename
);
408 /* Parse a trailing ":readahead=#:" param, if present. */
409 ra
= file
+ strlen(file
) - 1;
411 if (parse_state
== 0) {
417 } else if (parse_state
== 1) {
418 if (*ra
> '9' || *ra
< '0') {
419 char *opt_start
= ra
- strlen(RA_OPTSTR
) + 1;
420 if (opt_start
> file
&&
421 strncmp(opt_start
, RA_OPTSTR
, strlen(RA_OPTSTR
)) == 0) {
423 ra
-= strlen(RA_OPTSTR
) - 1;
425 qdict_put(options
, "readahead", qstring_from_str(ra_val
));
433 qdict_put(options
, "url", qstring_from_str(file
));
438 static QemuOptsList runtime_opts
= {
440 .head
= QTAILQ_HEAD_INITIALIZER(runtime_opts
.head
),
444 .type
= QEMU_OPT_STRING
,
445 .help
= "URL to open",
449 .type
= QEMU_OPT_SIZE
,
450 .help
= "Readahead size",
452 { /* end of list */ }
456 static int curl_open(BlockDriverState
*bs
, QDict
*options
, int flags
,
459 BDRVCURLState
*s
= bs
->opaque
;
460 CURLState
*state
= NULL
;
462 Error
*local_err
= NULL
;
466 static int inited
= 0;
468 if (flags
& BDRV_O_RDWR
) {
469 error_setg(errp
, "curl block device does not support writes");
473 opts
= qemu_opts_create(&runtime_opts
, NULL
, 0, &error_abort
);
474 qemu_opts_absorb_qdict(opts
, options
, &local_err
);
476 error_propagate(errp
, local_err
);
480 s
->readahead_size
= qemu_opt_get_size(opts
, "readahead", READ_AHEAD_SIZE
);
481 if ((s
->readahead_size
& 0x1ff) != 0) {
482 error_setg(errp
, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
487 file
= qemu_opt_get(opts
, "url");
489 error_setg(errp
, "curl block driver requires an 'url' option");
494 curl_global_init(CURL_GLOBAL_ALL
);
498 DPRINTF("CURL: Opening %s\n", file
);
499 s
->url
= g_strdup(file
);
500 state
= curl_init_state(s
);
506 s
->accept_range
= false;
507 curl_easy_setopt(state
->curl
, CURLOPT_NOBODY
, 1);
508 curl_easy_setopt(state
->curl
, CURLOPT_HEADERFUNCTION
,
510 curl_easy_setopt(state
->curl
, CURLOPT_HEADERDATA
, s
);
511 if (curl_easy_perform(state
->curl
))
513 curl_easy_getinfo(state
->curl
, CURLINFO_CONTENT_LENGTH_DOWNLOAD
, &d
);
518 if ((!strncasecmp(s
->url
, "http://", strlen("http://"))
519 || !strncasecmp(s
->url
, "https://", strlen("https://")))
520 && !s
->accept_range
) {
521 pstrcpy(state
->errmsg
, CURL_ERROR_SIZE
,
522 "Server does not support 'range' (byte ranges).");
525 DPRINTF("CURL: Size = %zd\n", s
->len
);
527 curl_clean_state(state
);
528 curl_easy_cleanup(state
->curl
);
531 aio_timer_init(bdrv_get_aio_context(bs
), &s
->timer
,
532 QEMU_CLOCK_REALTIME
, SCALE_NS
,
533 curl_multi_timeout_do
, s
);
535 // Now we know the file exists and its size, so let's
536 // initialize the multi interface!
538 s
->multi
= curl_multi_init();
539 curl_multi_setopt(s
->multi
, CURLMOPT_SOCKETFUNCTION
, curl_sock_cb
);
540 #ifdef NEED_CURL_TIMER_CALLBACK
541 curl_multi_setopt(s
->multi
, CURLMOPT_TIMERDATA
, s
);
542 curl_multi_setopt(s
->multi
, CURLMOPT_TIMERFUNCTION
, curl_timer_cb
);
549 error_setg(errp
, "CURL: Error opening file: %s", state
->errmsg
);
550 curl_easy_cleanup(state
->curl
);
558 static void curl_aio_cancel(BlockDriverAIOCB
*blockacb
)
560 // Do we have to implement canceling? Seems to work without...
563 static const AIOCBInfo curl_aiocb_info
= {
564 .aiocb_size
= sizeof(CURLAIOCB
),
565 .cancel
= curl_aio_cancel
,
569 static void curl_readv_bh_cb(void *p
)
575 BDRVCURLState
*s
= acb
->common
.bs
->opaque
;
577 qemu_bh_delete(acb
->bh
);
580 size_t start
= acb
->sector_num
* SECTOR_SIZE
;
583 // In case we have the requested data already (e.g. read-ahead),
584 // we can just call the callback and be done.
585 switch (curl_find_buf(s
, start
, acb
->nb_sectors
* SECTOR_SIZE
, acb
)) {
587 qemu_aio_release(acb
);
595 // No cache found, so let's start a new request
596 state
= curl_init_state(s
);
598 acb
->common
.cb(acb
->common
.opaque
, -EIO
);
599 qemu_aio_release(acb
);
604 acb
->end
= (acb
->nb_sectors
* SECTOR_SIZE
);
608 g_free(state
->orig_buf
);
609 state
->buf_start
= start
;
610 state
->buf_len
= acb
->end
+ s
->readahead_size
;
611 end
= MIN(start
+ state
->buf_len
, s
->len
) - 1;
612 state
->orig_buf
= g_malloc(state
->buf_len
);
615 snprintf(state
->range
, 127, "%zd-%zd", start
, end
);
616 DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
617 (acb
->nb_sectors
* SECTOR_SIZE
), start
, state
->range
);
618 curl_easy_setopt(state
->curl
, CURLOPT_RANGE
, state
->range
);
620 curl_multi_add_handle(s
->multi
, state
->curl
);
622 /* Tell curl it needs to kick things off */
623 curl_multi_socket_action(s
->multi
, CURL_SOCKET_TIMEOUT
, 0, &running
);
626 static BlockDriverAIOCB
*curl_aio_readv(BlockDriverState
*bs
,
627 int64_t sector_num
, QEMUIOVector
*qiov
, int nb_sectors
,
628 BlockDriverCompletionFunc
*cb
, void *opaque
)
632 acb
= qemu_aio_get(&curl_aiocb_info
, bs
, cb
, opaque
);
635 acb
->sector_num
= sector_num
;
636 acb
->nb_sectors
= nb_sectors
;
638 acb
->bh
= qemu_bh_new(curl_readv_bh_cb
, acb
);
639 qemu_bh_schedule(acb
->bh
);
643 static void curl_close(BlockDriverState
*bs
)
645 BDRVCURLState
*s
= bs
->opaque
;
648 DPRINTF("CURL: Close\n");
649 for (i
=0; i
<CURL_NUM_STATES
; i
++) {
650 if (s
->states
[i
].in_use
)
651 curl_clean_state(&s
->states
[i
]);
652 if (s
->states
[i
].curl
) {
653 curl_easy_cleanup(s
->states
[i
].curl
);
654 s
->states
[i
].curl
= NULL
;
656 if (s
->states
[i
].orig_buf
) {
657 g_free(s
->states
[i
].orig_buf
);
658 s
->states
[i
].orig_buf
= NULL
;
662 curl_multi_cleanup(s
->multi
);
664 timer_del(&s
->timer
);
669 static int64_t curl_getlength(BlockDriverState
*bs
)
671 BDRVCURLState
*s
= bs
->opaque
;
675 static BlockDriver bdrv_http
= {
676 .format_name
= "http",
677 .protocol_name
= "http",
679 .instance_size
= sizeof(BDRVCURLState
),
680 .bdrv_parse_filename
= curl_parse_filename
,
681 .bdrv_file_open
= curl_open
,
682 .bdrv_close
= curl_close
,
683 .bdrv_getlength
= curl_getlength
,
685 .bdrv_aio_readv
= curl_aio_readv
,
688 static BlockDriver bdrv_https
= {
689 .format_name
= "https",
690 .protocol_name
= "https",
692 .instance_size
= sizeof(BDRVCURLState
),
693 .bdrv_parse_filename
= curl_parse_filename
,
694 .bdrv_file_open
= curl_open
,
695 .bdrv_close
= curl_close
,
696 .bdrv_getlength
= curl_getlength
,
698 .bdrv_aio_readv
= curl_aio_readv
,
701 static BlockDriver bdrv_ftp
= {
702 .format_name
= "ftp",
703 .protocol_name
= "ftp",
705 .instance_size
= sizeof(BDRVCURLState
),
706 .bdrv_parse_filename
= curl_parse_filename
,
707 .bdrv_file_open
= curl_open
,
708 .bdrv_close
= curl_close
,
709 .bdrv_getlength
= curl_getlength
,
711 .bdrv_aio_readv
= curl_aio_readv
,
714 static BlockDriver bdrv_ftps
= {
715 .format_name
= "ftps",
716 .protocol_name
= "ftps",
718 .instance_size
= sizeof(BDRVCURLState
),
719 .bdrv_parse_filename
= curl_parse_filename
,
720 .bdrv_file_open
= curl_open
,
721 .bdrv_close
= curl_close
,
722 .bdrv_getlength
= curl_getlength
,
724 .bdrv_aio_readv
= curl_aio_readv
,
727 static BlockDriver bdrv_tftp
= {
728 .format_name
= "tftp",
729 .protocol_name
= "tftp",
731 .instance_size
= sizeof(BDRVCURLState
),
732 .bdrv_parse_filename
= curl_parse_filename
,
733 .bdrv_file_open
= curl_open
,
734 .bdrv_close
= curl_close
,
735 .bdrv_getlength
= curl_getlength
,
737 .bdrv_aio_readv
= curl_aio_readv
,
740 static void curl_block_init(void)
742 bdrv_register(&bdrv_http
);
743 bdrv_register(&bdrv_https
);
744 bdrv_register(&bdrv_ftp
);
745 bdrv_register(&bdrv_ftps
);
746 bdrv_register(&bdrv_tftp
);
749 block_init(curl_block_init
);