Return to http2-download.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / docs / examples |
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: /* <DESC> ! 23: * Multiplexed HTTP/2 downloads over a single connection ! 24: * </DESC> ! 25: */ ! 26: #include <stdio.h> ! 27: #include <stdlib.h> ! 28: #include <string.h> ! 29: ! 30: /* somewhat unix-specific */ ! 31: #include <sys/time.h> ! 32: #include <unistd.h> ! 33: ! 34: /* curl stuff */ ! 35: #include <curl/curl.h> ! 36: ! 37: #ifndef CURLPIPE_MULTIPLEX ! 38: /* This little trick will just make sure that we don't enable pipelining for ! 39: libcurls old enough to not have this symbol. It is _not_ defined to zero in ! 40: a recent libcurl header. */ ! 41: #define CURLPIPE_MULTIPLEX 0 ! 42: #endif ! 43: ! 44: struct transfer { ! 45: CURL *easy; ! 46: unsigned int num; ! 47: FILE *out; ! 48: }; ! 49: ! 50: #define NUM_HANDLES 1000 ! 51: ! 52: static ! 53: void dump(const char *text, int num, unsigned char *ptr, size_t size, ! 54: char nohex) ! 55: { ! 56: size_t i; ! 57: size_t c; ! 58: ! 59: unsigned int width = 0x10; ! 60: ! 61: if(nohex) ! 62: /* without the hex output, we can fit more on screen */ ! 63: width = 0x40; ! 64: ! 65: fprintf(stderr, "%d %s, %lu bytes (0x%lx)\n", ! 66: num, text, (unsigned long)size, (unsigned long)size); ! 67: ! 68: for(i = 0; i<size; i += width) { ! 69: ! 70: fprintf(stderr, "%4.4lx: ", (unsigned long)i); ! 71: ! 72: if(!nohex) { ! 73: /* hex not disabled, show it */ ! 74: for(c = 0; c < width; c++) ! 75: if(i + c < size) ! 76: fprintf(stderr, "%02x ", ptr[i + c]); ! 77: else ! 78: fputs(" ", stderr); ! 79: } ! 80: ! 81: for(c = 0; (c < width) && (i + c < size); c++) { ! 82: /* check for 0D0A; if found, skip past and start a new line of output */ ! 83: if(nohex && (i + c + 1 < size) && ptr[i + c] == 0x0D && ! 84: ptr[i + c + 1] == 0x0A) { ! 85: i += (c + 2 - width); ! 86: break; ! 87: } ! 88: fprintf(stderr, "%c", ! 89: (ptr[i + c] >= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); ! 90: /* check again for 0D0A, to avoid an extra \n if it's at width */ ! 91: if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && ! 92: ptr[i + c + 2] == 0x0A) { ! 93: i += (c + 3 - width); ! 94: break; ! 95: } ! 96: } ! 97: fputc('\n', stderr); /* newline */ ! 98: } ! 99: } ! 100: ! 101: static ! 102: int my_trace(CURL *handle, curl_infotype type, ! 103: char *data, size_t size, ! 104: void *userp) ! 105: { ! 106: const char *text; ! 107: struct transfer *t = (struct transfer *)userp; ! 108: unsigned int num = t->num; ! 109: (void)handle; /* prevent compiler warning */ ! 110: ! 111: switch(type) { ! 112: case CURLINFO_TEXT: ! 113: fprintf(stderr, "== %u Info: %s", num, data); ! 114: /* FALLTHROUGH */ ! 115: default: /* in case a new one is introduced to shock us */ ! 116: return 0; ! 117: ! 118: case CURLINFO_HEADER_OUT: ! 119: text = "=> Send header"; ! 120: break; ! 121: case CURLINFO_DATA_OUT: ! 122: text = "=> Send data"; ! 123: break; ! 124: case CURLINFO_SSL_DATA_OUT: ! 125: text = "=> Send SSL data"; ! 126: break; ! 127: case CURLINFO_HEADER_IN: ! 128: text = "<= Recv header"; ! 129: break; ! 130: case CURLINFO_DATA_IN: ! 131: text = "<= Recv data"; ! 132: break; ! 133: case CURLINFO_SSL_DATA_IN: ! 134: text = "<= Recv SSL data"; ! 135: break; ! 136: } ! 137: ! 138: dump(text, num, (unsigned char *)data, size, 1); ! 139: return 0; ! 140: } ! 141: ! 142: static void setup(struct transfer *t, int num) ! 143: { ! 144: char filename[128]; ! 145: CURL *hnd; ! 146: ! 147: hnd = t->easy = curl_easy_init(); ! 148: ! 149: snprintf(filename, 128, "dl-%d", num); ! 150: ! 151: t->out = fopen(filename, "wb"); ! 152: ! 153: /* write to this file */ ! 154: curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t->out); ! 155: ! 156: /* set the same URL */ ! 157: curl_easy_setopt(hnd, CURLOPT_URL, "https://localhost:8443/index.html"); ! 158: ! 159: /* please be verbose */ ! 160: curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); ! 161: curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); ! 162: curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, t); ! 163: ! 164: /* HTTP/2 please */ ! 165: curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); ! 166: ! 167: /* we use a self-signed test server, skip verification during debugging */ ! 168: curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); ! 169: curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); ! 170: ! 171: #if (CURLPIPE_MULTIPLEX > 0) ! 172: /* wait for pipe connection to confirm */ ! 173: curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); ! 174: #endif ! 175: } ! 176: ! 177: /* ! 178: * Download many transfers over HTTP/2, using the same connection! ! 179: */ ! 180: int main(int argc, char **argv) ! 181: { ! 182: struct transfer trans[NUM_HANDLES]; ! 183: CURLM *multi_handle; ! 184: int i; ! 185: int still_running = 0; /* keep number of running handles */ ! 186: int num_transfers; ! 187: if(argc > 1) { ! 188: /* if given a number, do that many transfers */ ! 189: num_transfers = atoi(argv[1]); ! 190: if((num_transfers < 1) || (num_transfers > NUM_HANDLES)) ! 191: num_transfers = 3; /* a suitable low default */ ! 192: } ! 193: else ! 194: num_transfers = 3; /* suitable default */ ! 195: ! 196: /* init a multi stack */ ! 197: multi_handle = curl_multi_init(); ! 198: ! 199: for(i = 0; i < num_transfers; i++) { ! 200: setup(&trans[i], i); ! 201: ! 202: /* add the individual transfer */ ! 203: curl_multi_add_handle(multi_handle, trans[i].easy); ! 204: } ! 205: ! 206: curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); ! 207: ! 208: /* we start some action by calling perform right away */ ! 209: curl_multi_perform(multi_handle, &still_running); ! 210: ! 211: while(still_running) { ! 212: struct timeval timeout; ! 213: int rc; /* select() return code */ ! 214: CURLMcode mc; /* curl_multi_fdset() return code */ ! 215: ! 216: fd_set fdread; ! 217: fd_set fdwrite; ! 218: fd_set fdexcep; ! 219: int maxfd = -1; ! 220: ! 221: long curl_timeo = -1; ! 222: ! 223: FD_ZERO(&fdread); ! 224: FD_ZERO(&fdwrite); ! 225: FD_ZERO(&fdexcep); ! 226: ! 227: /* set a suitable timeout to play around with */ ! 228: timeout.tv_sec = 1; ! 229: timeout.tv_usec = 0; ! 230: ! 231: curl_multi_timeout(multi_handle, &curl_timeo); ! 232: if(curl_timeo >= 0) { ! 233: timeout.tv_sec = curl_timeo / 1000; ! 234: if(timeout.tv_sec > 1) ! 235: timeout.tv_sec = 1; ! 236: else ! 237: timeout.tv_usec = (curl_timeo % 1000) * 1000; ! 238: } ! 239: ! 240: /* get file descriptors from the transfers */ ! 241: mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); ! 242: ! 243: if(mc != CURLM_OK) { ! 244: fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); ! 245: break; ! 246: } ! 247: ! 248: /* On success the value of maxfd is guaranteed to be >= -1. We call ! 249: select(maxfd + 1, ...); specially in case of (maxfd == -1) there are ! 250: no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- ! 251: to sleep 100ms, which is the minimum suggested value in the ! 252: curl_multi_fdset() doc. */ ! 253: ! 254: if(maxfd == -1) { ! 255: #ifdef _WIN32 ! 256: Sleep(100); ! 257: rc = 0; ! 258: #else ! 259: /* Portable sleep for platforms other than Windows. */ ! 260: struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ ! 261: rc = select(0, NULL, NULL, NULL, &wait); ! 262: #endif ! 263: } ! 264: else { ! 265: /* Note that on some platforms 'timeout' may be modified by select(). ! 266: If you need access to the original value save a copy beforehand. */ ! 267: rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); ! 268: } ! 269: ! 270: switch(rc) { ! 271: case -1: ! 272: /* select error */ ! 273: break; ! 274: case 0: ! 275: default: ! 276: /* timeout or readable/writable sockets */ ! 277: curl_multi_perform(multi_handle, &still_running); ! 278: break; ! 279: } ! 280: } ! 281: ! 282: for(i = 0; i < num_transfers; i++) { ! 283: curl_multi_remove_handle(multi_handle, trans[i].easy); ! 284: curl_easy_cleanup(trans[i].easy); ! 285: } ! 286: ! 287: curl_multi_cleanup(multi_handle); ! 288: ! 289: return 0; ! 290: }