1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 /* Example application code using the multi socket interface to download
24 multiple files at once, but instead of using curl_multi_perform and
25 curl_multi_wait, which uses select(), we use libuv.
26 It supports epoll, kqueue, etc. on unixes and fast IO completion ports on
27 Windows, which means, it should be very fast on all platforms..
29 Written by Clemens Gruber, based on an outdated example from uvbook and
30 some tests from libuv.
32 Requires libuv and (of course) libcurl.
34 See http://nikhilm.github.com/uvbook/ for more information on libuv.
40 #include <curl/curl.h>
46 typedef struct curl_context_s {
47 uv_poll_t poll_handle;
51 curl_context_t* create_curl_context(curl_socket_t sockfd)
53 curl_context_t *context;
55 context = (curl_context_t *) malloc(sizeof *context);
57 context->sockfd = sockfd;
59 uv_poll_init_socket(loop, &context->poll_handle, sockfd);
60 context->poll_handle.data = context;
65 void curl_close_cb(uv_handle_t *handle)
67 curl_context_t *context = (curl_context_t *) handle->data;
71 void destroy_curl_context(curl_context_t *context)
73 uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
77 void add_download(const char *url, int num)
83 sprintf(filename, "%d.download", num);
85 file = fopen(filename, "w");
87 fprintf(stderr, "Error opening %s\n", filename);
91 handle = curl_easy_init();
92 curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
93 curl_easy_setopt(handle, CURLOPT_PRIVATE, file);
94 curl_easy_setopt(handle, CURLOPT_URL, url);
95 curl_multi_add_handle(curl_handle, handle);
96 fprintf(stderr, "Added download %s -> %s\n", url, filename);
99 static void check_multi_info(void)
107 while((message = curl_multi_info_read(curl_handle, &pending))) {
108 switch(message->msg) {
110 curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL,
112 curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, &file);
113 printf("%s DONE\n", done_url);
115 curl_multi_remove_handle(curl_handle, message->easy_handle);
116 curl_easy_cleanup(message->easy_handle);
123 fprintf(stderr, "CURLMSG default\n");
129 void curl_perform(uv_poll_t *req, int status, int events)
133 curl_context_t *context;
138 uv_timer_stop(&timeout);
140 if(events & UV_READABLE)
141 flags |= CURL_CSELECT_IN;
142 if(events & UV_WRITABLE)
143 flags |= CURL_CSELECT_OUT;
145 context = (curl_context_t *) req;
147 curl_multi_socket_action(curl_handle, context->sockfd, flags,
153 void on_timeout(uv_timer_t *req, int status)
156 curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
161 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
164 timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
166 uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
169 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
172 curl_context_t *curl_context;
173 if(action == CURL_POLL_IN || action == CURL_POLL_OUT) {
175 curl_context = (curl_context_t *) socketp;
178 curl_context = create_curl_context(s);
180 curl_multi_assign(curl_handle, s, (void *) curl_context);
185 uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
188 uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
190 case CURL_POLL_REMOVE:
192 uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
193 destroy_curl_context((curl_context_t*) socketp);
194 curl_multi_assign(curl_handle, s, NULL);
204 int main(int argc, char **argv)
206 loop = uv_default_loop();
211 if(curl_global_init(CURL_GLOBAL_ALL)) {
212 fprintf(stderr, "Could not init cURL\n");
216 uv_timer_init(loop, &timeout);
218 curl_handle = curl_multi_init();
219 curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
220 curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
223 add_download(argv[argc], argc);
226 uv_run(loop, UV_RUN_DEFAULT);
227 curl_multi_cleanup(curl_handle);