xref: /aosp_15_r20/external/curl/docs/examples/http2-upload.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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