1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2015, 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 ***************************************************************************/
24 * multi_socket API using libuv
27 /* Example application code using the multi socket interface to download
28 multiple files at once, but instead of using curl_multi_perform and
29 curl_multi_wait, which uses select(), we use libuv.
30 It supports epoll, kqueue, etc. on unixes and fast IO completion ports on
31 Windows, which means, it should be very fast on all platforms..
33 Written by Clemens Gruber, based on an outdated example from uvbook and
34 some tests from libuv.
36 Requires libuv and (of course) libcurl.
38 See http://nikhilm.github.com/uvbook/ for more information on libuv.
44 #include <curl/curl.h>
50 typedef struct curl_context_s {
51 uv_poll_t poll_handle;
55 curl_context_t* create_curl_context(curl_socket_t sockfd)
57 curl_context_t *context;
59 context = (curl_context_t *) malloc(sizeof *context);
61 context->sockfd = sockfd;
63 uv_poll_init_socket(loop, &context->poll_handle, sockfd);
64 context->poll_handle.data = context;
69 void curl_close_cb(uv_handle_t *handle)
71 curl_context_t *context = (curl_context_t *) handle->data;
75 void destroy_curl_context(curl_context_t *context)
77 uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
81 void add_download(const char *url, int num)
87 sprintf(filename, "%d.download", num);
89 file = fopen(filename, "w");
91 fprintf(stderr, "Error opening %s\n", filename);
95 handle = curl_easy_init();
96 curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
97 curl_easy_setopt(handle, CURLOPT_PRIVATE, file);
98 curl_easy_setopt(handle, CURLOPT_URL, url);
99 curl_multi_add_handle(curl_handle, handle);
100 fprintf(stderr, "Added download %s -> %s\n", url, filename);
103 static void check_multi_info(void)
111 while((message = curl_multi_info_read(curl_handle, &pending))) {
112 switch(message->msg) {
114 curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL,
116 curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, &file);
117 printf("%s DONE\n", done_url);
119 curl_multi_remove_handle(curl_handle, message->easy_handle);
120 curl_easy_cleanup(message->easy_handle);
127 fprintf(stderr, "CURLMSG default\n");
133 void curl_perform(uv_poll_t *req, int status, int events)
137 curl_context_t *context;
142 uv_timer_stop(&timeout);
144 if(events & UV_READABLE)
145 flags |= CURL_CSELECT_IN;
146 if(events & UV_WRITABLE)
147 flags |= CURL_CSELECT_OUT;
149 context = (curl_context_t *) req;
151 curl_multi_socket_action(curl_handle, context->sockfd, flags,
157 void on_timeout(uv_timer_t *req, int status)
160 curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
165 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
168 timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
170 uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
173 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
176 curl_context_t *curl_context;
177 if(action == CURL_POLL_IN || action == CURL_POLL_OUT) {
179 curl_context = (curl_context_t *) socketp;
182 curl_context = create_curl_context(s);
184 curl_multi_assign(curl_handle, s, (void *) curl_context);
189 uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
192 uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
194 case CURL_POLL_REMOVE:
196 uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
197 destroy_curl_context((curl_context_t*) socketp);
198 curl_multi_assign(curl_handle, s, NULL);
208 int main(int argc, char **argv)
210 loop = uv_default_loop();
215 if(curl_global_init(CURL_GLOBAL_ALL)) {
216 fprintf(stderr, "Could not init cURL\n");
220 uv_timer_init(loop, &timeout);
222 curl_handle = curl_multi_init();
223 curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
224 curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
227 add_download(argv[argc], argc);
230 uv_run(loop, UV_RUN_DEFAULT);
231 curl_multi_cleanup(curl_handle);