curl.c 20.8 KB
Newer Older
A
Alexander Graf 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU Block driver for CURL images
 *
 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "qemu-common.h"
25
#include "block/block_int.h"
A
Alexander Graf 已提交
26 27 28 29 30 31
#include <curl/curl.h>

// #define DEBUG
// #define DEBUG_VERBOSE

#ifdef DEBUG_CURL
M
malc 已提交
32
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
A
Alexander Graf 已提交
33
#else
M
malc 已提交
34
#define DPRINTF(fmt, ...) do { } while (0)
A
Alexander Graf 已提交
35 36
#endif

37 38 39
#if LIBCURL_VERSION_NUM >= 0x071000
/* The multi interface timer callback was introduced in 7.16.0 */
#define NEED_CURL_TIMER_CALLBACK
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#define HAVE_SOCKET_ACTION
#endif

#ifndef HAVE_SOCKET_ACTION
/* If curl_multi_socket_action isn't available, define it statically here in
 * terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
 * less efficient but still safe. */
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
                                            curl_socket_t sockfd,
                                            int ev_bitmask,
                                            int *running_handles)
{
    return curl_multi_socket(multi_handle, sockfd, running_handles);
}
#define curl_multi_socket_action __curl_multi_socket_action
55 56
#endif

57 58 59 60
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
                   CURLPROTO_FTP | CURLPROTO_FTPS | \
                   CURLPROTO_TFTP)

A
Alexander Graf 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB    8
#define SECTOR_SIZE     512
#define READ_AHEAD_SIZE (256 * 1024)

#define FIND_RET_NONE   0
#define FIND_RET_OK     1
#define FIND_RET_WAIT   2

struct BDRVCURLState;

typedef struct CURLAIOCB {
    BlockDriverAIOCB common;
74
    QEMUBH *bh;
A
Alexander Graf 已提交
75
    QEMUIOVector *qiov;
76 77 78 79

    int64_t sector_num;
    int nb_sectors;

A
Alexander Graf 已提交
80 81 82 83 84 85 86 87 88
    size_t start;
    size_t end;
} CURLAIOCB;

typedef struct CURLState
{
    struct BDRVCURLState *s;
    CURLAIOCB *acb[CURL_NUM_ACB];
    CURL *curl;
89
    curl_socket_t sock_fd;
A
Alexander Graf 已提交
90 91 92 93 94 95 96 97 98 99 100
    char *orig_buf;
    size_t buf_start;
    size_t buf_off;
    size_t buf_len;
    char range[128];
    char errmsg[CURL_ERROR_SIZE];
    char in_use;
} CURLState;

typedef struct BDRVCURLState {
    CURLM *multi;
101
    QEMUTimer timer;
A
Alexander Graf 已提交
102 103 104
    size_t len;
    CURLState states[CURL_NUM_STATES];
    char *url;
105
    size_t readahead_size;
106
    bool accept_range;
A
Alexander Graf 已提交
107 108 109 110
} BDRVCURLState;

static void curl_clean_state(CURLState *s);
static void curl_multi_do(void *arg);
111
static void curl_multi_read(void *arg);
A
Alexander Graf 已提交
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
#ifdef NEED_CURL_TIMER_CALLBACK
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
{
    BDRVCURLState *s = opaque;

    DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
    if (timeout_ms == -1) {
        timer_del(&s->timer);
    } else {
        int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
        timer_mod(&s->timer,
                  qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
    }
    return 0;
}
#endif

A
Alexander Graf 已提交
130 131 132
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
                        void *s, void *sp)
{
133 134 135 136
    CURLState *state = NULL;
    curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
    state->sock_fd = fd;

M
malc 已提交
137
    DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
A
Alexander Graf 已提交
138 139
    switch (action) {
        case CURL_POLL_IN:
140
            qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
A
Alexander Graf 已提交
141 142
            break;
        case CURL_POLL_OUT:
143
            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
A
Alexander Graf 已提交
144 145
            break;
        case CURL_POLL_INOUT:
146
            qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
A
Alexander Graf 已提交
147 148
            break;
        case CURL_POLL_REMOVE:
S
Stefan Hajnoczi 已提交
149
            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
A
Alexander Graf 已提交
150 151 152 153 154 155
            break;
    }

    return 0;
}

156
static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
A
Alexander Graf 已提交
157
{
158
    BDRVCURLState *s = opaque;
A
Alexander Graf 已提交
159
    size_t realsize = size * nmemb;
160
    const char *accept_line = "Accept-Ranges: bytes";
A
Alexander Graf 已提交
161

162 163 164
    if (realsize >= strlen(accept_line)
        && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
        s->accept_range = true;
B
Blue Swirl 已提交
165
    }
A
Alexander Graf 已提交
166 167 168 169 170 171 172 173 174 175

    return realsize;
}

static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
{
    CURLState *s = ((CURLState*)opaque);
    size_t realsize = size * nmemb;
    int i;

B
Blue Swirl 已提交
176
    DPRINTF("CURL: Just reading %zd bytes\n", realsize);
A
Alexander Graf 已提交
177 178

    if (!s || !s->orig_buf)
179
        return 0;
A
Alexander Graf 已提交
180

181 182 183 184 185
    if (s->buf_off >= s->buf_len) {
        /* buffer full, read nothing */
        return 0;
    }
    realsize = MIN(realsize, s->buf_len - s->buf_off);
A
Alexander Graf 已提交
186 187 188 189 190 191 192 193 194 195
    memcpy(s->orig_buf + s->buf_off, ptr, realsize);
    s->buf_off += realsize;

    for(i=0; i<CURL_NUM_ACB; i++) {
        CURLAIOCB *acb = s->acb[i];

        if (!acb)
            continue;

        if ((s->buf_off >= acb->end)) {
196 197
            qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
                                acb->end - acb->start);
A
Alexander Graf 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
            acb->common.cb(acb->common.opaque, 0);
            qemu_aio_release(acb);
            s->acb[i] = NULL;
        }
    }

    return realsize;
}

static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
                         CURLAIOCB *acb)
{
    int i;
    size_t end = start + len;

    for (i=0; i<CURL_NUM_STATES; i++) {
        CURLState *state = &s->states[i];
        size_t buf_end = (state->buf_start + state->buf_off);
        size_t buf_fend = (state->buf_start + state->buf_len);

        if (!state->orig_buf)
            continue;
        if (!state->buf_off)
            continue;

        // Does the existing buffer cover our section?
        if ((start >= state->buf_start) &&
            (start <= buf_end) &&
            (end >= state->buf_start) &&
            (end <= buf_end))
        {
            char *buf = state->orig_buf + (start - state->buf_start);

231
            qemu_iovec_from_buf(acb->qiov, 0, buf, len);
A
Alexander Graf 已提交
232 233 234 235 236 237
            acb->common.cb(acb->common.opaque, 0);

            return FIND_RET_OK;
        }

        // Wait for unfinished chunks
238 239
        if (state->in_use &&
            (start >= state->buf_start) &&
A
Alexander Graf 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
            (start <= buf_fend) &&
            (end >= state->buf_start) &&
            (end <= buf_fend))
        {
            int j;

            acb->start = start - state->buf_start;
            acb->end = acb->start + len;

            for (j=0; j<CURL_NUM_ACB; j++) {
                if (!state->acb[j]) {
                    state->acb[j] = acb;
                    return FIND_RET_WAIT;
                }
            }
        }
    }

    return FIND_RET_NONE;
}

261
static void curl_multi_check_completion(BDRVCURLState *s)
A
Alexander Graf 已提交
262 263 264 265 266
{
    int msgs_in_queue;

    /* Try to find done transfers, so we can free the easy
     * handle again. */
267
    for (;;) {
A
Alexander Graf 已提交
268 269 270
        CURLMsg *msg;
        msg = curl_multi_info_read(s->multi, &msgs_in_queue);

271
        /* Quit when there are no more completions */
A
Alexander Graf 已提交
272 273 274
        if (!msg)
            break;

275 276 277 278 279 280 281 282 283 284 285 286 287
        if (msg->msg == CURLMSG_DONE) {
            CURLState *state = NULL;
            curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
                              (char **)&state);

            /* ACBs for successful messages get completed in curl_read_cb */
            if (msg->data.result != CURLE_OK) {
                int i;
                for (i = 0; i < CURL_NUM_ACB; i++) {
                    CURLAIOCB *acb = state->acb[i];

                    if (acb == NULL) {
                        continue;
288 289
                    }

290 291 292 293
                    acb->common.cb(acb->common.opaque, -EIO);
                    qemu_aio_release(acb);
                    state->acb[i] = NULL;
                }
A
Alexander Graf 已提交
294
            }
295 296 297

            curl_clean_state(state);
            break;
A
Alexander Graf 已提交
298
        }
299
    }
A
Alexander Graf 已提交
300 301
}

302 303
static void curl_multi_do(void *arg)
{
304
    CURLState *s = (CURLState *)arg;
305 306 307
    int running;
    int r;

308
    if (!s->s->multi) {
309 310 311 312
        return;
    }

    do {
313
        r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
314 315
    } while(r == CURLM_CALL_MULTI_PERFORM);

316 317 318 319 320 321 322 323
}

static void curl_multi_read(void *arg)
{
    CURLState *s = (CURLState *)arg;

    curl_multi_do(arg);
    curl_multi_check_completion(s->s);
324 325 326 327 328 329 330 331 332 333 334 335 336 337
}

static void curl_multi_timeout_do(void *arg)
{
#ifdef NEED_CURL_TIMER_CALLBACK
    BDRVCURLState *s = (BDRVCURLState *)arg;
    int running;

    if (!s->multi) {
        return;
    }

    curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);

338
    curl_multi_check_completion(s);
339 340 341 342 343
#else
    abort();
#endif
}

A
Alexander Graf 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
static CURLState *curl_init_state(BDRVCURLState *s)
{
    CURLState *state = NULL;
    int i, j;

    do {
        for (i=0; i<CURL_NUM_STATES; i++) {
            for (j=0; j<CURL_NUM_ACB; j++)
                if (s->states[i].acb[j])
                    continue;
            if (s->states[i].in_use)
                continue;

            state = &s->states[i];
            state->in_use = 1;
            break;
        }
        if (!state) {
362
            qemu_aio_wait();
A
Alexander Graf 已提交
363 364 365
        }
    } while(!state);

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    if (!state->curl) {
        state->curl = curl_easy_init();
        if (!state->curl) {
            return NULL;
        }
        curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
        curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
        curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
                         (void *)curl_read_cb);
        curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
        curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
        curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
        curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
        curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
        curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);

        /* Restrict supported protocols to avoid security issues in the more
         * obscure protocols.  For example, do not allow POP3/SMTP/IMAP see
         * CVE-2013-0249.
         *
         * Restricting protocols is only supported from 7.19.4 upwards.
         */
389
#if LIBCURL_VERSION_NUM >= 0x071304
390 391
        curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
        curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
392
#endif
393

A
Alexander Graf 已提交
394
#ifdef DEBUG_VERBOSE
395
        curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
A
Alexander Graf 已提交
396
#endif
397
    }
A
Alexander Graf 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410

    state->s = s;

    return state;
}

static void curl_clean_state(CURLState *s)
{
    if (s->s->multi)
        curl_multi_remove_handle(s->s->multi, s->curl);
    s->in_use = 0;
}

411 412
static void curl_parse_filename(const char *filename, QDict *options,
                                Error **errp)
A
Alexander Graf 已提交
413
{
414 415 416 417 418 419 420

    #define RA_OPTSTR ":readahead="
    char *file;
    char *ra;
    const char *ra_val;
    int parse_state = 0;

421
    file = g_strdup(filename);
422 423 424 425 426

    /* Parse a trailing ":readahead=#:" param, if present. */
    ra = file + strlen(file) - 1;
    while (ra >= file) {
        if (parse_state == 0) {
427
            if (*ra == ':') {
428
                parse_state++;
429
            } else {
430
                break;
431
            }
432 433 434 435 436 437 438 439
        } else if (parse_state == 1) {
            if (*ra > '9' || *ra < '0') {
                char *opt_start = ra - strlen(RA_OPTSTR) + 1;
                if (opt_start > file &&
                    strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
                    ra_val = ra + 1;
                    ra -= strlen(RA_OPTSTR) - 1;
                    *ra = '\0';
440
                    qdict_put(options, "readahead", qstring_from_str(ra_val));
441
                }
442
                break;
443 444 445 446 447
            }
        }
        ra--;
    }

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
    qdict_put(options, "url", qstring_from_str(file));

    g_free(file);
}

static QemuOptsList runtime_opts = {
    .name = "curl",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "url",
            .type = QEMU_OPT_STRING,
            .help = "URL to open",
        },
        {
            .name = "readahead",
            .type = QEMU_OPT_SIZE,
            .help = "Readahead size",
        },
        { /* end of list */ }
    },
};

M
Max Reitz 已提交
471 472
static int curl_open(BlockDriverState *bs, QDict *options, int flags,
                     Error **errp)
473 474 475 476 477 478 479 480 481 482
{
    BDRVCURLState *s = bs->opaque;
    CURLState *state = NULL;
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *file;
    double d;

    static int inited = 0;

483
    if (flags & BDRV_O_RDWR) {
P
Paolo Bonzini 已提交
484
        error_setg(errp, "curl block device does not support writes");
485 486 487
        return -EROFS;
    }

488
    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
489
    qemu_opts_absorb_qdict(opts, options, &local_err);
490
    if (local_err) {
P
Paolo Bonzini 已提交
491
        error_propagate(errp, local_err);
492 493 494 495
        goto out_noclean;
    }

    s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
496
    if ((s->readahead_size & 0x1ff) != 0) {
P
Paolo Bonzini 已提交
497 498
        error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
                   s->readahead_size);
499 500 501
        goto out_noclean;
    }

502 503
    file = qemu_opt_get(opts, "url");
    if (file == NULL) {
P
Paolo Bonzini 已提交
504
        error_setg(errp, "curl block driver requires an 'url' option");
505 506 507
        goto out_noclean;
    }

A
Alexander Graf 已提交
508 509 510 511 512
    if (!inited) {
        curl_global_init(CURL_GLOBAL_ALL);
        inited = 1;
    }

M
malc 已提交
513
    DPRINTF("CURL: Opening %s\n", file);
514
    s->url = g_strdup(file);
A
Alexander Graf 已提交
515 516 517 518 519 520
    state = curl_init_state(s);
    if (!state)
        goto out_noclean;

    // Get file size

521
    s->accept_range = false;
A
Alexander Graf 已提交
522
    curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
523 524 525
    curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION,
                     curl_header_cb);
    curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
A
Alexander Graf 已提交
526 527 528 529 530 531 532
    if (curl_easy_perform(state->curl))
        goto out;
    curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
    if (d)
        s->len = (size_t)d;
    else if(!s->len)
        goto out;
533 534 535 536 537 538 539
    if ((!strncasecmp(s->url, "http://", strlen("http://"))
        || !strncasecmp(s->url, "https://", strlen("https://")))
        && !s->accept_range) {
        pstrcpy(state->errmsg, CURL_ERROR_SIZE,
                "Server does not support 'range' (byte ranges).");
        goto out;
    }
B
Blue Swirl 已提交
540
    DPRINTF("CURL: Size = %zd\n", s->len);
A
Alexander Graf 已提交
541 542 543 544 545

    curl_clean_state(state);
    curl_easy_cleanup(state->curl);
    state->curl = NULL;

546 547 548 549
    aio_timer_init(bdrv_get_aio_context(bs), &s->timer,
                   QEMU_CLOCK_REALTIME, SCALE_NS,
                   curl_multi_timeout_do, s);

A
Alexander Graf 已提交
550 551 552 553
    // Now we know the file exists and its size, so let's
    // initialize the multi interface!

    s->multi = curl_multi_init();
554
    curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
555 556 557 558
#ifdef NEED_CURL_TIMER_CALLBACK
    curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
    curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
#endif
A
Alexander Graf 已提交
559

560
    qemu_opts_del(opts);
A
Alexander Graf 已提交
561 562 563
    return 0;

out:
564
    error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
A
Alexander Graf 已提交
565 566 567
    curl_easy_cleanup(state->curl);
    state->curl = NULL;
out_noclean:
568 569
    g_free(s->url);
    qemu_opts_del(opts);
A
Alexander Graf 已提交
570 571 572
    return -EINVAL;
}

573 574 575 576 577
static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
{
    // Do we have to implement canceling? Seems to work without...
}

S
Stefan Hajnoczi 已提交
578
static const AIOCBInfo curl_aiocb_info = {
579 580 581 582
    .aiocb_size         = sizeof(CURLAIOCB),
    .cancel             = curl_aio_cancel,
};

583 584

static void curl_readv_bh_cb(void *p)
A
Alexander Graf 已提交
585 586
{
    CURLState *state;
587
    int running;
A
Alexander Graf 已提交
588

589 590
    CURLAIOCB *acb = p;
    BDRVCURLState *s = acb->common.bs->opaque;
A
Alexander Graf 已提交
591

592 593 594 595 596
    qemu_bh_delete(acb->bh);
    acb->bh = NULL;

    size_t start = acb->sector_num * SECTOR_SIZE;
    size_t end;
A
Alexander Graf 已提交
597 598 599

    // In case we have the requested data already (e.g. read-ahead),
    // we can just call the callback and be done.
600
    switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
A
Alexander Graf 已提交
601 602 603 604
        case FIND_RET_OK:
            qemu_aio_release(acb);
            // fall through
        case FIND_RET_WAIT:
605
            return;
A
Alexander Graf 已提交
606 607 608 609 610 611
        default:
            break;
    }

    // No cache found, so let's start a new request
    state = curl_init_state(s);
612 613 614 615 616
    if (!state) {
        acb->common.cb(acb->common.opaque, -EIO);
        qemu_aio_release(acb);
        return;
    }
A
Alexander Graf 已提交
617 618

    acb->start = 0;
619
    acb->end = (acb->nb_sectors * SECTOR_SIZE);
A
Alexander Graf 已提交
620 621 622

    state->buf_off = 0;
    if (state->orig_buf)
623
        g_free(state->orig_buf);
A
Alexander Graf 已提交
624
    state->buf_start = start;
625
    state->buf_len = acb->end + s->readahead_size;
A
Alexander Graf 已提交
626
    end = MIN(start + state->buf_len, s->len) - 1;
627
    state->orig_buf = g_malloc(state->buf_len);
A
Alexander Graf 已提交
628 629
    state->acb[0] = acb;

B
Blue Swirl 已提交
630 631
    snprintf(state->range, 127, "%zd-%zd", start, end);
    DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
632
            (acb->nb_sectors * SECTOR_SIZE), start, state->range);
A
Alexander Graf 已提交
633 634 635 636
    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);

    curl_multi_add_handle(s->multi, state->curl);

637 638
    /* Tell curl it needs to kick things off */
    curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
639 640 641 642 643 644 645 646
}

static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
        BlockDriverCompletionFunc *cb, void *opaque)
{
    CURLAIOCB *acb;

S
Stefan Hajnoczi 已提交
647
    acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque);
648 649 650 651 652 653 654

    acb->qiov = qiov;
    acb->sector_num = sector_num;
    acb->nb_sectors = nb_sectors;

    acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
    qemu_bh_schedule(acb->bh);
A
Alexander Graf 已提交
655 656 657 658 659 660 661 662
    return &acb->common;
}

static void curl_close(BlockDriverState *bs)
{
    BDRVCURLState *s = bs->opaque;
    int i;

M
malc 已提交
663
    DPRINTF("CURL: Close\n");
A
Alexander Graf 已提交
664 665 666 667 668 669 670 671
    for (i=0; i<CURL_NUM_STATES; i++) {
        if (s->states[i].in_use)
            curl_clean_state(&s->states[i]);
        if (s->states[i].curl) {
            curl_easy_cleanup(s->states[i].curl);
            s->states[i].curl = NULL;
        }
        if (s->states[i].orig_buf) {
672
            g_free(s->states[i].orig_buf);
A
Alexander Graf 已提交
673 674 675 676 677
            s->states[i].orig_buf = NULL;
        }
    }
    if (s->multi)
        curl_multi_cleanup(s->multi);
678 679 680

    timer_del(&s->timer);

681
    g_free(s->url);
A
Alexander Graf 已提交
682 683 684 685 686 687 688 689 690
}

static int64_t curl_getlength(BlockDriverState *bs)
{
    BDRVCURLState *s = bs->opaque;
    return s->len;
}

static BlockDriver bdrv_http = {
691 692
    .format_name            = "http",
    .protocol_name          = "http",
A
Alexander Graf 已提交
693

694 695 696 697 698
    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
A
Alexander Graf 已提交
699

700
    .bdrv_aio_readv         = curl_aio_readv,
A
Alexander Graf 已提交
701 702 703
};

static BlockDriver bdrv_https = {
704 705
    .format_name            = "https",
    .protocol_name          = "https",
A
Alexander Graf 已提交
706

707 708 709 710 711
    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
A
Alexander Graf 已提交
712

713
    .bdrv_aio_readv         = curl_aio_readv,
A
Alexander Graf 已提交
714 715 716
};

static BlockDriver bdrv_ftp = {
717 718
    .format_name            = "ftp",
    .protocol_name          = "ftp",
A
Alexander Graf 已提交
719

720 721 722 723 724
    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
A
Alexander Graf 已提交
725

726
    .bdrv_aio_readv         = curl_aio_readv,
A
Alexander Graf 已提交
727 728 729
};

static BlockDriver bdrv_ftps = {
730 731
    .format_name            = "ftps",
    .protocol_name          = "ftps",
A
Alexander Graf 已提交
732

733 734 735 736 737
    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
A
Alexander Graf 已提交
738

739
    .bdrv_aio_readv         = curl_aio_readv,
A
Alexander Graf 已提交
740 741 742
};

static BlockDriver bdrv_tftp = {
743 744
    .format_name            = "tftp",
    .protocol_name          = "tftp",
A
Alexander Graf 已提交
745

746 747 748 749 750
    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
A
Alexander Graf 已提交
751

752
    .bdrv_aio_readv         = curl_aio_readv,
A
Alexander Graf 已提交
753 754 755 756 757 758 759 760 761 762 763 764
};

static void curl_block_init(void)
{
    bdrv_register(&bdrv_http);
    bdrv_register(&bdrv_https);
    bdrv_register(&bdrv_ftp);
    bdrv_register(&bdrv_ftps);
    bdrv_register(&bdrv_tftp);
}

block_init(curl_block_init);