Fix sys-queue.h conflict for good
[qemu] / block / curl.c
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_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 CURL_NUM_STATES 8
38 #define CURL_NUM_ACB    8
39 #define SECTOR_SIZE     512
40 #define READ_AHEAD_SIZE (256 * 1024)
41
42 #define FIND_RET_NONE   0
43 #define FIND_RET_OK     1
44 #define FIND_RET_WAIT   2
45
46 struct BDRVCURLState;
47
48 typedef struct CURLAIOCB {
49     BlockDriverAIOCB common;
50     QEMUIOVector *qiov;
51     size_t start;
52     size_t end;
53 } CURLAIOCB;
54
55 typedef struct CURLState
56 {
57     struct BDRVCURLState *s;
58     CURLAIOCB *acb[CURL_NUM_ACB];
59     CURL *curl;
60     char *orig_buf;
61     size_t buf_start;
62     size_t buf_off;
63     size_t buf_len;
64     char range[128];
65     char errmsg[CURL_ERROR_SIZE];
66     char in_use;
67 } CURLState;
68
69 typedef struct BDRVCURLState {
70     CURLM *multi;
71     size_t len;
72     CURLState states[CURL_NUM_STATES];
73     char *url;
74     size_t readahead_size;
75 } BDRVCURLState;
76
77 static void curl_clean_state(CURLState *s);
78 static void curl_multi_do(void *arg);
79
80 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
81                         void *s, void *sp)
82 {
83     dprintf("CURL (AIO): Sock action %d on fd %d\n", action, fd);
84     switch (action) {
85         case CURL_POLL_IN:
86             qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, s);
87             break;
88         case CURL_POLL_OUT:
89             qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, s);
90             break;
91         case CURL_POLL_INOUT:
92             qemu_aio_set_fd_handler(fd, curl_multi_do,
93                                     curl_multi_do, NULL, s);
94             break;
95         case CURL_POLL_REMOVE:
96             qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
97             break;
98     }
99
100     return 0;
101 }
102
103 static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
104 {
105     CURLState *s = ((CURLState*)opaque);
106     size_t realsize = size * nmemb;
107     long long fsize;
108
109     if(sscanf(ptr, "Content-Length: %lld", &fsize) == 1)
110         s->s->len = fsize;
111
112     return realsize;
113 }
114
115 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
116 {
117     CURLState *s = ((CURLState*)opaque);
118     size_t realsize = size * nmemb;
119     int i;
120
121     dprintf("CURL: Just reading %lld bytes\n", (unsigned long long)realsize);
122
123     if (!s || !s->orig_buf)
124         goto read_end;
125
126     memcpy(s->orig_buf + s->buf_off, ptr, realsize);
127     s->buf_off += realsize;
128
129     for(i=0; i<CURL_NUM_ACB; i++) {
130         CURLAIOCB *acb = s->acb[i];
131
132         if (!acb)
133             continue;
134
135         if ((s->buf_off >= acb->end)) {
136             qemu_iovec_from_buffer(acb->qiov, s->orig_buf + acb->start,
137                                    acb->end - acb->start);
138             acb->common.cb(acb->common.opaque, 0);
139             qemu_aio_release(acb);
140             s->acb[i] = NULL;
141         }
142     }
143
144 read_end:
145     return realsize;
146 }
147
148 static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
149                          CURLAIOCB *acb)
150 {
151     int i;
152     size_t end = start + len;
153
154     for (i=0; i<CURL_NUM_STATES; i++) {
155         CURLState *state = &s->states[i];
156         size_t buf_end = (state->buf_start + state->buf_off);
157         size_t buf_fend = (state->buf_start + state->buf_len);
158
159         if (!state->orig_buf)
160             continue;
161         if (!state->buf_off)
162             continue;
163
164         // Does the existing buffer cover our section?
165         if ((start >= state->buf_start) &&
166             (start <= buf_end) &&
167             (end >= state->buf_start) &&
168             (end <= buf_end))
169         {
170             char *buf = state->orig_buf + (start - state->buf_start);
171
172             qemu_iovec_from_buffer(acb->qiov, buf, len);
173             acb->common.cb(acb->common.opaque, 0);
174
175             return FIND_RET_OK;
176         }
177
178         // Wait for unfinished chunks
179         if ((start >= state->buf_start) &&
180             (start <= buf_fend) &&
181             (end >= state->buf_start) &&
182             (end <= buf_fend))
183         {
184             int j;
185
186             acb->start = start - state->buf_start;
187             acb->end = acb->start + len;
188
189             for (j=0; j<CURL_NUM_ACB; j++) {
190                 if (!state->acb[j]) {
191                     state->acb[j] = acb;
192                     return FIND_RET_WAIT;
193                 }
194             }
195         }
196     }
197
198     return FIND_RET_NONE;
199 }
200
201 static void curl_multi_do(void *arg)
202 {
203     BDRVCURLState *s = (BDRVCURLState *)arg;
204     int running;
205     int r;
206     int msgs_in_queue;
207
208     if (!s->multi)
209         return;
210
211     do {
212         r = curl_multi_socket_all(s->multi, &running);
213     } while(r == CURLM_CALL_MULTI_PERFORM);
214
215     /* Try to find done transfers, so we can free the easy
216      * handle again. */
217     do {
218         CURLMsg *msg;
219         msg = curl_multi_info_read(s->multi, &msgs_in_queue);
220
221         if (!msg)
222             break;
223         if (msg->msg == CURLMSG_NONE)
224             break;
225
226         switch (msg->msg) {
227             case CURLMSG_DONE:
228             {
229                 CURLState *state = NULL;
230                 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
231                 curl_clean_state(state);
232                 break;
233             }
234             default:
235                 msgs_in_queue = 0;
236                 break;
237         }
238     } while(msgs_in_queue);
239 }
240
241 static CURLState *curl_init_state(BDRVCURLState *s)
242 {
243     CURLState *state = NULL;
244     int i, j;
245
246     do {
247         for (i=0; i<CURL_NUM_STATES; i++) {
248             for (j=0; j<CURL_NUM_ACB; j++)
249                 if (s->states[i].acb[j])
250                     continue;
251             if (s->states[i].in_use)
252                 continue;
253
254             state = &s->states[i];
255             state->in_use = 1;
256             break;
257         }
258         if (!state) {
259             usleep(100);
260             curl_multi_do(s);
261         }
262     } while(!state);
263
264     if (state->curl)
265         goto has_curl;
266
267     state->curl = curl_easy_init();
268     if (!state->curl)
269         return NULL;
270     curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
271     curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
272     curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
273     curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
274     curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
275     curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
276     curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
277     curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
278     curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
279     
280 #ifdef DEBUG_VERBOSE
281     curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
282 #endif
283
284 has_curl:
285
286     state->s = s;
287
288     return state;
289 }
290
291 static void curl_clean_state(CURLState *s)
292 {
293     if (s->s->multi)
294         curl_multi_remove_handle(s->s->multi, s->curl);
295     s->in_use = 0;
296 }
297
298 static int curl_open(BlockDriverState *bs, const char *filename, int flags)
299 {
300     BDRVCURLState *s = bs->opaque;
301     CURLState *state = NULL;
302     double d;
303
304     #define RA_OPTSTR ":readahead="
305     char *file;
306     char *ra;
307     const char *ra_val;
308     int parse_state = 0;
309
310     static int inited = 0;
311
312     file = strdup(filename);
313     s->readahead_size = READ_AHEAD_SIZE;
314
315     /* Parse a trailing ":readahead=#:" param, if present. */
316     ra = file + strlen(file) - 1;
317     while (ra >= file) {
318         if (parse_state == 0) {
319             if (*ra == ':')
320                 parse_state++;
321             else
322                 break;
323         } else if (parse_state == 1) {
324             if (*ra > '9' || *ra < '0') {
325                 char *opt_start = ra - strlen(RA_OPTSTR) + 1;
326                 if (opt_start > file &&
327                     strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
328                     ra_val = ra + 1;
329                     ra -= strlen(RA_OPTSTR) - 1;
330                     *ra = '\0';
331                     s->readahead_size = atoi(ra_val);
332                     break;
333                 } else {
334                     break;
335                 }
336             }
337         }
338         ra--;
339     }
340
341     if ((s->readahead_size & 0x1ff) != 0) {
342         fprintf(stderr, "HTTP_READAHEAD_SIZE %Zd is not a multiple of 512\n",
343                 s->readahead_size);
344         goto out_noclean;
345     }
346
347     if (!inited) {
348         curl_global_init(CURL_GLOBAL_ALL);
349         inited = 1;
350     }
351
352     dprintf("CURL: Opening %s\n", file);
353     s->url = file;
354     state = curl_init_state(s);
355     if (!state)
356         goto out_noclean;
357
358     // Get file size
359
360     curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
361     curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb);
362     if (curl_easy_perform(state->curl))
363         goto out;
364     curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
365     curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
366     curl_easy_setopt(state->curl, CURLOPT_NOBODY, 0);
367     if (d)
368         s->len = (size_t)d;
369     else if(!s->len)
370         goto out;
371     dprintf("CURL: Size = %lld\n", (long long)s->len);
372
373     curl_clean_state(state);
374     curl_easy_cleanup(state->curl);
375     state->curl = NULL;
376
377     // Now we know the file exists and its size, so let's
378     // initialize the multi interface!
379
380     s->multi = curl_multi_init();
381     curl_multi_setopt( s->multi, CURLMOPT_SOCKETDATA, s); 
382     curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb ); 
383     curl_multi_do(s);
384
385     return 0;
386
387 out:
388     fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
389     curl_easy_cleanup(state->curl);
390     state->curl = NULL;
391 out_noclean:
392     qemu_free(file);
393     return -EINVAL;
394 }
395
396 static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
397 {
398     // Do we have to implement canceling? Seems to work without...
399 }
400
401 static AIOPool curl_aio_pool = {
402     .aiocb_size         = sizeof(CURLAIOCB),
403     .cancel             = curl_aio_cancel,
404 };
405
406 static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
407         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
408         BlockDriverCompletionFunc *cb, void *opaque)
409 {
410     BDRVCURLState *s = bs->opaque;
411     CURLAIOCB *acb;
412     size_t start = sector_num * SECTOR_SIZE;
413     size_t end;
414     CURLState *state;
415
416     acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
417     if (!acb)
418         return NULL;
419
420     acb->qiov = qiov;
421
422     // In case we have the requested data already (e.g. read-ahead),
423     // we can just call the callback and be done.
424
425     switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
426         case FIND_RET_OK:
427             qemu_aio_release(acb);
428             // fall through
429         case FIND_RET_WAIT:
430             return &acb->common;
431         default:
432             break;
433     }
434
435     // No cache found, so let's start a new request
436
437     state = curl_init_state(s);
438     if (!state)
439         return NULL;
440
441     acb->start = 0;
442     acb->end = (nb_sectors * SECTOR_SIZE);
443
444     state->buf_off = 0;
445     if (state->orig_buf)
446         qemu_free(state->orig_buf);
447     state->buf_start = start;
448     state->buf_len = acb->end + s->readahead_size;
449     end = MIN(start + state->buf_len, s->len) - 1;
450     state->orig_buf = qemu_malloc(state->buf_len);
451     state->acb[0] = acb;
452
453     snprintf(state->range, 127, "%lld-%lld", (long long)start, (long long)end);
454     dprintf("CURL (AIO): Reading %d at %lld (%s)\n", (nb_sectors * SECTOR_SIZE), start, state->range);
455     curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
456
457     curl_multi_add_handle(s->multi, state->curl);
458     curl_multi_do(s);
459
460     return &acb->common;
461 }
462
463 static void curl_close(BlockDriverState *bs)
464 {
465     BDRVCURLState *s = bs->opaque;
466     int i;
467
468     dprintf("CURL: Close\n");
469     for (i=0; i<CURL_NUM_STATES; i++) {
470         if (s->states[i].in_use)
471             curl_clean_state(&s->states[i]);
472         if (s->states[i].curl) {
473             curl_easy_cleanup(s->states[i].curl);
474             s->states[i].curl = NULL;
475         }
476         if (s->states[i].orig_buf) {
477             qemu_free(s->states[i].orig_buf);
478             s->states[i].orig_buf = NULL;
479         }
480     }
481     if (s->multi)
482         curl_multi_cleanup(s->multi);
483     if (s->url)
484         free(s->url);
485 }
486
487 static int64_t curl_getlength(BlockDriverState *bs)
488 {
489     BDRVCURLState *s = bs->opaque;
490     return s->len;
491 }
492
493 static BlockDriver bdrv_http = {
494     .format_name     = "http",
495     .protocol_name   = "http",
496
497     .instance_size   = sizeof(BDRVCURLState),
498     .bdrv_open       = curl_open,
499     .bdrv_close      = curl_close,
500     .bdrv_getlength  = curl_getlength,
501
502     .bdrv_aio_readv  = curl_aio_readv,
503 };
504
505 static BlockDriver bdrv_https = {
506     .format_name     = "https",
507     .protocol_name   = "https",
508
509     .instance_size   = sizeof(BDRVCURLState),
510     .bdrv_open       = curl_open,
511     .bdrv_close      = curl_close,
512     .bdrv_getlength  = curl_getlength,
513
514     .bdrv_aio_readv  = curl_aio_readv,
515 };
516
517 static BlockDriver bdrv_ftp = {
518     .format_name     = "ftp",
519     .protocol_name   = "ftp",
520
521     .instance_size   = sizeof(BDRVCURLState),
522     .bdrv_open       = curl_open,
523     .bdrv_close      = curl_close,
524     .bdrv_getlength  = curl_getlength,
525
526     .bdrv_aio_readv  = curl_aio_readv,
527 };
528
529 static BlockDriver bdrv_ftps = {
530     .format_name     = "ftps",
531     .protocol_name   = "ftps",
532
533     .instance_size   = sizeof(BDRVCURLState),
534     .bdrv_open       = curl_open,
535     .bdrv_close      = curl_close,
536     .bdrv_getlength  = curl_getlength,
537
538     .bdrv_aio_readv  = curl_aio_readv,
539 };
540
541 static BlockDriver bdrv_tftp = {
542     .format_name     = "tftp",
543     .protocol_name   = "tftp",
544
545     .instance_size   = sizeof(BDRVCURLState),
546     .bdrv_open       = curl_open,
547     .bdrv_close      = curl_close,
548     .bdrv_getlength  = curl_getlength,
549
550     .bdrv_aio_readv  = curl_aio_readv,
551 };
552
553 static void curl_block_init(void)
554 {
555     bdrv_register(&bdrv_http);
556     bdrv_register(&bdrv_https);
557     bdrv_register(&bdrv_ftp);
558     bdrv_register(&bdrv_ftps);
559     bdrv_register(&bdrv_tftp);
560 }
561
562 block_init(curl_block_init);