multi-uv.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 /* <DESC>
00024  * multi_socket API using libuv
00025  * </DESC>
00026  */
00027 /* Example application using the multi socket interface to download multiple
00028    files in parallel, powered by libuv.
00029 
00030    Requires libuv and (of course) libcurl.
00031 
00032    See https://nikhilm.github.com/uvbook/ for more information on libuv.
00033 */
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <uv.h>
00038 #include <curl/curl.h>
00039 
00040 uv_loop_t *loop;
00041 CURLM *curl_handle;
00042 uv_timer_t timeout;
00043 
00044 typedef struct curl_context_s {
00045   uv_poll_t poll_handle;
00046   curl_socket_t sockfd;
00047 } curl_context_t;
00048 
00049 curl_context_t* create_curl_context(curl_socket_t sockfd)
00050 {
00051   curl_context_t *context;
00052 
00053   context = (curl_context_t *) malloc(sizeof *context);
00054 
00055   context->sockfd = sockfd;
00056 
00057   uv_poll_init_socket(loop, &context->poll_handle, sockfd);
00058   context->poll_handle.data = context;
00059 
00060   return context;
00061 }
00062 
00063 void curl_close_cb(uv_handle_t *handle)
00064 {
00065   curl_context_t *context = (curl_context_t *) handle->data;
00066   free(context);
00067 }
00068 
00069 void destroy_curl_context(curl_context_t *context)
00070 {
00071   uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
00072 }
00073 
00074 void add_download(const char *url, int num)
00075 {
00076   char filename[50];
00077   FILE *file;
00078   CURL *handle;
00079 
00080   snprintf(filename, 50, "%d.download", num);
00081 
00082   file = fopen(filename, "wb");
00083   if(!file) {
00084     fprintf(stderr, "Error opening %s\n", filename);
00085     return;
00086   }
00087 
00088   handle = curl_easy_init();
00089   curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
00090   curl_easy_setopt(handle, CURLOPT_PRIVATE, file);
00091   curl_easy_setopt(handle, CURLOPT_URL, url);
00092   curl_multi_add_handle(curl_handle, handle);
00093   fprintf(stderr, "Added download %s -> %s\n", url, filename);
00094 }
00095 
00096 static void check_multi_info(void)
00097 {
00098   char *done_url;
00099   CURLMsg *message;
00100   int pending;
00101   CURL *easy_handle;
00102   FILE *file;
00103 
00104   while((message = curl_multi_info_read(curl_handle, &pending))) {
00105     switch(message->msg) {
00106     case CURLMSG_DONE:
00107       /* Do not use message data after calling curl_multi_remove_handle() and
00108          curl_easy_cleanup(). As per curl_multi_info_read() docs:
00109          "WARNING: The data the returned pointer points to will not survive
00110          calling curl_multi_cleanup, curl_multi_remove_handle or
00111          curl_easy_cleanup." */
00112       easy_handle = message->easy_handle;
00113 
00114       curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
00115       curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file);
00116       printf("%s DONE\n", done_url);
00117 
00118       curl_multi_remove_handle(curl_handle, easy_handle);
00119       curl_easy_cleanup(easy_handle);
00120       if(file) {
00121         fclose(file);
00122       }
00123       break;
00124 
00125     default:
00126       fprintf(stderr, "CURLMSG default\n");
00127       break;
00128     }
00129   }
00130 }
00131 
00132 void curl_perform(uv_poll_t *req, int status, int events)
00133 {
00134   int running_handles;
00135   int flags = 0;
00136   curl_context_t *context;
00137 
00138   uv_timer_stop(&timeout);
00139 
00140   if(events & UV_READABLE)
00141     flags |= CURL_CSELECT_IN;
00142   if(events & UV_WRITABLE)
00143     flags |= CURL_CSELECT_OUT;
00144 
00145   context = (curl_context_t *) req->data;
00146 
00147   curl_multi_socket_action(curl_handle, context->sockfd, flags,
00148                            &running_handles);
00149 
00150   check_multi_info();
00151 }
00152 
00153 void on_timeout(uv_timer_t *req, int status)
00154 {
00155   int running_handles;
00156   curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
00157                            &running_handles);
00158   check_multi_info();
00159 }
00160 
00161 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
00162 {
00163   if(timeout_ms <= 0)
00164     timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in
00165                        a bit */
00166   uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
00167 }
00168 
00169 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
00170                   void *socketp)
00171 {
00172   curl_context_t *curl_context;
00173   int events = 0;
00174 
00175   switch(action) {
00176   case CURL_POLL_IN:
00177   case CURL_POLL_OUT:
00178   case CURL_POLL_INOUT:
00179     curl_context = socketp ?
00180       (curl_context_t *) socketp : create_curl_context(s);
00181 
00182     curl_multi_assign(curl_handle, s, (void *) curl_context);
00183 
00184     if(action != CURL_POLL_IN)
00185       events |= UV_WRITABLE;
00186     if(action != CURL_POLL_OUT)
00187       events |= UV_READABLE;
00188 
00189     uv_poll_start(&curl_context->poll_handle, events, curl_perform);
00190     break;
00191   case CURL_POLL_REMOVE:
00192     if(socketp) {
00193       uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
00194       destroy_curl_context((curl_context_t*) socketp);
00195       curl_multi_assign(curl_handle, s, NULL);
00196     }
00197     break;
00198   default:
00199     abort();
00200   }
00201 
00202   return 0;
00203 }
00204 
00205 int main(int argc, char **argv)
00206 {
00207   loop = uv_default_loop();
00208 
00209   if(argc <= 1)
00210     return 0;
00211 
00212   if(curl_global_init(CURL_GLOBAL_ALL)) {
00213     fprintf(stderr, "Could not init curl\n");
00214     return 1;
00215   }
00216 
00217   uv_timer_init(loop, &timeout);
00218 
00219   curl_handle = curl_multi_init();
00220   curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
00221   curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
00222 
00223   while(argc-- > 1) {
00224     add_download(argv[argc], argc);
00225   }
00226 
00227   uv_run(loop, UV_RUN_DEFAULT);
00228   curl_multi_cleanup(curl_handle);
00229 
00230   return 0;
00231 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05