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 <curl/curl.h> 27 28 // #define DEBUG 29 // #define DEBUG_VERBOSE 30 31 #ifdef DEBUG_CURL 32 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0) 33 #else 34 #define DPRINTF(fmt, ...) do { } while (0) 35 #endif 36 37 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ 38 CURLPROTO_FTP | CURLPROTO_FTPS | \ 39 CURLPROTO_TFTP) 40 41 #define CURL_NUM_STATES 8 42 #define CURL_NUM_ACB 8 43 #define SECTOR_SIZE 512 44 #define READ_AHEAD_SIZE (256 * 1024) 45 46 #define FIND_RET_NONE 0 47 #define FIND_RET_OK 1 48 #define FIND_RET_WAIT 2 49 50 struct BDRVCURLState; 51 52 typedef struct CURLAIOCB { 53 BlockDriverAIOCB common; 54 QEMUBH *bh; 55 QEMUIOVector *qiov; 56 57 int64_t sector_num; 58 int nb_sectors; 59 60 size_t start; 61 size_t end; 62 } CURLAIOCB; 63 64 typedef struct CURLState 65 { 66 struct BDRVCURLState *s; 67 CURLAIOCB *acb[CURL_NUM_ACB]; 68 CURL *curl; 69 char *orig_buf; 70 size_t buf_start; 71 size_t buf_off; 72 size_t buf_len; 73 char range[128]; 74 char errmsg[CURL_ERROR_SIZE]; 75 char in_use; 76 } CURLState; 77 78 typedef struct BDRVCURLState { 79 CURLM *multi; 80 size_t len; 81 CURLState states[CURL_NUM_STATES]; 82 char *url; 83 size_t readahead_size; 84 } BDRVCURLState; 85 86 static void curl_clean_state(CURLState *s); 87 static void curl_multi_do(void *arg); 88 static int curl_aio_flush(void *opaque); 89 90 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, 91 void *s, void *sp) 92 { 93 DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd); 94 switch (action) { 95 case CURL_POLL_IN: 96 qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s); 97 break; 98 case CURL_POLL_OUT: 99 qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s); 100 break; 101 case CURL_POLL_INOUT: 102 qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, 103 curl_aio_flush, s); 104 break; 105 case CURL_POLL_REMOVE: 106 qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL); 107 break; 108 } 109 110 return 0; 111 } 112 113 static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 114 { 115 CURLState *s = ((CURLState*)opaque); 116 size_t realsize = size * nmemb; 117 size_t fsize; 118 119 if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) { 120 s->s->len = fsize; 121 } 122 123 return realsize; 124 } 125 126 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 127 { 128 CURLState *s = ((CURLState*)opaque); 129 size_t realsize = size * nmemb; 130 int i; 131 132 DPRINTF("CURL: Just reading %zd bytes\n", realsize); 133 134 if (!s || !s->orig_buf) 135 goto read_end; 136 137 memcpy(s->orig_buf + s->buf_off, ptr, realsize); 138 s->buf_off += realsize; 139 140 for(i=0; i<CURL_NUM_ACB; i++) { 141 CURLAIOCB *acb = s->acb[i]; 142 143 if (!acb) 144 continue; 145 146 if ((s->buf_off >= acb->end)) { 147 qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start, 148 acb->end - acb->start); 149 acb->common.cb(acb->common.opaque, 0); 150 qemu_aio_release(acb); 151 s->acb[i] = NULL; 152 } 153 } 154 155 read_end: 156 return realsize; 157 } 158 159 static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len, 160 CURLAIOCB *acb) 161 { 162 int i; 163 size_t end = start + len; 164 165 for (i=0; i<CURL_NUM_STATES; i++) { 166 CURLState *state = &s->states[i]; 167 size_t buf_end = (state->buf_start + state->buf_off); 168 size_t buf_fend = (state->buf_start + state->buf_len); 169 170 if (!state->orig_buf) 171 continue; 172 if (!state->buf_off) 173 continue; 174 175 // Does the existing buffer cover our section? 176 if ((start >= state->buf_start) && 177 (start <= buf_end) && 178 (end >= state->buf_start) && 179 (end <= buf_end)) 180 { 181 char *buf = state->orig_buf + (start - state->buf_start); 182 183 qemu_iovec_from_buf(acb->qiov, 0, buf, len); 184 acb->common.cb(acb->common.opaque, 0); 185 186 return FIND_RET_OK; 187 } 188 189 // Wait for unfinished chunks 190 if ((start >= state->buf_start) && 191 (start <= buf_fend) && 192 (end >= state->buf_start) && 193 (end <= buf_fend)) 194 { 195 int j; 196 197 acb->start = start - state->buf_start; 198 acb->end = acb->start + len; 199 200 for (j=0; j<CURL_NUM_ACB; j++) { 201 if (!state->acb[j]) { 202 state->acb[j] = acb; 203 return FIND_RET_WAIT; 204 } 205 } 206 } 207 } 208 209 return FIND_RET_NONE; 210 } 211 212 static void curl_multi_do(void *arg) 213 { 214 BDRVCURLState *s = (BDRVCURLState *)arg; 215 int running; 216 int r; 217 int msgs_in_queue; 218 219 if (!s->multi) 220 return; 221 222 do { 223 r = curl_multi_socket_all(s->multi, &running); 224 } while(r == CURLM_CALL_MULTI_PERFORM); 225 226 /* Try to find done transfers, so we can free the easy 227 * handle again. */ 228 do { 229 CURLMsg *msg; 230 msg = curl_multi_info_read(s->multi, &msgs_in_queue); 231 232 if (!msg) 233 break; 234 if (msg->msg == CURLMSG_NONE) 235 break; 236 237 switch (msg->msg) { 238 case CURLMSG_DONE: 239 { 240 CURLState *state = NULL; 241 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state); 242 243 /* ACBs for successful messages get completed in curl_read_cb */ 244 if (msg->data.result != CURLE_OK) { 245 int i; 246 for (i = 0; i < CURL_NUM_ACB; i++) { 247 CURLAIOCB *acb = state->acb[i]; 248 249 if (acb == NULL) { 250 continue; 251 } 252 253 acb->common.cb(acb->common.opaque, -EIO); 254 qemu_aio_release(acb); 255 state->acb[i] = NULL; 256 } 257 } 258 259 curl_clean_state(state); 260 break; 261 } 262 default: 263 msgs_in_queue = 0; 264 break; 265 } 266 } while(msgs_in_queue); 267 } 268 269 static CURLState *curl_init_state(BDRVCURLState *s) 270 { 271 CURLState *state = NULL; 272 int i, j; 273 274 do { 275 for (i=0; i<CURL_NUM_STATES; i++) { 276 for (j=0; j<CURL_NUM_ACB; j++) 277 if (s->states[i].acb[j]) 278 continue; 279 if (s->states[i].in_use) 280 continue; 281 282 state = &s->states[i]; 283 state->in_use = 1; 284 break; 285 } 286 if (!state) { 287 g_usleep(100); 288 curl_multi_do(s); 289 } 290 } while(!state); 291 292 if (state->curl) 293 goto has_curl; 294 295 state->curl = curl_easy_init(); 296 if (!state->curl) 297 return NULL; 298 curl_easy_setopt(state->curl, CURLOPT_URL, s->url); 299 curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5); 300 curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb); 301 curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state); 302 curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state); 303 curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1); 304 curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1); 305 curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1); 306 curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg); 307 curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1); 308 309 /* Restrict supported protocols to avoid security issues in the more 310 * obscure protocols. For example, do not allow POP3/SMTP/IMAP see 311 * CVE-2013-0249. 312 * 313 * Restricting protocols is only supported from 7.19.4 upwards. 314 */ 315 #if LIBCURL_VERSION_NUM >= 0x071304 316 curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS); 317 curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS); 318 #endif 319 320 #ifdef DEBUG_VERBOSE 321 curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1); 322 #endif 323 324 has_curl: 325 326 state->s = s; 327 328 return state; 329 } 330 331 static void curl_clean_state(CURLState *s) 332 { 333 if (s->s->multi) 334 curl_multi_remove_handle(s->s->multi, s->curl); 335 s->in_use = 0; 336 } 337 338 static void curl_parse_filename(const char *filename, QDict *options, 339 Error **errp) 340 { 341 342 #define RA_OPTSTR ":readahead=" 343 char *file; 344 char *ra; 345 const char *ra_val; 346 int parse_state = 0; 347 348 file = g_strdup(filename); 349 350 /* Parse a trailing ":readahead=#:" param, if present. */ 351 ra = file + strlen(file) - 1; 352 while (ra >= file) { 353 if (parse_state == 0) { 354 if (*ra == ':') { 355 parse_state++; 356 } else { 357 break; 358 } 359 } else if (parse_state == 1) { 360 if (*ra > '9' || *ra < '0') { 361 char *opt_start = ra - strlen(RA_OPTSTR) + 1; 362 if (opt_start > file && 363 strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) { 364 ra_val = ra + 1; 365 ra -= strlen(RA_OPTSTR) - 1; 366 *ra = '\0'; 367 qdict_put(options, "readahead", qstring_from_str(ra_val)); 368 } 369 break; 370 } 371 } 372 ra--; 373 } 374 375 qdict_put(options, "url", qstring_from_str(file)); 376 377 g_free(file); 378 } 379 380 static QemuOptsList runtime_opts = { 381 .name = "curl", 382 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 383 .desc = { 384 { 385 .name = "url", 386 .type = QEMU_OPT_STRING, 387 .help = "URL to open", 388 }, 389 { 390 .name = "readahead", 391 .type = QEMU_OPT_SIZE, 392 .help = "Readahead size", 393 }, 394 { /* end of list */ } 395 }, 396 }; 397 398 static int curl_open(BlockDriverState *bs, QDict *options, int flags) 399 { 400 BDRVCURLState *s = bs->opaque; 401 CURLState *state = NULL; 402 QemuOpts *opts; 403 Error *local_err = NULL; 404 const char *file; 405 double d; 406 407 static int inited = 0; 408 409 if (flags & BDRV_O_RDWR) { 410 qerror_report(ERROR_CLASS_GENERIC_ERROR, 411 "curl block device does not support writes"); 412 return -EROFS; 413 } 414 415 opts = qemu_opts_create_nofail(&runtime_opts); 416 qemu_opts_absorb_qdict(opts, options, &local_err); 417 if (error_is_set(&local_err)) { 418 qerror_report_err(local_err); 419 error_free(local_err); 420 goto out_noclean; 421 } 422 423 s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE); 424 if ((s->readahead_size & 0x1ff) != 0) { 425 fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n", 426 s->readahead_size); 427 goto out_noclean; 428 } 429 430 file = qemu_opt_get(opts, "url"); 431 if (file == NULL) { 432 qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block driver requires " 433 "an 'url' option"); 434 goto out_noclean; 435 } 436 437 if (!inited) { 438 curl_global_init(CURL_GLOBAL_ALL); 439 inited = 1; 440 } 441 442 DPRINTF("CURL: Opening %s\n", file); 443 s->url = g_strdup(file); 444 state = curl_init_state(s); 445 if (!state) 446 goto out_noclean; 447 448 // Get file size 449 450 curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1); 451 curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb); 452 if (curl_easy_perform(state->curl)) 453 goto out; 454 curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); 455 if (d) 456 s->len = (size_t)d; 457 else if(!s->len) 458 goto out; 459 DPRINTF("CURL: Size = %zd\n", s->len); 460 461 curl_clean_state(state); 462 curl_easy_cleanup(state->curl); 463 state->curl = NULL; 464 465 // Now we know the file exists and its size, so let's 466 // initialize the multi interface! 467 468 s->multi = curl_multi_init(); 469 curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s); 470 curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); 471 curl_multi_do(s); 472 473 qemu_opts_del(opts); 474 return 0; 475 476 out: 477 fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg); 478 curl_easy_cleanup(state->curl); 479 state->curl = NULL; 480 out_noclean: 481 g_free(s->url); 482 qemu_opts_del(opts); 483 return -EINVAL; 484 } 485 486 static int curl_aio_flush(void *opaque) 487 { 488 BDRVCURLState *s = opaque; 489 int i, j; 490 491 for (i=0; i < CURL_NUM_STATES; i++) { 492 for(j=0; j < CURL_NUM_ACB; j++) { 493 if (s->states[i].acb[j]) { 494 return 1; 495 } 496 } 497 } 498 return 0; 499 } 500 501 static void curl_aio_cancel(BlockDriverAIOCB *blockacb) 502 { 503 // Do we have to implement canceling? Seems to work without... 504 } 505 506 static const AIOCBInfo curl_aiocb_info = { 507 .aiocb_size = sizeof(CURLAIOCB), 508 .cancel = curl_aio_cancel, 509 }; 510 511 512 static void curl_readv_bh_cb(void *p) 513 { 514 CURLState *state; 515 516 CURLAIOCB *acb = p; 517 BDRVCURLState *s = acb->common.bs->opaque; 518 519 qemu_bh_delete(acb->bh); 520 acb->bh = NULL; 521 522 size_t start = acb->sector_num * SECTOR_SIZE; 523 size_t end; 524 525 // In case we have the requested data already (e.g. read-ahead), 526 // we can just call the callback and be done. 527 switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) { 528 case FIND_RET_OK: 529 qemu_aio_release(acb); 530 // fall through 531 case FIND_RET_WAIT: 532 return; 533 default: 534 break; 535 } 536 537 // No cache found, so let's start a new request 538 state = curl_init_state(s); 539 if (!state) { 540 acb->common.cb(acb->common.opaque, -EIO); 541 qemu_aio_release(acb); 542 return; 543 } 544 545 acb->start = 0; 546 acb->end = (acb->nb_sectors * SECTOR_SIZE); 547 548 state->buf_off = 0; 549 if (state->orig_buf) 550 g_free(state->orig_buf); 551 state->buf_start = start; 552 state->buf_len = acb->end + s->readahead_size; 553 end = MIN(start + state->buf_len, s->len) - 1; 554 state->orig_buf = g_malloc(state->buf_len); 555 state->acb[0] = acb; 556 557 snprintf(state->range, 127, "%zd-%zd", start, end); 558 DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n", 559 (acb->nb_sectors * SECTOR_SIZE), start, state->range); 560 curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range); 561 562 curl_multi_add_handle(s->multi, state->curl); 563 curl_multi_do(s); 564 565 } 566 567 static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, 568 int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, 569 BlockDriverCompletionFunc *cb, void *opaque) 570 { 571 CURLAIOCB *acb; 572 573 acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque); 574 575 acb->qiov = qiov; 576 acb->sector_num = sector_num; 577 acb->nb_sectors = nb_sectors; 578 579 acb->bh = qemu_bh_new(curl_readv_bh_cb, acb); 580 581 if (!acb->bh) { 582 DPRINTF("CURL: qemu_bh_new failed\n"); 583 return NULL; 584 } 585 586 qemu_bh_schedule(acb->bh); 587 return &acb->common; 588 } 589 590 static void curl_close(BlockDriverState *bs) 591 { 592 BDRVCURLState *s = bs->opaque; 593 int i; 594 595 DPRINTF("CURL: Close\n"); 596 for (i=0; i<CURL_NUM_STATES; i++) { 597 if (s->states[i].in_use) 598 curl_clean_state(&s->states[i]); 599 if (s->states[i].curl) { 600 curl_easy_cleanup(s->states[i].curl); 601 s->states[i].curl = NULL; 602 } 603 if (s->states[i].orig_buf) { 604 g_free(s->states[i].orig_buf); 605 s->states[i].orig_buf = NULL; 606 } 607 } 608 if (s->multi) 609 curl_multi_cleanup(s->multi); 610 g_free(s->url); 611 } 612 613 static int64_t curl_getlength(BlockDriverState *bs) 614 { 615 BDRVCURLState *s = bs->opaque; 616 return s->len; 617 } 618 619 static BlockDriver bdrv_http = { 620 .format_name = "http", 621 .protocol_name = "http", 622 623 .instance_size = sizeof(BDRVCURLState), 624 .bdrv_parse_filename = curl_parse_filename, 625 .bdrv_file_open = curl_open, 626 .bdrv_close = curl_close, 627 .bdrv_getlength = curl_getlength, 628 629 .bdrv_aio_readv = curl_aio_readv, 630 }; 631 632 static BlockDriver bdrv_https = { 633 .format_name = "https", 634 .protocol_name = "https", 635 636 .instance_size = sizeof(BDRVCURLState), 637 .bdrv_parse_filename = curl_parse_filename, 638 .bdrv_file_open = curl_open, 639 .bdrv_close = curl_close, 640 .bdrv_getlength = curl_getlength, 641 642 .bdrv_aio_readv = curl_aio_readv, 643 }; 644 645 static BlockDriver bdrv_ftp = { 646 .format_name = "ftp", 647 .protocol_name = "ftp", 648 649 .instance_size = sizeof(BDRVCURLState), 650 .bdrv_parse_filename = curl_parse_filename, 651 .bdrv_file_open = curl_open, 652 .bdrv_close = curl_close, 653 .bdrv_getlength = curl_getlength, 654 655 .bdrv_aio_readv = curl_aio_readv, 656 }; 657 658 static BlockDriver bdrv_ftps = { 659 .format_name = "ftps", 660 .protocol_name = "ftps", 661 662 .instance_size = sizeof(BDRVCURLState), 663 .bdrv_parse_filename = curl_parse_filename, 664 .bdrv_file_open = curl_open, 665 .bdrv_close = curl_close, 666 .bdrv_getlength = curl_getlength, 667 668 .bdrv_aio_readv = curl_aio_readv, 669 }; 670 671 static BlockDriver bdrv_tftp = { 672 .format_name = "tftp", 673 .protocol_name = "tftp", 674 675 .instance_size = sizeof(BDRVCURLState), 676 .bdrv_parse_filename = curl_parse_filename, 677 .bdrv_file_open = curl_open, 678 .bdrv_close = curl_close, 679 .bdrv_getlength = curl_getlength, 680 681 .bdrv_aio_readv = curl_aio_readv, 682 }; 683 684 static void curl_block_init(void) 685 { 686 bdrv_register(&bdrv_http); 687 bdrv_register(&bdrv_https); 688 bdrv_register(&bdrv_ftp); 689 bdrv_register(&bdrv_ftps); 690 bdrv_register(&bdrv_tftp); 691 } 692 693 block_init(curl_block_init); 694