http2-upload.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 /* <DESC>
00023  * Multiplexed HTTP/2 uploads over a single connection
00024  * </DESC>
00025  */
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <fcntl.h>
00030 #include <sys/stat.h>
00031 
00032 /* somewhat unix-specific */
00033 #include <sys/time.h>
00034 #include <unistd.h>
00035 
00036 /* curl stuff */
00037 #include <curl/curl.h>
00038 
00039 #ifndef CURLPIPE_MULTIPLEX
00040 /* This little trick will just make sure that we don't enable pipelining for
00041    libcurls old enough to not have this symbol. It is _not_ defined to zero in
00042    a recent libcurl header. */
00043 #define CURLPIPE_MULTIPLEX 0
00044 #endif
00045 
00046 #define NUM_HANDLES 1000
00047 
00048 void *curl_hnd[NUM_HANDLES];
00049 int num_transfers;
00050 
00051 /* a handle to number lookup, highly ineffective when we do many
00052    transfers... */
00053 static int hnd2num(CURL *hnd)
00054 {
00055   int i;
00056   for(i=0; i< num_transfers; i++) {
00057     if(curl_hnd[i] == hnd)
00058       return i;
00059   }
00060   return 0; /* weird, but just a fail-safe */
00061 }
00062 
00063 static
00064 void dump(const char *text, int num, unsigned char *ptr, size_t size,
00065           char nohex)
00066 {
00067   size_t i;
00068   size_t c;
00069   unsigned int width=0x10;
00070 
00071   if(nohex)
00072     /* without the hex output, we can fit more on screen */
00073     width = 0x40;
00074 
00075   fprintf(stderr, "%d %s, %ld bytes (0x%lx)\n",
00076           num, text, (long)size, (long)size);
00077 
00078   for(i=0; i<size; i+= width) {
00079 
00080     fprintf(stderr, "%4.4lx: ", (long)i);
00081 
00082     if(!nohex) {
00083       /* hex not disabled, show it */
00084       for(c = 0; c < width; c++)
00085         if(i+c < size)
00086           fprintf(stderr, "%02x ", ptr[i+c]);
00087         else
00088           fputs("   ", stderr);
00089     }
00090 
00091     for(c = 0; (c < width) && (i+c < size); c++) {
00092       /* check for 0D0A; if found, skip past and start a new line of output */
00093       if(nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
00094         i+=(c+2-width);
00095         break;
00096       }
00097       fprintf(stderr, "%c",
00098               (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
00099       /* check again for 0D0A, to avoid an extra \n if it's at width */
00100       if(nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
00101         i+=(c+3-width);
00102         break;
00103       }
00104     }
00105     fputc('\n', stderr); /* newline */
00106   }
00107 }
00108 
00109 static
00110 int my_trace(CURL *handle, curl_infotype type,
00111              char *data, size_t size,
00112              void *userp)
00113 {
00114   char timebuf[20];
00115   const char *text;
00116   int num = hnd2num(handle);
00117   static time_t epoch_offset;
00118   static int    known_offset;
00119   struct timeval tv;
00120   time_t secs;
00121   struct tm *now;
00122 
00123   (void)handle; /* prevent compiler warning */
00124   (void)userp;
00125 
00126   gettimeofday(&tv, NULL);
00127   if(!known_offset) {
00128     epoch_offset = time(NULL) - tv.tv_sec;
00129     known_offset = 1;
00130   }
00131   secs = epoch_offset + tv.tv_sec;
00132   now = localtime(&secs);  /* not thread safe but we don't care */
00133   snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
00134            now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
00135 
00136   switch(type) {
00137   case CURLINFO_TEXT:
00138     fprintf(stderr, "%s [%d] Info: %s", timebuf, num, data);
00139   default: /* in case a new one is introduced to shock us */
00140     return 0;
00141 
00142   case CURLINFO_HEADER_OUT:
00143     text = "=> Send header";
00144     break;
00145   case CURLINFO_DATA_OUT:
00146     text = "=> Send data";
00147     break;
00148   case CURLINFO_SSL_DATA_OUT:
00149     text = "=> Send SSL data";
00150     break;
00151   case CURLINFO_HEADER_IN:
00152     text = "<= Recv header";
00153     break;
00154   case CURLINFO_DATA_IN:
00155     text = "<= Recv data";
00156     break;
00157   case CURLINFO_SSL_DATA_IN:
00158     text = "<= Recv SSL data";
00159     break;
00160   }
00161 
00162   dump(text, num, (unsigned char *)data, size, 1);
00163   return 0;
00164 }
00165 
00166 struct input {
00167   FILE *in;
00168   size_t bytes_read; /* count up */
00169   CURL *hnd;
00170 };
00171 
00172 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
00173 {
00174   struct input *i = userp;
00175   size_t retcode = fread(ptr, size, nmemb, i->in);
00176   i->bytes_read += retcode;
00177   return retcode;
00178 }
00179 
00180 struct input indata[NUM_HANDLES];
00181 
00182 static void setup(CURL *hnd, int num, const char *upload)
00183 {
00184   FILE *out;
00185   char url[256];
00186   char filename[128];
00187   struct stat file_info;
00188   curl_off_t uploadsize;
00189 
00190   snprintf(filename, 128, "dl-%d", num);
00191   out = fopen(filename, "wb");
00192 
00193   snprintf(url, 256, "https://localhost:8443/upload-%d", num);
00194 
00195   /* get the file size of the local file */
00196   stat(upload, &file_info);
00197   uploadsize = file_info.st_size;
00198 
00199   indata[num].in = fopen(upload, "rb");
00200   indata[num].hnd = hnd;
00201 
00202   /* write to this file */
00203   curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out);
00204 
00205   /* we want to use our own read function */
00206   curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback);
00207   /* read from this file */
00208   curl_easy_setopt(hnd, CURLOPT_READDATA, &indata[num]);
00209   /* provide the size of the upload */
00210   curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize);
00211 
00212   /* send in the URL to store the upload as */
00213   curl_easy_setopt(hnd, CURLOPT_URL, url);
00214 
00215   /* upload please */
00216   curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
00217 
00218   /* send it verbose for max debuggaility */
00219   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
00220   curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
00221 
00222   /* HTTP/2 please */
00223   curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
00224 
00225   /* we use a self-signed test server, skip verification during debugging */
00226   curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
00227   curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
00228 
00229 #if (CURLPIPE_MULTIPLEX > 0)
00230   /* wait for pipe connection to confirm */
00231   curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
00232 #endif
00233 
00234   curl_hnd[num] = hnd;
00235 }
00236 
00237 /*
00238  * Upload all files over HTTP/2, using the same physical connection!
00239  */
00240 int main(int argc, char **argv)
00241 {
00242   CURL *easy[NUM_HANDLES];
00243   CURLM *multi_handle;
00244   int i;
00245   int still_running; /* keep number of running handles */
00246   const char *filename = "index.html";
00247 
00248   if(argc > 1)
00249     /* if given a number, do that many transfers */
00250     num_transfers = atoi(argv[1]);
00251 
00252   if(argc > 2)
00253     /* if given a file name, upload this! */
00254     filename = argv[2];
00255 
00256   if(!num_transfers || (num_transfers > NUM_HANDLES))
00257     num_transfers = 3; /* a suitable low default */
00258 
00259   /* init a multi stack */
00260   multi_handle = curl_multi_init();
00261 
00262   for(i=0; i<num_transfers; i++) {
00263     easy[i] = curl_easy_init();
00264     /* set options */
00265     setup(easy[i], i, filename);
00266 
00267     /* add the individual transfer */
00268     curl_multi_add_handle(multi_handle, easy[i]);
00269   }
00270 
00271   curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
00272 
00273   /* We do HTTP/2 so let's stick to one connection per host */
00274   curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
00275 
00276   /* we start some action by calling perform right away */
00277   curl_multi_perform(multi_handle, &still_running);
00278 
00279   do {
00280     struct timeval timeout;
00281     int rc; /* select() return code */
00282     CURLMcode mc; /* curl_multi_fdset() return code */
00283 
00284     fd_set fdread;
00285     fd_set fdwrite;
00286     fd_set fdexcep;
00287     int maxfd = -1;
00288 
00289     long curl_timeo = -1;
00290 
00291     FD_ZERO(&fdread);
00292     FD_ZERO(&fdwrite);
00293     FD_ZERO(&fdexcep);
00294 
00295     /* set a suitable timeout to play around with */
00296     timeout.tv_sec = 1;
00297     timeout.tv_usec = 0;
00298 
00299     curl_multi_timeout(multi_handle, &curl_timeo);
00300     if(curl_timeo >= 0) {
00301       timeout.tv_sec = curl_timeo / 1000;
00302       if(timeout.tv_sec > 1)
00303         timeout.tv_sec = 1;
00304       else
00305         timeout.tv_usec = (curl_timeo % 1000) * 1000;
00306     }
00307 
00308     /* get file descriptors from the transfers */
00309     mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
00310 
00311     if(mc != CURLM_OK) {
00312       fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
00313       break;
00314     }
00315 
00316     /* On success the value of maxfd is guaranteed to be >= -1. We call
00317        select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
00318        no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
00319        to sleep 100ms, which is the minimum suggested value in the
00320        curl_multi_fdset() doc. */
00321 
00322     if(maxfd == -1) {
00323 #ifdef _WIN32
00324       Sleep(100);
00325       rc = 0;
00326 #else
00327       /* Portable sleep for platforms other than Windows. */
00328       struct timeval wait = { 0, 100 * 1000 }; /* 100ms */
00329       rc = select(0, NULL, NULL, NULL, &wait);
00330 #endif
00331     }
00332     else {
00333       /* Note that on some platforms 'timeout' may be modified by select().
00334          If you need access to the original value save a copy beforehand. */
00335       rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00336     }
00337 
00338     switch(rc) {
00339     case -1:
00340       /* select error */
00341       break;
00342     case 0:
00343     default:
00344       /* timeout or readable/writable sockets */
00345       curl_multi_perform(multi_handle, &still_running);
00346       break;
00347     }
00348   } while(still_running);
00349 
00350   curl_multi_cleanup(multi_handle);
00351 
00352   for(i=0; i<num_transfers; i++)
00353     curl_easy_cleanup(easy[i]);
00354 
00355   return 0;
00356 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:04