From 142755fa5cdd2fea72c68663bfefeb9c6ccf5315 Mon Sep 17 00:00:00 2001 From: Clemens Gruber Date: Tue, 26 Mar 2013 23:22:30 +0100 Subject: Added libuv example multi-uv.c --- docs/examples/Makefile.inc | 3 +- docs/examples/README | 1 + docs/examples/multi-uv.c | 213 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 docs/examples/multi-uv.c (limited to 'docs') diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc index 9aabfcabd..2ce561305 100644 --- a/docs/examples/Makefile.inc +++ b/docs/examples/Makefile.inc @@ -12,4 +12,5 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface debug fileupload \ COMPLICATED_EXAMPLES = curlgtk.c curlx.c htmltitle.cpp cacertinmem.c \ ftpuploadresume.c ghiper.c hiperfifo.c htmltidy.c multithread.c \ opensslthreadlock.c sampleconv.c synctime.c threaded-ssl.c evhiperfifo.c \ - smooth-gtk-thread.c version-check.pl href_extractor.c asiohiper.cpp + smooth-gtk-thread.c version-check.pl href_extractor.c asiohiper.cpp \ + multi-uv.c diff --git a/docs/examples/README b/docs/examples/README index 270048a6c..b89338f62 100644 --- a/docs/examples/README +++ b/docs/examples/README @@ -61,6 +61,7 @@ multi-debugcallback.c - a multi-interface app using the debug callback multi-double.c - a multi-interface app doing two simultaneous transfers multi-post.c - a multi-interface app doing a multipart formpost multi-single.c - a multi-interface app getting a single file +multi-uv.c - a multi-interface app using libuv multithread.c - an example using multi-treading transferring multiple files opensslthreadlock.c - show how to do locking when using OpenSSL multi-threaded persistant.c - request two URLs with a persistent connection diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c new file mode 100644 index 000000000..564be2d48 --- /dev/null +++ b/docs/examples/multi-uv.c @@ -0,0 +1,213 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* Example application code using the multi socket interface to download + multiple files at once, but instead of using curl_multi_perform and + curl_multi_wait, which uses select(), we use libuv. + It supports epoll, kqueue, etc. on unixes and fast IO completion ports on + Windows, which means, it should be very fast on all platforms.. + + Written by Clemens Gruber, based on an outdated example from uvbook and + some tests from libuv. + + Requires libuv and (of course) libcurl. + + See http://nikhilm.github.com/uvbook/ for more information on libuv. +*/ + +#include +#include +#include +#include + +uv_loop_t *loop; +CURLM *curl_handle; +uv_timer_t timeout; + +typedef struct curl_context_s { + uv_poll_t poll_handle; + curl_socket_t sockfd; +} curl_context_t; + +curl_context_t* create_curl_context(curl_socket_t sockfd) +{ + int r; + curl_context_t *context; + + context = (curl_context_t *) malloc(sizeof *context); + + context->sockfd = sockfd; + + r = uv_poll_init_socket(loop, &context->poll_handle, sockfd); + context->poll_handle.data = context; + + return context; +} + +void curl_close_cb(uv_handle_t *handle) +{ + curl_context_t* context = (curl_context_t*) handle->data; + free(context); +} + +void destroy_curl_context(curl_context_t *context) +{ + uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb); +} + + +void add_download(const char *url, int num) +{ + char filename[50]; + FILE *file; + CURL *handle; + + sprintf(filename, "%d.download", num); + + file = fopen(filename, "w"); + if (file == NULL) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +void curl_perform(uv_poll_t *req, int status, int events) +{ + int running_handles; + int flags = 0; + curl_context_t *context; + char *done_url; + CURLMsg *message; + int pending; + + uv_timer_stop(&timeout); + + if (events & UV_READABLE) + flags |= CURL_CSELECT_IN; + if (events & UV_WRITABLE) + flags |= CURL_CSELECT_OUT; + + context = (curl_context_t*)req; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, + &running_handles); + + while ((message = curl_multi_info_read(curl_handle, &pending))) { + switch (message->msg) { + case CURLMSG_DONE: + curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, + &done_url); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, message->easy_handle); + curl_easy_cleanup(message->easy_handle); + + break; + default: + fprintf(stderr, "CURLMSG default\n"); + abort(); + } + } +} + +void on_timeout(uv_timer_t *req, int status) +{ + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, + &running_handles); +} + +void start_timeout(CURLM *multi, long timeout_ms, void *userp) +{ + if (timeout_ms <= 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in + a bit */ + uv_timer_start(&timeout, on_timeout, timeout_ms, 0); +} + +int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, + void *socketp) +{ + curl_context_t *curl_context; + if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { + if (socketp) { + curl_context = (curl_context_t*) socketp; + } + else { + curl_context = create_curl_context(s); + } + curl_multi_assign(curl_handle, s, (void *) curl_context); + } + + switch (action) { + case CURL_POLL_IN: + uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform); + break; + case CURL_POLL_OUT: + uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform); + break; + case CURL_POLL_REMOVE: + if (socketp) { + uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) +{ + loop = uv_default_loop(); + + if (argc <= 1) + return 0; + + if (curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init cURL\n"); + return 1; + } + + uv_timer_init(loop, &timeout); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while (argc-- > 1) { + add_download(argv[argc], argc); + } + + uv_run(loop, UV_RUN_DEFAULT); + curl_multi_cleanup(curl_handle); + return 0; +} -- cgit v1.2.3