Revert "Imported Upstream version 7.53.1"
[platform/upstream/curl.git] / docs / examples / multi-uv.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, 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 https://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 /* <DESC>
24  * multi_socket API using libuv
25  * </DESC>
26  */
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..
32
33    Written by Clemens Gruber, based on an outdated example from uvbook and
34    some tests from libuv.
35
36    Requires libuv and (of course) libcurl.
37
38    See http://nikhilm.github.com/uvbook/ for more information on libuv.
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <uv.h>
44 #include <curl/curl.h>
45
46 uv_loop_t *loop;
47 CURLM *curl_handle;
48 uv_timer_t timeout;
49
50 typedef struct curl_context_s {
51   uv_poll_t poll_handle;
52   curl_socket_t sockfd;
53 } curl_context_t;
54
55 curl_context_t* create_curl_context(curl_socket_t sockfd)
56 {
57   curl_context_t *context;
58
59   context = (curl_context_t *) malloc(sizeof *context);
60
61   context->sockfd = sockfd;
62
63   uv_poll_init_socket(loop, &context->poll_handle, sockfd);
64   context->poll_handle.data = context;
65
66   return context;
67 }
68
69 void curl_close_cb(uv_handle_t *handle)
70 {
71   curl_context_t *context = (curl_context_t *) handle->data;
72   free(context);
73 }
74
75 void destroy_curl_context(curl_context_t *context)
76 {
77   uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
78 }
79
80
81 void add_download(const char *url, int num)
82 {
83   char filename[50];
84   FILE *file;
85   CURL *handle;
86
87   snprintf(filename, 50, "%d.download", num);
88
89   file = fopen(filename, "wb");
90   if(!file) {
91     fprintf(stderr, "Error opening %s\n", filename);
92     return;
93   }
94
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);
101 }
102
103 static void check_multi_info(void)
104 {
105   int running_handles;
106   char *done_url;
107   CURLMsg *message;
108   int pending;
109   FILE *file;
110
111   while((message = curl_multi_info_read(curl_handle, &pending))) {
112     switch(message->msg) {
113     case CURLMSG_DONE:
114       curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL,
115                         &done_url);
116       curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, &file);
117       printf("%s DONE\n", done_url);
118
119       curl_multi_remove_handle(curl_handle, message->easy_handle);
120       curl_easy_cleanup(message->easy_handle);
121       if(file) {
122         fclose(file);
123       }
124       break;
125
126     default:
127       fprintf(stderr, "CURLMSG default\n");
128       break;
129     }
130   }
131 }
132
133 void curl_perform(uv_poll_t *req, int status, int events)
134 {
135   int running_handles;
136   int flags = 0;
137   curl_context_t *context;
138   char *done_url;
139   CURLMsg *message;
140   int pending;
141
142   uv_timer_stop(&timeout);
143
144   if(events & UV_READABLE)
145     flags |= CURL_CSELECT_IN;
146   if(events & UV_WRITABLE)
147     flags |= CURL_CSELECT_OUT;
148
149   context = (curl_context_t *) req;
150
151   curl_multi_socket_action(curl_handle, context->sockfd, flags,
152                            &running_handles);
153
154   check_multi_info();
155 }
156
157 void on_timeout(uv_timer_t *req, int status)
158 {
159   int running_handles;
160   curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
161                            &running_handles);
162   check_multi_info();
163 }
164
165 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
166 {
167   if(timeout_ms <= 0)
168     timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
169                        a bit */
170   uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
171 }
172
173 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
174                   void *socketp)
175 {
176   curl_context_t *curl_context;
177   if(action == CURL_POLL_IN || action == CURL_POLL_OUT) {
178     if(socketp) {
179       curl_context = (curl_context_t *) socketp;
180     }
181     else {
182       curl_context = create_curl_context(s);
183     }
184     curl_multi_assign(curl_handle, s, (void *) curl_context);
185   }
186
187   switch(action) {
188   case CURL_POLL_IN:
189     uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform);
190     break;
191   case CURL_POLL_OUT:
192     uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform);
193     break;
194   case CURL_POLL_REMOVE:
195     if(socketp) {
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);
199     }
200     break;
201   default:
202     abort();
203   }
204
205   return 0;
206 }
207
208 int main(int argc, char **argv)
209 {
210   loop = uv_default_loop();
211
212   if(argc <= 1)
213     return 0;
214
215   if(curl_global_init(CURL_GLOBAL_ALL)) {
216     fprintf(stderr, "Could not init cURL\n");
217     return 1;
218   }
219
220   uv_timer_init(loop, &timeout);
221
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);
225
226   while(argc-- > 1) {
227     add_download(argv[argc], argc);
228   }
229
230   uv_run(loop, UV_RUN_DEFAULT);
231   curl_multi_cleanup(curl_handle);
232
233   return 0;
234 }