00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <fcntl.h>
00030 #include <sys/stat.h>
00031
00032
00033 #include <sys/time.h>
00034 #include <unistd.h>
00035
00036
00037 #include <curl/curl.h>
00038
00039 #ifndef CURLPIPE_MULTIPLEX
00040
00041
00042
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
00052
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;
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
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
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
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
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);
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;
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);
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:
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;
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
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
00203 curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out);
00204
00205
00206 curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback);
00207
00208 curl_easy_setopt(hnd, CURLOPT_READDATA, &indata[num]);
00209
00210 curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize);
00211
00212
00213 curl_easy_setopt(hnd, CURLOPT_URL, url);
00214
00215
00216 curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
00217
00218
00219 curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
00220 curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
00221
00222
00223 curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
00224
00225
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
00231 curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
00232 #endif
00233
00234 curl_hnd[num] = hnd;
00235 }
00236
00237
00238
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;
00246 const char *filename = "index.html";
00247
00248 if(argc > 1)
00249
00250 num_transfers = atoi(argv[1]);
00251
00252 if(argc > 2)
00253
00254 filename = argv[2];
00255
00256 if(!num_transfers || (num_transfers > NUM_HANDLES))
00257 num_transfers = 3;
00258
00259
00260 multi_handle = curl_multi_init();
00261
00262 for(i=0; i<num_transfers; i++) {
00263 easy[i] = curl_easy_init();
00264
00265 setup(easy[i], i, filename);
00266
00267
00268 curl_multi_add_handle(multi_handle, easy[i]);
00269 }
00270
00271 curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
00272
00273
00274 curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
00275
00276
00277 curl_multi_perform(multi_handle, &still_running);
00278
00279 do {
00280 struct timeval timeout;
00281 int rc;
00282 CURLMcode mc;
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
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
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
00317
00318
00319
00320
00321
00322 if(maxfd == -1) {
00323 #ifdef _WIN32
00324 Sleep(100);
00325 rc = 0;
00326 #else
00327
00328 struct timeval wait = { 0, 100 * 1000 };
00329 rc = select(0, NULL, NULL, NULL, &wait);
00330 #endif
00331 }
00332 else {
00333
00334
00335 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00336 }
00337
00338 switch(rc) {
00339 case -1:
00340
00341 break;
00342 case 0:
00343 default:
00344
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 }