Annotation of embedaddon/curl/docs/examples/multi-uv.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>