qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

curl.c (31903B)


      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 
     25 #include "qemu/osdep.h"
     26 #include "qapi/error.h"
     27 #include "qemu/error-report.h"
     28 #include "qemu/module.h"
     29 #include "qemu/option.h"
     30 #include "block/block_int.h"
     31 #include "qapi/qmp/qdict.h"
     32 #include "qapi/qmp/qstring.h"
     33 #include "crypto/secret.h"
     34 #include <curl/curl.h>
     35 #include "qemu/cutils.h"
     36 #include "trace.h"
     37 
     38 // #define DEBUG_VERBOSE
     39 
     40 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
     41                    CURLPROTO_FTP | CURLPROTO_FTPS)
     42 
     43 #define CURL_NUM_STATES 8
     44 #define CURL_NUM_ACB    8
     45 #define CURL_TIMEOUT_MAX 10000
     46 
     47 #define CURL_BLOCK_OPT_URL       "url"
     48 #define CURL_BLOCK_OPT_READAHEAD "readahead"
     49 #define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
     50 #define CURL_BLOCK_OPT_TIMEOUT "timeout"
     51 #define CURL_BLOCK_OPT_COOKIE    "cookie"
     52 #define CURL_BLOCK_OPT_COOKIE_SECRET "cookie-secret"
     53 #define CURL_BLOCK_OPT_USERNAME "username"
     54 #define CURL_BLOCK_OPT_PASSWORD_SECRET "password-secret"
     55 #define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username"
     56 #define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret"
     57 
     58 #define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024)
     59 #define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true
     60 #define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5
     61 
     62 struct BDRVCURLState;
     63 struct CURLState;
     64 
     65 static bool libcurl_initialized;
     66 
     67 typedef struct CURLAIOCB {
     68     Coroutine *co;
     69     QEMUIOVector *qiov;
     70 
     71     uint64_t offset;
     72     uint64_t bytes;
     73     int ret;
     74 
     75     size_t start;
     76     size_t end;
     77 } CURLAIOCB;
     78 
     79 typedef struct CURLSocket {
     80     int fd;
     81     struct BDRVCURLState *s;
     82 } CURLSocket;
     83 
     84 typedef struct CURLState
     85 {
     86     struct BDRVCURLState *s;
     87     CURLAIOCB *acb[CURL_NUM_ACB];
     88     CURL *curl;
     89     char *orig_buf;
     90     uint64_t buf_start;
     91     size_t buf_off;
     92     size_t buf_len;
     93     char range[128];
     94     char errmsg[CURL_ERROR_SIZE];
     95     char in_use;
     96 } CURLState;
     97 
     98 typedef struct BDRVCURLState {
     99     CURLM *multi;
    100     QEMUTimer timer;
    101     uint64_t len;
    102     CURLState states[CURL_NUM_STATES];
    103     GHashTable *sockets; /* GINT_TO_POINTER(fd) -> socket */
    104     char *url;
    105     size_t readahead_size;
    106     bool sslverify;
    107     uint64_t timeout;
    108     char *cookie;
    109     bool accept_range;
    110     AioContext *aio_context;
    111     QemuMutex mutex;
    112     CoQueue free_state_waitq;
    113     char *username;
    114     char *password;
    115     char *proxyusername;
    116     char *proxypassword;
    117 } BDRVCURLState;
    118 
    119 static void curl_clean_state(CURLState *s);
    120 static void curl_multi_do(void *arg);
    121 
    122 static gboolean curl_drop_socket(void *key, void *value, void *opaque)
    123 {
    124     CURLSocket *socket = value;
    125     BDRVCURLState *s = socket->s;
    126 
    127     aio_set_fd_handler(s->aio_context, socket->fd, false,
    128                        NULL, NULL, NULL, NULL, NULL);
    129     return true;
    130 }
    131 
    132 static void curl_drop_all_sockets(GHashTable *sockets)
    133 {
    134     g_hash_table_foreach_remove(sockets, curl_drop_socket, NULL);
    135 }
    136 
    137 /* Called from curl_multi_do_locked, with s->mutex held.  */
    138 static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
    139 {
    140     BDRVCURLState *s = opaque;
    141 
    142     trace_curl_timer_cb(timeout_ms);
    143     if (timeout_ms == -1) {
    144         timer_del(&s->timer);
    145     } else {
    146         int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
    147         timer_mod(&s->timer,
    148                   qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
    149     }
    150     return 0;
    151 }
    152 
    153 /* Called from curl_multi_do_locked, with s->mutex held.  */
    154 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
    155                         void *userp, void *sp)
    156 {
    157     BDRVCURLState *s;
    158     CURLState *state = NULL;
    159     CURLSocket *socket;
    160 
    161     curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
    162     s = state->s;
    163 
    164     socket = g_hash_table_lookup(s->sockets, GINT_TO_POINTER(fd));
    165     if (!socket) {
    166         socket = g_new0(CURLSocket, 1);
    167         socket->fd = fd;
    168         socket->s = s;
    169         g_hash_table_insert(s->sockets, GINT_TO_POINTER(fd), socket);
    170     }
    171 
    172     trace_curl_sock_cb(action, (int)fd);
    173     switch (action) {
    174         case CURL_POLL_IN:
    175             aio_set_fd_handler(s->aio_context, fd, false,
    176                                curl_multi_do, NULL, NULL, NULL, socket);
    177             break;
    178         case CURL_POLL_OUT:
    179             aio_set_fd_handler(s->aio_context, fd, false,
    180                                NULL, curl_multi_do, NULL, NULL, socket);
    181             break;
    182         case CURL_POLL_INOUT:
    183             aio_set_fd_handler(s->aio_context, fd, false,
    184                                curl_multi_do, curl_multi_do,
    185                                NULL, NULL, socket);
    186             break;
    187         case CURL_POLL_REMOVE:
    188             aio_set_fd_handler(s->aio_context, fd, false,
    189                                NULL, NULL, NULL, NULL, NULL);
    190             break;
    191     }
    192 
    193     if (action == CURL_POLL_REMOVE) {
    194         g_hash_table_remove(s->sockets, GINT_TO_POINTER(fd));
    195     }
    196 
    197     return 0;
    198 }
    199 
    200 /* Called from curl_multi_do_locked, with s->mutex held.  */
    201 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
    202 {
    203     BDRVCURLState *s = opaque;
    204     size_t realsize = size * nmemb;
    205     const char *header = (char *)ptr;
    206     const char *end = header + realsize;
    207     const char *accept_ranges = "accept-ranges:";
    208     const char *bytes = "bytes";
    209 
    210     if (realsize >= strlen(accept_ranges)
    211         && g_ascii_strncasecmp(header, accept_ranges,
    212                                strlen(accept_ranges)) == 0) {
    213 
    214         char *p = strchr(header, ':') + 1;
    215 
    216         /* Skip whitespace between the header name and value. */
    217         while (p < end && *p && g_ascii_isspace(*p)) {
    218             p++;
    219         }
    220 
    221         if (end - p >= strlen(bytes)
    222             && strncmp(p, bytes, strlen(bytes)) == 0) {
    223 
    224             /* Check that there is nothing but whitespace after the value. */
    225             p += strlen(bytes);
    226             while (p < end && *p && g_ascii_isspace(*p)) {
    227                 p++;
    228             }
    229 
    230             if (p == end || !*p) {
    231                 s->accept_range = true;
    232             }
    233         }
    234     }
    235 
    236     return realsize;
    237 }
    238 
    239 /* Called from curl_multi_do_locked, with s->mutex held.  */
    240 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
    241 {
    242     CURLState *s = ((CURLState*)opaque);
    243     size_t realsize = size * nmemb;
    244 
    245     trace_curl_read_cb(realsize);
    246 
    247     if (!s || !s->orig_buf) {
    248         goto read_end;
    249     }
    250 
    251     if (s->buf_off >= s->buf_len) {
    252         /* buffer full, read nothing */
    253         goto read_end;
    254     }
    255     realsize = MIN(realsize, s->buf_len - s->buf_off);
    256     memcpy(s->orig_buf + s->buf_off, ptr, realsize);
    257     s->buf_off += realsize;
    258 
    259 read_end:
    260     /* curl will error out if we do not return this value */
    261     return size * nmemb;
    262 }
    263 
    264 /* Called with s->mutex held.  */
    265 static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len,
    266                           CURLAIOCB *acb)
    267 {
    268     int i;
    269     uint64_t end = start + len;
    270     uint64_t clamped_end = MIN(end, s->len);
    271     uint64_t clamped_len = clamped_end - start;
    272 
    273     for (i=0; i<CURL_NUM_STATES; i++) {
    274         CURLState *state = &s->states[i];
    275         uint64_t buf_end = (state->buf_start + state->buf_off);
    276         uint64_t buf_fend = (state->buf_start + state->buf_len);
    277 
    278         if (!state->orig_buf)
    279             continue;
    280         if (!state->buf_off)
    281             continue;
    282 
    283         // Does the existing buffer cover our section?
    284         if ((start >= state->buf_start) &&
    285             (start <= buf_end) &&
    286             (clamped_end >= state->buf_start) &&
    287             (clamped_end <= buf_end))
    288         {
    289             char *buf = state->orig_buf + (start - state->buf_start);
    290 
    291             qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len);
    292             if (clamped_len < len) {
    293                 qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len);
    294             }
    295             acb->ret = 0;
    296             return true;
    297         }
    298 
    299         // Wait for unfinished chunks
    300         if (state->in_use &&
    301             (start >= state->buf_start) &&
    302             (start <= buf_fend) &&
    303             (clamped_end >= state->buf_start) &&
    304             (clamped_end <= buf_fend))
    305         {
    306             int j;
    307 
    308             acb->start = start - state->buf_start;
    309             acb->end = acb->start + clamped_len;
    310 
    311             for (j=0; j<CURL_NUM_ACB; j++) {
    312                 if (!state->acb[j]) {
    313                     state->acb[j] = acb;
    314                     return true;
    315                 }
    316             }
    317         }
    318     }
    319 
    320     return false;
    321 }
    322 
    323 /* Called with s->mutex held.  */
    324 static void curl_multi_check_completion(BDRVCURLState *s)
    325 {
    326     int msgs_in_queue;
    327 
    328     /* Try to find done transfers, so we can free the easy
    329      * handle again. */
    330     for (;;) {
    331         CURLMsg *msg;
    332         msg = curl_multi_info_read(s->multi, &msgs_in_queue);
    333 
    334         /* Quit when there are no more completions */
    335         if (!msg)
    336             break;
    337 
    338         if (msg->msg == CURLMSG_DONE) {
    339             int i;
    340             CURLState *state = NULL;
    341             bool error = msg->data.result != CURLE_OK;
    342 
    343             curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
    344                               (char **)&state);
    345 
    346             if (error) {
    347                 static int errcount = 100;
    348 
    349                 /* Don't lose the original error message from curl, since
    350                  * it contains extra data.
    351                  */
    352                 if (errcount > 0) {
    353                     error_report("curl: %s", state->errmsg);
    354                     if (--errcount == 0) {
    355                         error_report("curl: further errors suppressed");
    356                     }
    357                 }
    358             }
    359 
    360             for (i = 0; i < CURL_NUM_ACB; i++) {
    361                 CURLAIOCB *acb = state->acb[i];
    362 
    363                 if (acb == NULL) {
    364                     continue;
    365                 }
    366 
    367                 if (!error) {
    368                     /* Assert that we have read all data */
    369                     assert(state->buf_off >= acb->end);
    370 
    371                     qemu_iovec_from_buf(acb->qiov, 0,
    372                                         state->orig_buf + acb->start,
    373                                         acb->end - acb->start);
    374 
    375                     if (acb->end - acb->start < acb->bytes) {
    376                         size_t offset = acb->end - acb->start;
    377                         qemu_iovec_memset(acb->qiov, offset, 0,
    378                                           acb->bytes - offset);
    379                     }
    380                 }
    381 
    382                 acb->ret = error ? -EIO : 0;
    383                 state->acb[i] = NULL;
    384                 qemu_mutex_unlock(&s->mutex);
    385                 aio_co_wake(acb->co);
    386                 qemu_mutex_lock(&s->mutex);
    387             }
    388 
    389             curl_clean_state(state);
    390             break;
    391         }
    392     }
    393 }
    394 
    395 /* Called with s->mutex held.  */
    396 static void curl_multi_do_locked(CURLSocket *socket)
    397 {
    398     BDRVCURLState *s = socket->s;
    399     int running;
    400     int r;
    401 
    402     if (!s->multi) {
    403         return;
    404     }
    405 
    406     do {
    407         r = curl_multi_socket_action(s->multi, socket->fd, 0, &running);
    408     } while (r == CURLM_CALL_MULTI_PERFORM);
    409 }
    410 
    411 static void curl_multi_do(void *arg)
    412 {
    413     CURLSocket *socket = arg;
    414     BDRVCURLState *s = socket->s;
    415 
    416     qemu_mutex_lock(&s->mutex);
    417     curl_multi_do_locked(socket);
    418     curl_multi_check_completion(s);
    419     qemu_mutex_unlock(&s->mutex);
    420 }
    421 
    422 static void curl_multi_timeout_do(void *arg)
    423 {
    424     BDRVCURLState *s = (BDRVCURLState *)arg;
    425     int running;
    426 
    427     if (!s->multi) {
    428         return;
    429     }
    430 
    431     qemu_mutex_lock(&s->mutex);
    432     curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
    433 
    434     curl_multi_check_completion(s);
    435     qemu_mutex_unlock(&s->mutex);
    436 }
    437 
    438 /* Called with s->mutex held.  */
    439 static CURLState *curl_find_state(BDRVCURLState *s)
    440 {
    441     CURLState *state = NULL;
    442     int i;
    443 
    444     for (i = 0; i < CURL_NUM_STATES; i++) {
    445         if (!s->states[i].in_use) {
    446             state = &s->states[i];
    447             state->in_use = 1;
    448             break;
    449         }
    450     }
    451     return state;
    452 }
    453 
    454 static int curl_init_state(BDRVCURLState *s, CURLState *state)
    455 {
    456     if (!state->curl) {
    457         state->curl = curl_easy_init();
    458         if (!state->curl) {
    459             return -EIO;
    460         }
    461         if (curl_easy_setopt(state->curl, CURLOPT_URL, s->url) ||
    462             curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
    463                              (long) s->sslverify) ||
    464             curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYHOST,
    465                              s->sslverify ? 2L : 0L)) {
    466             goto err;
    467         }
    468         if (s->cookie) {
    469             if (curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie)) {
    470                 goto err;
    471             }
    472         }
    473         if (curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout) ||
    474             curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
    475                              (void *)curl_read_cb) ||
    476             curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state) ||
    477             curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state) ||
    478             curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1) ||
    479             curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1) ||
    480             curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1) ||
    481             curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg) ||
    482             curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1)) {
    483             goto err;
    484         }
    485         if (s->username) {
    486             if (curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username)) {
    487                 goto err;
    488             }
    489         }
    490         if (s->password) {
    491             if (curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password)) {
    492                 goto err;
    493             }
    494         }
    495         if (s->proxyusername) {
    496             if (curl_easy_setopt(state->curl,
    497                                  CURLOPT_PROXYUSERNAME, s->proxyusername)) {
    498                 goto err;
    499             }
    500         }
    501         if (s->proxypassword) {
    502             if (curl_easy_setopt(state->curl,
    503                                  CURLOPT_PROXYPASSWORD, s->proxypassword)) {
    504                 goto err;
    505             }
    506         }
    507 
    508         /* Restrict supported protocols to avoid security issues in the more
    509          * obscure protocols.  For example, do not allow POP3/SMTP/IMAP see
    510          * CVE-2013-0249.
    511          *
    512          * Restricting protocols is only supported from 7.19.4 upwards.
    513          */
    514 #if LIBCURL_VERSION_NUM >= 0x071304
    515         if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) ||
    516             curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) {
    517             goto err;
    518         }
    519 #endif
    520 
    521 #ifdef DEBUG_VERBOSE
    522         if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) {
    523             goto err;
    524         }
    525 #endif
    526     }
    527 
    528     state->s = s;
    529 
    530     return 0;
    531 
    532 err:
    533     curl_easy_cleanup(state->curl);
    534     state->curl = NULL;
    535     return -EIO;
    536 }
    537 
    538 /* Called with s->mutex held.  */
    539 static void curl_clean_state(CURLState *s)
    540 {
    541     int j;
    542     for (j = 0; j < CURL_NUM_ACB; j++) {
    543         assert(!s->acb[j]);
    544     }
    545 
    546     if (s->s->multi)
    547         curl_multi_remove_handle(s->s->multi, s->curl);
    548 
    549     s->in_use = 0;
    550 
    551     qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex);
    552 }
    553 
    554 static void curl_parse_filename(const char *filename, QDict *options,
    555                                 Error **errp)
    556 {
    557     qdict_put_str(options, CURL_BLOCK_OPT_URL, filename);
    558 }
    559 
    560 static void curl_detach_aio_context(BlockDriverState *bs)
    561 {
    562     BDRVCURLState *s = bs->opaque;
    563     int i;
    564 
    565     WITH_QEMU_LOCK_GUARD(&s->mutex) {
    566         curl_drop_all_sockets(s->sockets);
    567         for (i = 0; i < CURL_NUM_STATES; i++) {
    568             if (s->states[i].in_use) {
    569                 curl_clean_state(&s->states[i]);
    570             }
    571             if (s->states[i].curl) {
    572                 curl_easy_cleanup(s->states[i].curl);
    573                 s->states[i].curl = NULL;
    574             }
    575             g_free(s->states[i].orig_buf);
    576             s->states[i].orig_buf = NULL;
    577         }
    578         if (s->multi) {
    579             curl_multi_cleanup(s->multi);
    580             s->multi = NULL;
    581         }
    582     }
    583 
    584     timer_del(&s->timer);
    585 }
    586 
    587 static void curl_attach_aio_context(BlockDriverState *bs,
    588                                     AioContext *new_context)
    589 {
    590     BDRVCURLState *s = bs->opaque;
    591 
    592     aio_timer_init(new_context, &s->timer,
    593                    QEMU_CLOCK_REALTIME, SCALE_NS,
    594                    curl_multi_timeout_do, s);
    595 
    596     assert(!s->multi);
    597     s->multi = curl_multi_init();
    598     s->aio_context = new_context;
    599     curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
    600     curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
    601     curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
    602 }
    603 
    604 static QemuOptsList runtime_opts = {
    605     .name = "curl",
    606     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    607     .desc = {
    608         {
    609             .name = CURL_BLOCK_OPT_URL,
    610             .type = QEMU_OPT_STRING,
    611             .help = "URL to open",
    612         },
    613         {
    614             .name = CURL_BLOCK_OPT_READAHEAD,
    615             .type = QEMU_OPT_SIZE,
    616             .help = "Readahead size",
    617         },
    618         {
    619             .name = CURL_BLOCK_OPT_SSLVERIFY,
    620             .type = QEMU_OPT_BOOL,
    621             .help = "Verify SSL certificate"
    622         },
    623         {
    624             .name = CURL_BLOCK_OPT_TIMEOUT,
    625             .type = QEMU_OPT_NUMBER,
    626             .help = "Curl timeout"
    627         },
    628         {
    629             .name = CURL_BLOCK_OPT_COOKIE,
    630             .type = QEMU_OPT_STRING,
    631             .help = "Pass the cookie or list of cookies with each request"
    632         },
    633         {
    634             .name = CURL_BLOCK_OPT_COOKIE_SECRET,
    635             .type = QEMU_OPT_STRING,
    636             .help = "ID of secret used as cookie passed with each request"
    637         },
    638         {
    639             .name = CURL_BLOCK_OPT_USERNAME,
    640             .type = QEMU_OPT_STRING,
    641             .help = "Username for HTTP auth"
    642         },
    643         {
    644             .name = CURL_BLOCK_OPT_PASSWORD_SECRET,
    645             .type = QEMU_OPT_STRING,
    646             .help = "ID of secret used as password for HTTP auth",
    647         },
    648         {
    649             .name = CURL_BLOCK_OPT_PROXY_USERNAME,
    650             .type = QEMU_OPT_STRING,
    651             .help = "Username for HTTP proxy auth"
    652         },
    653         {
    654             .name = CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
    655             .type = QEMU_OPT_STRING,
    656             .help = "ID of secret used as password for HTTP proxy auth",
    657         },
    658         { /* end of list */ }
    659     },
    660 };
    661 
    662 
    663 static int curl_open(BlockDriverState *bs, QDict *options, int flags,
    664                      Error **errp)
    665 {
    666     BDRVCURLState *s = bs->opaque;
    667     CURLState *state = NULL;
    668     QemuOpts *opts;
    669     const char *file;
    670     const char *cookie;
    671     const char *cookie_secret;
    672     double d;
    673     const char *secretid;
    674     const char *protocol_delimiter;
    675     int ret;
    676 
    677     ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
    678                                     errp);
    679     if (ret < 0) {
    680         return ret;
    681     }
    682 
    683     if (!libcurl_initialized) {
    684         ret = curl_global_init(CURL_GLOBAL_ALL);
    685         if (ret) {
    686             error_setg(errp, "libcurl initialization failed with %d", ret);
    687             return -EIO;
    688         }
    689         libcurl_initialized = true;
    690     }
    691 
    692     qemu_mutex_init(&s->mutex);
    693     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
    694     if (!qemu_opts_absorb_qdict(opts, options, errp)) {
    695         goto out_noclean;
    696     }
    697 
    698     s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
    699                                           CURL_BLOCK_OPT_READAHEAD_DEFAULT);
    700     if ((s->readahead_size & 0x1ff) != 0) {
    701         error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
    702                    s->readahead_size);
    703         goto out_noclean;
    704     }
    705 
    706     s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
    707                                      CURL_BLOCK_OPT_TIMEOUT_DEFAULT);
    708     if (s->timeout > CURL_TIMEOUT_MAX) {
    709         error_setg(errp, "timeout parameter is too large or negative");
    710         goto out_noclean;
    711     }
    712 
    713     s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY,
    714                                      CURL_BLOCK_OPT_SSLVERIFY_DEFAULT);
    715 
    716     cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
    717     cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET);
    718 
    719     if (cookie && cookie_secret) {
    720         error_setg(errp,
    721                    "curl driver cannot handle both cookie and cookie secret");
    722         goto out_noclean;
    723     }
    724 
    725     if (cookie_secret) {
    726         s->cookie = qcrypto_secret_lookup_as_utf8(cookie_secret, errp);
    727         if (!s->cookie) {
    728             goto out_noclean;
    729         }
    730     } else {
    731         s->cookie = g_strdup(cookie);
    732     }
    733 
    734     file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
    735     if (file == NULL) {
    736         error_setg(errp, "curl block driver requires an 'url' option");
    737         goto out_noclean;
    738     }
    739 
    740     if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) ||
    741         !strstart(protocol_delimiter, "://", NULL))
    742     {
    743         error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not "
    744                    "start with '%s://')", bs->drv->protocol_name, file,
    745                    bs->drv->protocol_name);
    746         goto out_noclean;
    747     }
    748 
    749     s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
    750     secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);
    751 
    752     if (secretid) {
    753         s->password = qcrypto_secret_lookup_as_utf8(secretid, errp);
    754         if (!s->password) {
    755             goto out_noclean;
    756         }
    757     }
    758 
    759     s->proxyusername = g_strdup(
    760         qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_USERNAME));
    761     secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET);
    762     if (secretid) {
    763         s->proxypassword = qcrypto_secret_lookup_as_utf8(secretid, errp);
    764         if (!s->proxypassword) {
    765             goto out_noclean;
    766         }
    767     }
    768 
    769     trace_curl_open(file);
    770     qemu_co_queue_init(&s->free_state_waitq);
    771     s->aio_context = bdrv_get_aio_context(bs);
    772     s->url = g_strdup(file);
    773     s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free);
    774     qemu_mutex_lock(&s->mutex);
    775     state = curl_find_state(s);
    776     qemu_mutex_unlock(&s->mutex);
    777     if (!state) {
    778         goto out_noclean;
    779     }
    780 
    781     // Get file size
    782 
    783     if (curl_init_state(s, state) < 0) {
    784         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    785                 "curl library initialization failed.");
    786         goto out;
    787     }
    788 
    789     s->accept_range = false;
    790     if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) ||
    791         curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) ||
    792         curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) {
    793         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    794                 "curl library initialization failed.");
    795         goto out;
    796     }
    797     if (curl_easy_perform(state->curl))
    798         goto out;
    799     if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
    800         goto out;
    801     }
    802     /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not
    803      * know or the size is zero. From 7.19.4 CURL returns -1 if size is not
    804      * known and zero if it is really zero-length file. */
    805 #if LIBCURL_VERSION_NUM >= 0x071304
    806     if (d < 0) {
    807         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    808                 "Server didn't report file size.");
    809         goto out;
    810     }
    811 #else
    812     if (d <= 0) {
    813         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    814                 "Unknown file size or zero-length file.");
    815         goto out;
    816     }
    817 #endif
    818 
    819     s->len = d;
    820 
    821     if ((!strncasecmp(s->url, "http://", strlen("http://"))
    822         || !strncasecmp(s->url, "https://", strlen("https://")))
    823         && !s->accept_range) {
    824         pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    825                 "Server does not support 'range' (byte ranges).");
    826         goto out;
    827     }
    828     trace_curl_open_size(s->len);
    829 
    830     qemu_mutex_lock(&s->mutex);
    831     curl_clean_state(state);
    832     qemu_mutex_unlock(&s->mutex);
    833     curl_easy_cleanup(state->curl);
    834     state->curl = NULL;
    835 
    836     curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
    837 
    838     qemu_opts_del(opts);
    839     return 0;
    840 
    841 out:
    842     error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
    843     curl_easy_cleanup(state->curl);
    844     state->curl = NULL;
    845 out_noclean:
    846     qemu_mutex_destroy(&s->mutex);
    847     g_free(s->cookie);
    848     g_free(s->url);
    849     g_free(s->username);
    850     g_free(s->proxyusername);
    851     g_free(s->proxypassword);
    852     curl_drop_all_sockets(s->sockets);
    853     g_hash_table_destroy(s->sockets);
    854     qemu_opts_del(opts);
    855     return -EINVAL;
    856 }
    857 
    858 static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
    859 {
    860     CURLState *state;
    861     int running;
    862 
    863     BDRVCURLState *s = bs->opaque;
    864 
    865     uint64_t start = acb->offset;
    866     uint64_t end;
    867 
    868     qemu_mutex_lock(&s->mutex);
    869 
    870     // In case we have the requested data already (e.g. read-ahead),
    871     // we can just call the callback and be done.
    872     if (curl_find_buf(s, start, acb->bytes, acb)) {
    873         goto out;
    874     }
    875 
    876     // No cache found, so let's start a new request
    877     for (;;) {
    878         state = curl_find_state(s);
    879         if (state) {
    880             break;
    881         }
    882         qemu_co_queue_wait(&s->free_state_waitq, &s->mutex);
    883     }
    884 
    885     if (curl_init_state(s, state) < 0) {
    886         curl_clean_state(state);
    887         acb->ret = -EIO;
    888         goto out;
    889     }
    890 
    891     acb->start = 0;
    892     acb->end = MIN(acb->bytes, s->len - start);
    893 
    894     state->buf_off = 0;
    895     g_free(state->orig_buf);
    896     state->buf_start = start;
    897     state->buf_len = MIN(acb->end + s->readahead_size, s->len - start);
    898     end = start + state->buf_len - 1;
    899     state->orig_buf = g_try_malloc(state->buf_len);
    900     if (state->buf_len && state->orig_buf == NULL) {
    901         curl_clean_state(state);
    902         acb->ret = -ENOMEM;
    903         goto out;
    904     }
    905     state->acb[0] = acb;
    906 
    907     snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end);
    908     trace_curl_setup_preadv(acb->bytes, start, state->range);
    909     if (curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range) ||
    910         curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) {
    911         state->acb[0] = NULL;
    912         acb->ret = -EIO;
    913 
    914         curl_clean_state(state);
    915         goto out;
    916     }
    917 
    918     /* Tell curl it needs to kick things off */
    919     curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
    920 
    921 out:
    922     qemu_mutex_unlock(&s->mutex);
    923 }
    924 
    925 static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
    926         int64_t offset, int64_t bytes, QEMUIOVector *qiov,
    927         BdrvRequestFlags flags)
    928 {
    929     CURLAIOCB acb = {
    930         .co = qemu_coroutine_self(),
    931         .ret = -EINPROGRESS,
    932         .qiov = qiov,
    933         .offset = offset,
    934         .bytes = bytes
    935     };
    936 
    937     curl_setup_preadv(bs, &acb);
    938     while (acb.ret == -EINPROGRESS) {
    939         qemu_coroutine_yield();
    940     }
    941     return acb.ret;
    942 }
    943 
    944 static void curl_close(BlockDriverState *bs)
    945 {
    946     BDRVCURLState *s = bs->opaque;
    947 
    948     trace_curl_close();
    949     curl_detach_aio_context(bs);
    950     qemu_mutex_destroy(&s->mutex);
    951 
    952     g_hash_table_destroy(s->sockets);
    953     g_free(s->cookie);
    954     g_free(s->url);
    955     g_free(s->username);
    956     g_free(s->proxyusername);
    957     g_free(s->proxypassword);
    958 }
    959 
    960 static int64_t curl_getlength(BlockDriverState *bs)
    961 {
    962     BDRVCURLState *s = bs->opaque;
    963     return s->len;
    964 }
    965 
    966 static void curl_refresh_filename(BlockDriverState *bs)
    967 {
    968     BDRVCURLState *s = bs->opaque;
    969 
    970     /* "readahead" and "timeout" do not change the guest-visible data,
    971      * so ignore them */
    972     if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT ||
    973         s->cookie || s->username || s->password || s->proxyusername ||
    974         s->proxypassword)
    975     {
    976         return;
    977     }
    978 
    979     pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url);
    980 }
    981 
    982 
    983 static const char *const curl_strong_runtime_opts[] = {
    984     CURL_BLOCK_OPT_URL,
    985     CURL_BLOCK_OPT_SSLVERIFY,
    986     CURL_BLOCK_OPT_COOKIE,
    987     CURL_BLOCK_OPT_COOKIE_SECRET,
    988     CURL_BLOCK_OPT_USERNAME,
    989     CURL_BLOCK_OPT_PASSWORD_SECRET,
    990     CURL_BLOCK_OPT_PROXY_USERNAME,
    991     CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
    992 
    993     NULL
    994 };
    995 
    996 static BlockDriver bdrv_http = {
    997     .format_name                = "http",
    998     .protocol_name              = "http",
    999 
   1000     .instance_size              = sizeof(BDRVCURLState),
   1001     .bdrv_parse_filename        = curl_parse_filename,
   1002     .bdrv_file_open             = curl_open,
   1003     .bdrv_close                 = curl_close,
   1004     .bdrv_getlength             = curl_getlength,
   1005 
   1006     .bdrv_co_preadv             = curl_co_preadv,
   1007 
   1008     .bdrv_detach_aio_context    = curl_detach_aio_context,
   1009     .bdrv_attach_aio_context    = curl_attach_aio_context,
   1010 
   1011     .bdrv_refresh_filename      = curl_refresh_filename,
   1012     .strong_runtime_opts        = curl_strong_runtime_opts,
   1013 };
   1014 
   1015 static BlockDriver bdrv_https = {
   1016     .format_name                = "https",
   1017     .protocol_name              = "https",
   1018 
   1019     .instance_size              = sizeof(BDRVCURLState),
   1020     .bdrv_parse_filename        = curl_parse_filename,
   1021     .bdrv_file_open             = curl_open,
   1022     .bdrv_close                 = curl_close,
   1023     .bdrv_getlength             = curl_getlength,
   1024 
   1025     .bdrv_co_preadv             = curl_co_preadv,
   1026 
   1027     .bdrv_detach_aio_context    = curl_detach_aio_context,
   1028     .bdrv_attach_aio_context    = curl_attach_aio_context,
   1029 
   1030     .bdrv_refresh_filename      = curl_refresh_filename,
   1031     .strong_runtime_opts        = curl_strong_runtime_opts,
   1032 };
   1033 
   1034 static BlockDriver bdrv_ftp = {
   1035     .format_name                = "ftp",
   1036     .protocol_name              = "ftp",
   1037 
   1038     .instance_size              = sizeof(BDRVCURLState),
   1039     .bdrv_parse_filename        = curl_parse_filename,
   1040     .bdrv_file_open             = curl_open,
   1041     .bdrv_close                 = curl_close,
   1042     .bdrv_getlength             = curl_getlength,
   1043 
   1044     .bdrv_co_preadv             = curl_co_preadv,
   1045 
   1046     .bdrv_detach_aio_context    = curl_detach_aio_context,
   1047     .bdrv_attach_aio_context    = curl_attach_aio_context,
   1048 
   1049     .bdrv_refresh_filename      = curl_refresh_filename,
   1050     .strong_runtime_opts        = curl_strong_runtime_opts,
   1051 };
   1052 
   1053 static BlockDriver bdrv_ftps = {
   1054     .format_name                = "ftps",
   1055     .protocol_name              = "ftps",
   1056 
   1057     .instance_size              = sizeof(BDRVCURLState),
   1058     .bdrv_parse_filename        = curl_parse_filename,
   1059     .bdrv_file_open             = curl_open,
   1060     .bdrv_close                 = curl_close,
   1061     .bdrv_getlength             = curl_getlength,
   1062 
   1063     .bdrv_co_preadv             = curl_co_preadv,
   1064 
   1065     .bdrv_detach_aio_context    = curl_detach_aio_context,
   1066     .bdrv_attach_aio_context    = curl_attach_aio_context,
   1067 
   1068     .bdrv_refresh_filename      = curl_refresh_filename,
   1069     .strong_runtime_opts        = curl_strong_runtime_opts,
   1070 };
   1071 
   1072 static void curl_block_init(void)
   1073 {
   1074     bdrv_register(&bdrv_http);
   1075     bdrv_register(&bdrv_https);
   1076     bdrv_register(&bdrv_ftp);
   1077     bdrv_register(&bdrv_ftps);
   1078 }
   1079 
   1080 block_init(curl_block_init);