1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker /* <DESC>
25*6236dae4SAndroid Build Coastguard Worker * Multiplexed HTTP/2 uploads over a single connection
26*6236dae4SAndroid Build Coastguard Worker * </DESC>
27*6236dae4SAndroid Build Coastguard Worker */
28*6236dae4SAndroid Build Coastguard Worker #include <stdio.h>
29*6236dae4SAndroid Build Coastguard Worker #include <stdlib.h>
30*6236dae4SAndroid Build Coastguard Worker #include <string.h>
31*6236dae4SAndroid Build Coastguard Worker #include <fcntl.h>
32*6236dae4SAndroid Build Coastguard Worker #include <sys/stat.h>
33*6236dae4SAndroid Build Coastguard Worker #include <errno.h>
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Worker /* somewhat Unix-specific */
36*6236dae4SAndroid Build Coastguard Worker #ifndef _MSC_VER
37*6236dae4SAndroid Build Coastguard Worker #include <sys/time.h>
38*6236dae4SAndroid Build Coastguard Worker #include <unistd.h>
39*6236dae4SAndroid Build Coastguard Worker #endif
40*6236dae4SAndroid Build Coastguard Worker
41*6236dae4SAndroid Build Coastguard Worker /* curl stuff */
42*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
43*6236dae4SAndroid Build Coastguard Worker #include <curl/mprintf.h>
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Worker #ifndef CURLPIPE_MULTIPLEX
46*6236dae4SAndroid Build Coastguard Worker /* This little trick makes sure that we do not enable pipelining for libcurls
47*6236dae4SAndroid Build Coastguard Worker old enough to not have this symbol. It is _not_ defined to zero in a recent
48*6236dae4SAndroid Build Coastguard Worker libcurl header. */
49*6236dae4SAndroid Build Coastguard Worker #define CURLPIPE_MULTIPLEX 0
50*6236dae4SAndroid Build Coastguard Worker #endif
51*6236dae4SAndroid Build Coastguard Worker
52*6236dae4SAndroid Build Coastguard Worker #define NUM_HANDLES 1000
53*6236dae4SAndroid Build Coastguard Worker
54*6236dae4SAndroid Build Coastguard Worker #ifdef _MSC_VER
55*6236dae4SAndroid Build Coastguard Worker #define gettimeofday(a, b) my_gettimeofday((a), (b))
56*6236dae4SAndroid Build Coastguard Worker static
my_gettimeofday(struct timeval * tp,void * tzp)57*6236dae4SAndroid Build Coastguard Worker int my_gettimeofday(struct timeval *tp, void *tzp)
58*6236dae4SAndroid Build Coastguard Worker {
59*6236dae4SAndroid Build Coastguard Worker (void)tzp;
60*6236dae4SAndroid Build Coastguard Worker if(tp) {
61*6236dae4SAndroid Build Coastguard Worker /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */
62*6236dae4SAndroid Build Coastguard Worker #define _WIN32_FT_OFFSET (116444736000000000)
63*6236dae4SAndroid Build Coastguard Worker union {
64*6236dae4SAndroid Build Coastguard Worker CURL_TYPEOF_CURL_OFF_T ns100; /* time since 1 Jan 1601 in 100ns units */
65*6236dae4SAndroid Build Coastguard Worker FILETIME ft;
66*6236dae4SAndroid Build Coastguard Worker } _now;
67*6236dae4SAndroid Build Coastguard Worker GetSystemTimeAsFileTime(&_now.ft);
68*6236dae4SAndroid Build Coastguard Worker tp->tv_usec = (long)((_now.ns100 / 10) % 1000000);
69*6236dae4SAndroid Build Coastguard Worker tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000);
70*6236dae4SAndroid Build Coastguard Worker }
71*6236dae4SAndroid Build Coastguard Worker return 0;
72*6236dae4SAndroid Build Coastguard Worker }
73*6236dae4SAndroid Build Coastguard Worker #endif
74*6236dae4SAndroid Build Coastguard Worker
75*6236dae4SAndroid Build Coastguard Worker struct input {
76*6236dae4SAndroid Build Coastguard Worker FILE *in;
77*6236dae4SAndroid Build Coastguard Worker size_t bytes_read; /* count up */
78*6236dae4SAndroid Build Coastguard Worker CURL *hnd;
79*6236dae4SAndroid Build Coastguard Worker int num;
80*6236dae4SAndroid Build Coastguard Worker };
81*6236dae4SAndroid Build Coastguard Worker
82*6236dae4SAndroid Build Coastguard Worker static
dump(const char * text,int num,unsigned char * ptr,size_t size,char nohex)83*6236dae4SAndroid Build Coastguard Worker void dump(const char *text, int num, unsigned char *ptr, size_t size,
84*6236dae4SAndroid Build Coastguard Worker char nohex)
85*6236dae4SAndroid Build Coastguard Worker {
86*6236dae4SAndroid Build Coastguard Worker size_t i;
87*6236dae4SAndroid Build Coastguard Worker size_t c;
88*6236dae4SAndroid Build Coastguard Worker unsigned int width = 0x10;
89*6236dae4SAndroid Build Coastguard Worker
90*6236dae4SAndroid Build Coastguard Worker if(nohex)
91*6236dae4SAndroid Build Coastguard Worker /* without the hex output, we can fit more on screen */
92*6236dae4SAndroid Build Coastguard Worker width = 0x40;
93*6236dae4SAndroid Build Coastguard Worker
94*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%d %s, %lu bytes (0x%lx)\n",
95*6236dae4SAndroid Build Coastguard Worker num, text, (unsigned long)size, (unsigned long)size);
96*6236dae4SAndroid Build Coastguard Worker
97*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < size; i += width) {
98*6236dae4SAndroid Build Coastguard Worker
99*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%4.4lx: ", (unsigned long)i);
100*6236dae4SAndroid Build Coastguard Worker
101*6236dae4SAndroid Build Coastguard Worker if(!nohex) {
102*6236dae4SAndroid Build Coastguard Worker /* hex not disabled, show it */
103*6236dae4SAndroid Build Coastguard Worker for(c = 0; c < width; c++)
104*6236dae4SAndroid Build Coastguard Worker if(i + c < size)
105*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%02x ", ptr[i + c]);
106*6236dae4SAndroid Build Coastguard Worker else
107*6236dae4SAndroid Build Coastguard Worker fputs(" ", stderr);
108*6236dae4SAndroid Build Coastguard Worker }
109*6236dae4SAndroid Build Coastguard Worker
110*6236dae4SAndroid Build Coastguard Worker for(c = 0; (c < width) && (i + c < size); c++) {
111*6236dae4SAndroid Build Coastguard Worker /* check for 0D0A; if found, skip past and start a new line of output */
112*6236dae4SAndroid Build Coastguard Worker if(nohex && (i + c + 1 < size) && ptr[i + c] == 0x0D &&
113*6236dae4SAndroid Build Coastguard Worker ptr[i + c + 1] == 0x0A) {
114*6236dae4SAndroid Build Coastguard Worker i += (c + 2 - width);
115*6236dae4SAndroid Build Coastguard Worker break;
116*6236dae4SAndroid Build Coastguard Worker }
117*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%c",
118*6236dae4SAndroid Build Coastguard Worker (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.');
119*6236dae4SAndroid Build Coastguard Worker /* check again for 0D0A, to avoid an extra \n if it's at width */
120*6236dae4SAndroid Build Coastguard Worker if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D &&
121*6236dae4SAndroid Build Coastguard Worker ptr[i + c + 2] == 0x0A) {
122*6236dae4SAndroid Build Coastguard Worker i += (c + 3 - width);
123*6236dae4SAndroid Build Coastguard Worker break;
124*6236dae4SAndroid Build Coastguard Worker }
125*6236dae4SAndroid Build Coastguard Worker }
126*6236dae4SAndroid Build Coastguard Worker fputc('\n', stderr); /* newline */
127*6236dae4SAndroid Build Coastguard Worker }
128*6236dae4SAndroid Build Coastguard Worker }
129*6236dae4SAndroid Build Coastguard Worker
130*6236dae4SAndroid Build Coastguard Worker static
my_trace(CURL * handle,curl_infotype type,char * data,size_t size,void * userp)131*6236dae4SAndroid Build Coastguard Worker int my_trace(CURL *handle, curl_infotype type,
132*6236dae4SAndroid Build Coastguard Worker char *data, size_t size,
133*6236dae4SAndroid Build Coastguard Worker void *userp)
134*6236dae4SAndroid Build Coastguard Worker {
135*6236dae4SAndroid Build Coastguard Worker char timebuf[60];
136*6236dae4SAndroid Build Coastguard Worker const char *text;
137*6236dae4SAndroid Build Coastguard Worker struct input *i = (struct input *)userp;
138*6236dae4SAndroid Build Coastguard Worker int num = i->num;
139*6236dae4SAndroid Build Coastguard Worker static time_t epoch_offset;
140*6236dae4SAndroid Build Coastguard Worker static int known_offset;
141*6236dae4SAndroid Build Coastguard Worker struct timeval tv;
142*6236dae4SAndroid Build Coastguard Worker time_t secs;
143*6236dae4SAndroid Build Coastguard Worker struct tm *now;
144*6236dae4SAndroid Build Coastguard Worker (void)handle; /* prevent compiler warning */
145*6236dae4SAndroid Build Coastguard Worker
146*6236dae4SAndroid Build Coastguard Worker gettimeofday(&tv, NULL);
147*6236dae4SAndroid Build Coastguard Worker if(!known_offset) {
148*6236dae4SAndroid Build Coastguard Worker epoch_offset = time(NULL) - tv.tv_sec;
149*6236dae4SAndroid Build Coastguard Worker known_offset = 1;
150*6236dae4SAndroid Build Coastguard Worker }
151*6236dae4SAndroid Build Coastguard Worker secs = epoch_offset + tv.tv_sec;
152*6236dae4SAndroid Build Coastguard Worker now = localtime(&secs); /* not thread safe but we do not care */
153*6236dae4SAndroid Build Coastguard Worker curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
154*6236dae4SAndroid Build Coastguard Worker now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
155*6236dae4SAndroid Build Coastguard Worker
156*6236dae4SAndroid Build Coastguard Worker switch(type) {
157*6236dae4SAndroid Build Coastguard Worker case CURLINFO_TEXT:
158*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%s [%d] Info: %s", timebuf, num, data);
159*6236dae4SAndroid Build Coastguard Worker return 0;
160*6236dae4SAndroid Build Coastguard Worker case CURLINFO_HEADER_OUT:
161*6236dae4SAndroid Build Coastguard Worker text = "=> Send header";
162*6236dae4SAndroid Build Coastguard Worker break;
163*6236dae4SAndroid Build Coastguard Worker case CURLINFO_DATA_OUT:
164*6236dae4SAndroid Build Coastguard Worker text = "=> Send data";
165*6236dae4SAndroid Build Coastguard Worker break;
166*6236dae4SAndroid Build Coastguard Worker case CURLINFO_SSL_DATA_OUT:
167*6236dae4SAndroid Build Coastguard Worker text = "=> Send SSL data";
168*6236dae4SAndroid Build Coastguard Worker break;
169*6236dae4SAndroid Build Coastguard Worker case CURLINFO_HEADER_IN:
170*6236dae4SAndroid Build Coastguard Worker text = "<= Recv header";
171*6236dae4SAndroid Build Coastguard Worker break;
172*6236dae4SAndroid Build Coastguard Worker case CURLINFO_DATA_IN:
173*6236dae4SAndroid Build Coastguard Worker text = "<= Recv data";
174*6236dae4SAndroid Build Coastguard Worker break;
175*6236dae4SAndroid Build Coastguard Worker case CURLINFO_SSL_DATA_IN:
176*6236dae4SAndroid Build Coastguard Worker text = "<= Recv SSL data";
177*6236dae4SAndroid Build Coastguard Worker break;
178*6236dae4SAndroid Build Coastguard Worker default: /* in case a new one is introduced to shock us */
179*6236dae4SAndroid Build Coastguard Worker return 0;
180*6236dae4SAndroid Build Coastguard Worker }
181*6236dae4SAndroid Build Coastguard Worker
182*6236dae4SAndroid Build Coastguard Worker dump(text, num, (unsigned char *)data, size, 1);
183*6236dae4SAndroid Build Coastguard Worker return 0;
184*6236dae4SAndroid Build Coastguard Worker }
185*6236dae4SAndroid Build Coastguard Worker
read_callback(char * ptr,size_t size,size_t nmemb,void * userp)186*6236dae4SAndroid Build Coastguard Worker static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp)
187*6236dae4SAndroid Build Coastguard Worker {
188*6236dae4SAndroid Build Coastguard Worker struct input *i = userp;
189*6236dae4SAndroid Build Coastguard Worker size_t retcode = fread(ptr, size, nmemb, i->in);
190*6236dae4SAndroid Build Coastguard Worker i->bytes_read += retcode;
191*6236dae4SAndroid Build Coastguard Worker return retcode;
192*6236dae4SAndroid Build Coastguard Worker }
193*6236dae4SAndroid Build Coastguard Worker
setup(struct input * i,int num,const char * upload)194*6236dae4SAndroid Build Coastguard Worker static void setup(struct input *i, int num, const char *upload)
195*6236dae4SAndroid Build Coastguard Worker {
196*6236dae4SAndroid Build Coastguard Worker FILE *out;
197*6236dae4SAndroid Build Coastguard Worker char url[256];
198*6236dae4SAndroid Build Coastguard Worker char filename[128];
199*6236dae4SAndroid Build Coastguard Worker struct stat file_info;
200*6236dae4SAndroid Build Coastguard Worker curl_off_t uploadsize;
201*6236dae4SAndroid Build Coastguard Worker CURL *hnd;
202*6236dae4SAndroid Build Coastguard Worker
203*6236dae4SAndroid Build Coastguard Worker hnd = i->hnd = curl_easy_init();
204*6236dae4SAndroid Build Coastguard Worker i->num = num;
205*6236dae4SAndroid Build Coastguard Worker curl_msnprintf(filename, 128, "dl-%d", num);
206*6236dae4SAndroid Build Coastguard Worker out = fopen(filename, "wb");
207*6236dae4SAndroid Build Coastguard Worker if(!out) {
208*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "error: could not open file %s for writing: %s\n", upload,
209*6236dae4SAndroid Build Coastguard Worker strerror(errno));
210*6236dae4SAndroid Build Coastguard Worker exit(1);
211*6236dae4SAndroid Build Coastguard Worker }
212*6236dae4SAndroid Build Coastguard Worker
213*6236dae4SAndroid Build Coastguard Worker curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num);
214*6236dae4SAndroid Build Coastguard Worker
215*6236dae4SAndroid Build Coastguard Worker /* get the file size of the local file */
216*6236dae4SAndroid Build Coastguard Worker if(stat(upload, &file_info)) {
217*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "error: could not stat file %s: %s\n", upload,
218*6236dae4SAndroid Build Coastguard Worker strerror(errno));
219*6236dae4SAndroid Build Coastguard Worker exit(1);
220*6236dae4SAndroid Build Coastguard Worker }
221*6236dae4SAndroid Build Coastguard Worker
222*6236dae4SAndroid Build Coastguard Worker uploadsize = file_info.st_size;
223*6236dae4SAndroid Build Coastguard Worker
224*6236dae4SAndroid Build Coastguard Worker i->in = fopen(upload, "rb");
225*6236dae4SAndroid Build Coastguard Worker if(!i->in) {
226*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "error: could not open file %s for reading: %s\n", upload,
227*6236dae4SAndroid Build Coastguard Worker strerror(errno));
228*6236dae4SAndroid Build Coastguard Worker exit(1);
229*6236dae4SAndroid Build Coastguard Worker }
230*6236dae4SAndroid Build Coastguard Worker
231*6236dae4SAndroid Build Coastguard Worker /* write to this file */
232*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out);
233*6236dae4SAndroid Build Coastguard Worker
234*6236dae4SAndroid Build Coastguard Worker /* we want to use our own read function */
235*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback);
236*6236dae4SAndroid Build Coastguard Worker /* read from this file */
237*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_READDATA, i);
238*6236dae4SAndroid Build Coastguard Worker /* provide the size of the upload */
239*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize);
240*6236dae4SAndroid Build Coastguard Worker
241*6236dae4SAndroid Build Coastguard Worker /* send in the URL to store the upload as */
242*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_URL, url);
243*6236dae4SAndroid Build Coastguard Worker
244*6236dae4SAndroid Build Coastguard Worker /* upload please */
245*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
246*6236dae4SAndroid Build Coastguard Worker
247*6236dae4SAndroid Build Coastguard Worker /* please be verbose */
248*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
249*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
250*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, i);
251*6236dae4SAndroid Build Coastguard Worker
252*6236dae4SAndroid Build Coastguard Worker /* HTTP/2 please */
253*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
254*6236dae4SAndroid Build Coastguard Worker
255*6236dae4SAndroid Build Coastguard Worker /* we use a self-signed test server, skip verification during debugging */
256*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
257*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
258*6236dae4SAndroid Build Coastguard Worker
259*6236dae4SAndroid Build Coastguard Worker #if (CURLPIPE_MULTIPLEX > 0)
260*6236dae4SAndroid Build Coastguard Worker /* wait for pipe connection to confirm */
261*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
262*6236dae4SAndroid Build Coastguard Worker #endif
263*6236dae4SAndroid Build Coastguard Worker }
264*6236dae4SAndroid Build Coastguard Worker
265*6236dae4SAndroid Build Coastguard Worker /*
266*6236dae4SAndroid Build Coastguard Worker * Upload all files over HTTP/2, using the same physical connection!
267*6236dae4SAndroid Build Coastguard Worker */
main(int argc,char ** argv)268*6236dae4SAndroid Build Coastguard Worker int main(int argc, char **argv)
269*6236dae4SAndroid Build Coastguard Worker {
270*6236dae4SAndroid Build Coastguard Worker struct input trans[NUM_HANDLES];
271*6236dae4SAndroid Build Coastguard Worker CURLM *multi_handle;
272*6236dae4SAndroid Build Coastguard Worker int i;
273*6236dae4SAndroid Build Coastguard Worker int still_running = 0; /* keep number of running handles */
274*6236dae4SAndroid Build Coastguard Worker const char *filename = "index.html";
275*6236dae4SAndroid Build Coastguard Worker int num_transfers;
276*6236dae4SAndroid Build Coastguard Worker
277*6236dae4SAndroid Build Coastguard Worker if(argc > 1) {
278*6236dae4SAndroid Build Coastguard Worker /* if given a number, do that many transfers */
279*6236dae4SAndroid Build Coastguard Worker num_transfers = atoi(argv[1]);
280*6236dae4SAndroid Build Coastguard Worker
281*6236dae4SAndroid Build Coastguard Worker if(!num_transfers || (num_transfers > NUM_HANDLES))
282*6236dae4SAndroid Build Coastguard Worker num_transfers = 3; /* a suitable low default */
283*6236dae4SAndroid Build Coastguard Worker
284*6236dae4SAndroid Build Coastguard Worker if(argc > 2)
285*6236dae4SAndroid Build Coastguard Worker /* if given a file name, upload this! */
286*6236dae4SAndroid Build Coastguard Worker filename = argv[2];
287*6236dae4SAndroid Build Coastguard Worker }
288*6236dae4SAndroid Build Coastguard Worker else
289*6236dae4SAndroid Build Coastguard Worker num_transfers = 3;
290*6236dae4SAndroid Build Coastguard Worker
291*6236dae4SAndroid Build Coastguard Worker /* init a multi stack */
292*6236dae4SAndroid Build Coastguard Worker multi_handle = curl_multi_init();
293*6236dae4SAndroid Build Coastguard Worker
294*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < num_transfers; i++) {
295*6236dae4SAndroid Build Coastguard Worker setup(&trans[i], i, filename);
296*6236dae4SAndroid Build Coastguard Worker
297*6236dae4SAndroid Build Coastguard Worker /* add the individual transfer */
298*6236dae4SAndroid Build Coastguard Worker curl_multi_add_handle(multi_handle, trans[i].hnd);
299*6236dae4SAndroid Build Coastguard Worker }
300*6236dae4SAndroid Build Coastguard Worker
301*6236dae4SAndroid Build Coastguard Worker curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
302*6236dae4SAndroid Build Coastguard Worker
303*6236dae4SAndroid Build Coastguard Worker /* We do HTTP/2 so let's stick to one connection per host */
304*6236dae4SAndroid Build Coastguard Worker curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
305*6236dae4SAndroid Build Coastguard Worker
306*6236dae4SAndroid Build Coastguard Worker do {
307*6236dae4SAndroid Build Coastguard Worker CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
308*6236dae4SAndroid Build Coastguard Worker
309*6236dae4SAndroid Build Coastguard Worker if(still_running)
310*6236dae4SAndroid Build Coastguard Worker /* wait for activity, timeout or "nothing" */
311*6236dae4SAndroid Build Coastguard Worker mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
312*6236dae4SAndroid Build Coastguard Worker
313*6236dae4SAndroid Build Coastguard Worker if(mc)
314*6236dae4SAndroid Build Coastguard Worker break;
315*6236dae4SAndroid Build Coastguard Worker
316*6236dae4SAndroid Build Coastguard Worker } while(still_running);
317*6236dae4SAndroid Build Coastguard Worker
318*6236dae4SAndroid Build Coastguard Worker curl_multi_cleanup(multi_handle);
319*6236dae4SAndroid Build Coastguard Worker
320*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < num_transfers; i++) {
321*6236dae4SAndroid Build Coastguard Worker curl_multi_remove_handle(multi_handle, trans[i].hnd);
322*6236dae4SAndroid Build Coastguard Worker curl_easy_cleanup(trans[i].hnd);
323*6236dae4SAndroid Build Coastguard Worker }
324*6236dae4SAndroid Build Coastguard Worker
325*6236dae4SAndroid Build Coastguard Worker return 0;
326*6236dae4SAndroid Build Coastguard Worker }
327