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_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
#define CURL_NUM_STATES 8
38
#define CURL_NUM_ACB 8
39
#define SECTOR_SIZE 512
40
#define READ_AHEAD_SIZE (256 * 1024)
42
#define FIND_RET_NONE 0
44
#define FIND_RET_WAIT 2
48
typedef struct CURLAIOCB {
49
BlockDriverAIOCB common;
60
typedef struct CURLState
62
struct BDRVCURLState *s;
63
CURLAIOCB *acb[CURL_NUM_ACB];
70
char errmsg[CURL_ERROR_SIZE];
74
typedef struct BDRVCURLState {
77
CURLState states[CURL_NUM_STATES];
79
size_t readahead_size;
82
static void curl_clean_state(CURLState *s);
83
static void curl_multi_do(void *arg);
84
static int curl_aio_flush(void *opaque);
86
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
89
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
92
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
96
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
100
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
101
curl_aio_flush, NULL, s);
103
case CURL_POLL_REMOVE:
104
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
111
static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
113
CURLState *s = ((CURLState*)opaque);
114
size_t realsize = size * nmemb;
117
if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) {
124
static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
126
CURLState *s = ((CURLState*)opaque);
127
size_t realsize = size * nmemb;
130
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
132
if (!s || !s->orig_buf)
135
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
136
s->buf_off += realsize;
138
for(i=0; i<CURL_NUM_ACB; i++) {
139
CURLAIOCB *acb = s->acb[i];
144
if ((s->buf_off >= acb->end)) {
145
qemu_iovec_from_buffer(acb->qiov, s->orig_buf + acb->start,
146
acb->end - acb->start);
147
acb->common.cb(acb->common.opaque, 0);
148
qemu_aio_release(acb);
157
static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
161
size_t end = start + len;
163
for (i=0; i<CURL_NUM_STATES; i++) {
164
CURLState *state = &s->states[i];
165
size_t buf_end = (state->buf_start + state->buf_off);
166
size_t buf_fend = (state->buf_start + state->buf_len);
168
if (!state->orig_buf)
173
// Does the existing buffer cover our section?
174
if ((start >= state->buf_start) &&
175
(start <= buf_end) &&
176
(end >= state->buf_start) &&
179
char *buf = state->orig_buf + (start - state->buf_start);
181
qemu_iovec_from_buffer(acb->qiov, buf, len);
182
acb->common.cb(acb->common.opaque, 0);
187
// Wait for unfinished chunks
188
if ((start >= state->buf_start) &&
189
(start <= buf_fend) &&
190
(end >= state->buf_start) &&
195
acb->start = start - state->buf_start;
196
acb->end = acb->start + len;
198
for (j=0; j<CURL_NUM_ACB; j++) {
199
if (!state->acb[j]) {
201
return FIND_RET_WAIT;
207
return FIND_RET_NONE;
210
static void curl_multi_do(void *arg)
212
BDRVCURLState *s = (BDRVCURLState *)arg;
221
r = curl_multi_socket_all(s->multi, &running);
222
} while(r == CURLM_CALL_MULTI_PERFORM);
224
/* Try to find done transfers, so we can free the easy
228
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
232
if (msg->msg == CURLMSG_NONE)
238
CURLState *state = NULL;
239
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
241
/* ACBs for successful messages get completed in curl_read_cb */
242
if (msg->data.result != CURLE_OK) {
244
for (i = 0; i < CURL_NUM_ACB; i++) {
245
CURLAIOCB *acb = state->acb[i];
251
acb->common.cb(acb->common.opaque, -EIO);
252
qemu_aio_release(acb);
253
state->acb[i] = NULL;
257
curl_clean_state(state);
264
} while(msgs_in_queue);
267
static CURLState *curl_init_state(BDRVCURLState *s)
269
CURLState *state = NULL;
273
for (i=0; i<CURL_NUM_STATES; i++) {
274
for (j=0; j<CURL_NUM_ACB; j++)
275
if (s->states[i].acb[j])
277
if (s->states[i].in_use)
280
state = &s->states[i];
293
state->curl = curl_easy_init();
296
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
297
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
298
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
299
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
300
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
301
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
302
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
303
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
304
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
305
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
308
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
318
static void curl_clean_state(CURLState *s)
321
curl_multi_remove_handle(s->s->multi, s->curl);
325
static int curl_open(BlockDriverState *bs, const char *filename, int flags)
327
BDRVCURLState *s = bs->opaque;
328
CURLState *state = NULL;
331
#define RA_OPTSTR ":readahead="
337
static int inited = 0;
339
file = g_strdup(filename);
340
s->readahead_size = READ_AHEAD_SIZE;
342
/* Parse a trailing ":readahead=#:" param, if present. */
343
ra = file + strlen(file) - 1;
345
if (parse_state == 0) {
350
} else if (parse_state == 1) {
351
if (*ra > '9' || *ra < '0') {
352
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
353
if (opt_start > file &&
354
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
356
ra -= strlen(RA_OPTSTR) - 1;
358
s->readahead_size = atoi(ra_val);
368
if ((s->readahead_size & 0x1ff) != 0) {
369
fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
375
curl_global_init(CURL_GLOBAL_ALL);
379
DPRINTF("CURL: Opening %s\n", file);
381
state = curl_init_state(s);
387
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
388
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb);
389
if (curl_easy_perform(state->curl))
391
curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
392
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
393
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 0);
398
DPRINTF("CURL: Size = %zd\n", s->len);
400
curl_clean_state(state);
401
curl_easy_cleanup(state->curl);
404
// Now we know the file exists and its size, so let's
405
// initialize the multi interface!
407
s->multi = curl_multi_init();
408
curl_multi_setopt( s->multi, CURLMOPT_SOCKETDATA, s);
409
curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb );
415
fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
416
curl_easy_cleanup(state->curl);
423
static int curl_aio_flush(void *opaque)
425
BDRVCURLState *s = opaque;
428
for (i=0; i < CURL_NUM_STATES; i++) {
429
for(j=0; j < CURL_NUM_ACB; j++) {
430
if (s->states[i].acb[j]) {
438
static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
440
// Do we have to implement canceling? Seems to work without...
443
static AIOPool curl_aio_pool = {
444
.aiocb_size = sizeof(CURLAIOCB),
445
.cancel = curl_aio_cancel,
449
static void curl_readv_bh_cb(void *p)
454
BDRVCURLState *s = acb->common.bs->opaque;
456
qemu_bh_delete(acb->bh);
459
size_t start = acb->sector_num * SECTOR_SIZE;
462
// In case we have the requested data already (e.g. read-ahead),
463
// we can just call the callback and be done.
464
switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
466
qemu_aio_release(acb);
474
// No cache found, so let's start a new request
475
state = curl_init_state(s);
477
acb->common.cb(acb->common.opaque, -EIO);
478
qemu_aio_release(acb);
483
acb->end = (acb->nb_sectors * SECTOR_SIZE);
487
g_free(state->orig_buf);
488
state->buf_start = start;
489
state->buf_len = acb->end + s->readahead_size;
490
end = MIN(start + state->buf_len, s->len) - 1;
491
state->orig_buf = g_malloc(state->buf_len);
494
snprintf(state->range, 127, "%zd-%zd", start, end);
495
DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
496
(acb->nb_sectors * SECTOR_SIZE), start, state->range);
497
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
499
curl_multi_add_handle(s->multi, state->curl);
504
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
505
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
506
BlockDriverCompletionFunc *cb, void *opaque)
510
acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
517
acb->sector_num = sector_num;
518
acb->nb_sectors = nb_sectors;
520
acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
523
DPRINTF("CURL: qemu_bh_new failed\n");
527
qemu_bh_schedule(acb->bh);
531
static void curl_close(BlockDriverState *bs)
533
BDRVCURLState *s = bs->opaque;
536
DPRINTF("CURL: Close\n");
537
for (i=0; i<CURL_NUM_STATES; i++) {
538
if (s->states[i].in_use)
539
curl_clean_state(&s->states[i]);
540
if (s->states[i].curl) {
541
curl_easy_cleanup(s->states[i].curl);
542
s->states[i].curl = NULL;
544
if (s->states[i].orig_buf) {
545
g_free(s->states[i].orig_buf);
546
s->states[i].orig_buf = NULL;
550
curl_multi_cleanup(s->multi);
555
static int64_t curl_getlength(BlockDriverState *bs)
557
BDRVCURLState *s = bs->opaque;
561
static BlockDriver bdrv_http = {
562
.format_name = "http",
563
.protocol_name = "http",
565
.instance_size = sizeof(BDRVCURLState),
566
.bdrv_file_open = curl_open,
567
.bdrv_close = curl_close,
568
.bdrv_getlength = curl_getlength,
570
.bdrv_aio_readv = curl_aio_readv,
573
static BlockDriver bdrv_https = {
574
.format_name = "https",
575
.protocol_name = "https",
577
.instance_size = sizeof(BDRVCURLState),
578
.bdrv_file_open = curl_open,
579
.bdrv_close = curl_close,
580
.bdrv_getlength = curl_getlength,
582
.bdrv_aio_readv = curl_aio_readv,
585
static BlockDriver bdrv_ftp = {
586
.format_name = "ftp",
587
.protocol_name = "ftp",
589
.instance_size = sizeof(BDRVCURLState),
590
.bdrv_file_open = curl_open,
591
.bdrv_close = curl_close,
592
.bdrv_getlength = curl_getlength,
594
.bdrv_aio_readv = curl_aio_readv,
597
static BlockDriver bdrv_ftps = {
598
.format_name = "ftps",
599
.protocol_name = "ftps",
601
.instance_size = sizeof(BDRVCURLState),
602
.bdrv_file_open = curl_open,
603
.bdrv_close = curl_close,
604
.bdrv_getlength = curl_getlength,
606
.bdrv_aio_readv = curl_aio_readv,
609
static BlockDriver bdrv_tftp = {
610
.format_name = "tftp",
611
.protocol_name = "tftp",
613
.instance_size = sizeof(BDRVCURLState),
614
.bdrv_file_open = curl_open,
615
.bdrv_close = curl_close,
616
.bdrv_getlength = curl_getlength,
618
.bdrv_aio_readv = curl_aio_readv,
621
static void curl_block_init(void)
623
bdrv_register(&bdrv_http);
624
bdrv_register(&bdrv_https);
625
bdrv_register(&bdrv_ftp);
626
bdrv_register(&bdrv_ftps);
627
bdrv_register(&bdrv_tftp);
630
block_init(curl_block_init);