1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, 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_URL, url);
94 curl_multi_add_handle(curl_handle, handle);
95 fprintf(stderr, "Added download %s -> %s\n", url, filename);
98 void curl_perform(uv_poll_t *req, int status, int events)
102 curl_context_t *context;
107 uv_timer_stop(&timeout);
109 if (events & UV_READABLE)
110 flags |= CURL_CSELECT_IN;
111 if (events & UV_WRITABLE)
112 flags |= CURL_CSELECT_OUT;
114 context = (curl_context_t*)req;
116 curl_multi_socket_action(curl_handle, context->sockfd, flags,
119 while ((message = curl_multi_info_read(curl_handle, &pending))) {
120 switch (message->msg) {
122 curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL,
124 printf("%s DONE\n", done_url);
126 curl_multi_remove_handle(curl_handle, message->easy_handle);
127 curl_easy_cleanup(message->easy_handle);
131 fprintf(stderr, "CURLMSG default\n");
137 void on_timeout(uv_timer_t *req, int status)
140 curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
144 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
147 timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
149 uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
152 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
155 curl_context_t *curl_context;
156 if (action == CURL_POLL_IN || action == CURL_POLL_OUT) {
158 curl_context = (curl_context_t*) socketp;
161 curl_context = create_curl_context(s);
163 curl_multi_assign(curl_handle, s, (void *) curl_context);
168 uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
171 uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
173 case CURL_POLL_REMOVE:
175 uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
176 destroy_curl_context((curl_context_t*) socketp);
177 curl_multi_assign(curl_handle, s, NULL);
187 int main(int argc, char **argv)
189 loop = uv_default_loop();
194 if (curl_global_init(CURL_GLOBAL_ALL)) {
195 fprintf(stderr, "Could not init cURL\n");
199 uv_timer_init(loop, &timeout);
201 curl_handle = curl_multi_init();
202 curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
203 curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
206 add_download(argv[argc], argc);
209 uv_run(loop, UV_RUN_DEFAULT);
210 curl_multi_cleanup(curl_handle);