Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/docs/examples/multi-uv.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 } |
