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