Annotation of embedaddon/curl/docs/examples/multi-uv.c, revision 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>