Annotation of embedaddon/curl/docs/examples/multi-event.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2019, 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 libevent
! 25: * </DESC>
! 26: */
! 27:
! 28: #include <stdio.h>
! 29: #include <stdlib.h>
! 30: #include <event2/event.h>
! 31: #include <curl/curl.h>
! 32:
! 33: struct event_base *base;
! 34: CURLM *curl_handle;
! 35: struct event *timeout;
! 36:
! 37: typedef struct curl_context_s {
! 38: struct event *event;
! 39: curl_socket_t sockfd;
! 40: } curl_context_t;
! 41:
! 42: static void curl_perform(int fd, short event, void *arg);
! 43:
! 44: static curl_context_t* create_curl_context(curl_socket_t sockfd)
! 45: {
! 46: curl_context_t *context;
! 47:
! 48: context = (curl_context_t *) malloc(sizeof(*context));
! 49:
! 50: context->sockfd = sockfd;
! 51:
! 52: context->event = event_new(base, sockfd, 0, curl_perform, context);
! 53:
! 54: return context;
! 55: }
! 56:
! 57: static void destroy_curl_context(curl_context_t *context)
! 58: {
! 59: event_del(context->event);
! 60: event_free(context->event);
! 61: free(context);
! 62: }
! 63:
! 64: static void add_download(const char *url, int num)
! 65: {
! 66: char filename[50];
! 67: FILE *file;
! 68: CURL *handle;
! 69:
! 70: snprintf(filename, 50, "%d.download", num);
! 71:
! 72: file = fopen(filename, "wb");
! 73: if(!file) {
! 74: fprintf(stderr, "Error opening %s\n", filename);
! 75: return;
! 76: }
! 77:
! 78: handle = curl_easy_init();
! 79: curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
! 80: curl_easy_setopt(handle, CURLOPT_PRIVATE, file);
! 81: curl_easy_setopt(handle, CURLOPT_URL, url);
! 82: curl_multi_add_handle(curl_handle, handle);
! 83: fprintf(stderr, "Added download %s -> %s\n", url, filename);
! 84: }
! 85:
! 86: static void check_multi_info(void)
! 87: {
! 88: char *done_url;
! 89: CURLMsg *message;
! 90: int pending;
! 91: CURL *easy_handle;
! 92: FILE *file;
! 93:
! 94: while((message = curl_multi_info_read(curl_handle, &pending))) {
! 95: switch(message->msg) {
! 96: case CURLMSG_DONE:
! 97: /* Do not use message data after calling curl_multi_remove_handle() and
! 98: curl_easy_cleanup(). As per curl_multi_info_read() docs:
! 99: "WARNING: The data the returned pointer points to will not survive
! 100: calling curl_multi_cleanup, curl_multi_remove_handle or
! 101: curl_easy_cleanup." */
! 102: easy_handle = message->easy_handle;
! 103:
! 104: curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
! 105: curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file);
! 106: printf("%s DONE\n", done_url);
! 107:
! 108: curl_multi_remove_handle(curl_handle, easy_handle);
! 109: curl_easy_cleanup(easy_handle);
! 110: if(file) {
! 111: fclose(file);
! 112: }
! 113: break;
! 114:
! 115: default:
! 116: fprintf(stderr, "CURLMSG default\n");
! 117: break;
! 118: }
! 119: }
! 120: }
! 121:
! 122: static void curl_perform(int fd, short event, void *arg)
! 123: {
! 124: int running_handles;
! 125: int flags = 0;
! 126: curl_context_t *context;
! 127:
! 128: if(event & EV_READ)
! 129: flags |= CURL_CSELECT_IN;
! 130: if(event & EV_WRITE)
! 131: flags |= CURL_CSELECT_OUT;
! 132:
! 133: context = (curl_context_t *) arg;
! 134:
! 135: curl_multi_socket_action(curl_handle, context->sockfd, flags,
! 136: &running_handles);
! 137:
! 138: check_multi_info();
! 139: }
! 140:
! 141: static void on_timeout(evutil_socket_t fd, short events, void *arg)
! 142: {
! 143: int running_handles;
! 144: curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
! 145: &running_handles);
! 146: check_multi_info();
! 147: }
! 148:
! 149: static int start_timeout(CURLM *multi, long timeout_ms, void *userp)
! 150: {
! 151: if(timeout_ms < 0) {
! 152: evtimer_del(timeout);
! 153: }
! 154: else {
! 155: if(timeout_ms == 0)
! 156: timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it
! 157: in a bit */
! 158: struct timeval tv;
! 159: tv.tv_sec = timeout_ms / 1000;
! 160: tv.tv_usec = (timeout_ms % 1000) * 1000;
! 161: evtimer_del(timeout);
! 162: evtimer_add(timeout, &tv);
! 163: }
! 164: return 0;
! 165: }
! 166:
! 167: static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
! 168: void *socketp)
! 169: {
! 170: curl_context_t *curl_context;
! 171: int events = 0;
! 172:
! 173: switch(action) {
! 174: case CURL_POLL_IN:
! 175: case CURL_POLL_OUT:
! 176: case CURL_POLL_INOUT:
! 177: curl_context = socketp ?
! 178: (curl_context_t *) socketp : create_curl_context(s);
! 179:
! 180: curl_multi_assign(curl_handle, s, (void *) curl_context);
! 181:
! 182: if(action != CURL_POLL_IN)
! 183: events |= EV_WRITE;
! 184: if(action != CURL_POLL_OUT)
! 185: events |= EV_READ;
! 186:
! 187: events |= EV_PERSIST;
! 188:
! 189: event_del(curl_context->event);
! 190: event_assign(curl_context->event, base, curl_context->sockfd, events,
! 191: curl_perform, curl_context);
! 192: event_add(curl_context->event, NULL);
! 193:
! 194: break;
! 195: case CURL_POLL_REMOVE:
! 196: if(socketp) {
! 197: event_del(((curl_context_t*) socketp)->event);
! 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: if(argc <= 1)
! 212: return 0;
! 213:
! 214: if(curl_global_init(CURL_GLOBAL_ALL)) {
! 215: fprintf(stderr, "Could not init curl\n");
! 216: return 1;
! 217: }
! 218:
! 219: base = event_base_new();
! 220: timeout = evtimer_new(base, on_timeout, NULL);
! 221:
! 222: curl_handle = curl_multi_init();
! 223: curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
! 224: curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
! 225:
! 226: while(argc-- > 1) {
! 227: add_download(argv[argc], argc);
! 228: }
! 229:
! 230: event_base_dispatch(base);
! 231:
! 232: curl_multi_cleanup(curl_handle);
! 233: event_free(timeout);
! 234: event_base_free(base);
! 235:
! 236: libevent_global_shutdown();
! 237: curl_global_cleanup();
! 238:
! 239: return 0;
! 240: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>