57d712fcfaac486ed18f59f5e792206ea8b05c9d
[platform/upstream/curl.git] / docs / examples / multi-uv.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
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..
28
29    Written by Clemens Gruber, based on an outdated example from uvbook and
30    some tests from libuv.
31
32    Requires libuv and (of course) libcurl.
33
34    See http://nikhilm.github.com/uvbook/ for more information on libuv.
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <uv.h>
40 #include <curl/curl.h>
41
42 uv_loop_t *loop;
43 CURLM *curl_handle;
44 uv_timer_t timeout;
45
46 typedef struct curl_context_s {
47   uv_poll_t poll_handle;
48   curl_socket_t sockfd;
49 } curl_context_t;
50
51 curl_context_t* create_curl_context(curl_socket_t sockfd)
52 {
53   curl_context_t *context;
54
55   context = (curl_context_t *) malloc(sizeof *context);
56
57   context->sockfd = sockfd;
58
59   uv_poll_init_socket(loop, &context->poll_handle, sockfd);
60   context->poll_handle.data = context;
61
62   return context;
63 }
64
65 void curl_close_cb(uv_handle_t *handle)
66 {
67   curl_context_t* context = (curl_context_t*) handle->data;
68   free(context);
69 }
70
71 void destroy_curl_context(curl_context_t *context)
72 {
73   uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb);
74 }
75
76
77 void add_download(const char *url, int num)
78 {
79   char filename[50];
80   FILE *file;
81   CURL *handle;
82
83   sprintf(filename, "%d.download", num);
84
85   file = fopen(filename, "w");
86   if (file == NULL) {
87     fprintf(stderr, "Error opening %s\n", filename);
88     return;
89   }
90
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);
96 }
97
98 void curl_perform(uv_poll_t *req, int status, int events)
99 {
100   int running_handles;
101   int flags = 0;
102   curl_context_t *context;
103   char *done_url;
104   CURLMsg *message;
105   int pending;
106
107   uv_timer_stop(&timeout);
108
109   if (events & UV_READABLE)
110     flags |= CURL_CSELECT_IN;
111   if (events & UV_WRITABLE)
112     flags |= CURL_CSELECT_OUT;
113
114   context = (curl_context_t*)req;
115
116   curl_multi_socket_action(curl_handle, context->sockfd, flags,
117                            &running_handles);
118
119   while ((message = curl_multi_info_read(curl_handle, &pending))) {
120     switch (message->msg) {
121     case CURLMSG_DONE:
122       curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL,
123                         &done_url);
124       printf("%s DONE\n", done_url);
125
126       curl_multi_remove_handle(curl_handle, message->easy_handle);
127       curl_easy_cleanup(message->easy_handle);
128
129       break;
130     default:
131       fprintf(stderr, "CURLMSG default\n");
132       abort();
133     }
134   }
135 }
136
137 void on_timeout(uv_timer_t *req, int status)
138 {
139   int running_handles;
140   curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
141                            &running_handles);
142 }
143
144 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
145 {
146   if (timeout_ms <= 0)
147     timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
148                        a bit */
149   uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
150 }
151
152 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
153                   void *socketp)
154 {
155   curl_context_t *curl_context;
156   if (action == CURL_POLL_IN || action == CURL_POLL_OUT) {
157     if (socketp) {
158       curl_context = (curl_context_t*) socketp;
159     }
160     else {
161       curl_context = create_curl_context(s);
162     }
163     curl_multi_assign(curl_handle, s, (void *) curl_context);
164   }
165
166   switch (action) {
167   case CURL_POLL_IN:
168     uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
169     break;
170   case CURL_POLL_OUT:
171     uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
172     break;
173   case CURL_POLL_REMOVE:
174     if (socketp) {
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);
178     }
179     break;
180   default:
181     abort();
182   }
183
184   return 0;
185 }
186
187 int main(int argc, char **argv)
188 {
189   loop = uv_default_loop();
190
191   if (argc <= 1)
192     return 0;
193
194   if (curl_global_init(CURL_GLOBAL_ALL)) {
195     fprintf(stderr, "Could not init cURL\n");
196     return 1;
197   }
198
199   uv_timer_init(loop, &timeout);
200
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);
204
205   while (argc-- > 1) {
206     add_download(argv[argc], argc);
207   }
208
209   uv_run(loop, UV_RUN_DEFAULT);
210   curl_multi_cleanup(curl_handle);
211   return 0;
212 }