113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci/* <DESC> 2513498266Sopenharmony_ci * TLS session reuse 2613498266Sopenharmony_ci * </DESC> 2713498266Sopenharmony_ci */ 2813498266Sopenharmony_ci#include <stdio.h> 2913498266Sopenharmony_ci#include <stdlib.h> 3013498266Sopenharmony_ci#include <stdint.h> 3113498266Sopenharmony_ci#include <string.h> 3213498266Sopenharmony_ci#include <inttypes.h> 3313498266Sopenharmony_ci/* #include <error.h> */ 3413498266Sopenharmony_ci#include <errno.h> 3513498266Sopenharmony_ci#include <curl/curl.h> 3613498266Sopenharmony_ci#include <curl/mprintf.h> 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci 3913498266Sopenharmony_cistatic void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) 4013498266Sopenharmony_ci{ 4113498266Sopenharmony_ci /* 4213498266Sopenharmony_ci * This is the trace look that is similar to what libcurl makes on its 4313498266Sopenharmony_ci * own. 4413498266Sopenharmony_ci */ 4513498266Sopenharmony_ci static const char * const s_infotype[] = { 4613498266Sopenharmony_ci "* ", "< ", "> ", "{ ", "} ", "{ ", "} " 4713498266Sopenharmony_ci }; 4813498266Sopenharmony_ci if(idsbuf && *idsbuf) 4913498266Sopenharmony_ci fprintf(log, "%s%s", idsbuf, s_infotype[type]); 5013498266Sopenharmony_ci else 5113498266Sopenharmony_ci fputs(s_infotype[type], log); 5213498266Sopenharmony_ci} 5313498266Sopenharmony_ci 5413498266Sopenharmony_ci#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] " 5513498266Sopenharmony_ci#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \ 5613498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T "] " 5713498266Sopenharmony_ci/* 5813498266Sopenharmony_ci** callback for CURLOPT_DEBUGFUNCTION 5913498266Sopenharmony_ci*/ 6013498266Sopenharmony_cistatic int debug_cb(CURL *handle, curl_infotype type, 6113498266Sopenharmony_ci char *data, size_t size, 6213498266Sopenharmony_ci void *userdata) 6313498266Sopenharmony_ci{ 6413498266Sopenharmony_ci FILE *output = stderr; 6513498266Sopenharmony_ci static int newl = 0; 6613498266Sopenharmony_ci static int traced_data = 0; 6713498266Sopenharmony_ci char idsbuf[60]; 6813498266Sopenharmony_ci curl_off_t xfer_id, conn_id; 6913498266Sopenharmony_ci 7013498266Sopenharmony_ci (void)handle; /* not used */ 7113498266Sopenharmony_ci (void)userdata; 7213498266Sopenharmony_ci 7313498266Sopenharmony_ci if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { 7413498266Sopenharmony_ci if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && 7513498266Sopenharmony_ci conn_id >= 0) { 7613498266Sopenharmony_ci curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, 7713498266Sopenharmony_ci xfer_id, conn_id); 7813498266Sopenharmony_ci } 7913498266Sopenharmony_ci else { 8013498266Sopenharmony_ci curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); 8113498266Sopenharmony_ci } 8213498266Sopenharmony_ci } 8313498266Sopenharmony_ci else 8413498266Sopenharmony_ci idsbuf[0] = 0; 8513498266Sopenharmony_ci 8613498266Sopenharmony_ci switch(type) { 8713498266Sopenharmony_ci case CURLINFO_HEADER_OUT: 8813498266Sopenharmony_ci if(size > 0) { 8913498266Sopenharmony_ci size_t st = 0; 9013498266Sopenharmony_ci size_t i; 9113498266Sopenharmony_ci for(i = 0; i < size - 1; i++) { 9213498266Sopenharmony_ci if(data[i] == '\n') { /* LF */ 9313498266Sopenharmony_ci if(!newl) { 9413498266Sopenharmony_ci log_line_start(output, idsbuf, type); 9513498266Sopenharmony_ci } 9613498266Sopenharmony_ci (void)fwrite(data + st, i - st + 1, 1, output); 9713498266Sopenharmony_ci st = i + 1; 9813498266Sopenharmony_ci newl = 0; 9913498266Sopenharmony_ci } 10013498266Sopenharmony_ci } 10113498266Sopenharmony_ci if(!newl) 10213498266Sopenharmony_ci log_line_start(output, idsbuf, type); 10313498266Sopenharmony_ci (void)fwrite(data + st, i - st + 1, 1, output); 10413498266Sopenharmony_ci } 10513498266Sopenharmony_ci newl = (size && (data[size - 1] != '\n')) ? 1 : 0; 10613498266Sopenharmony_ci traced_data = 0; 10713498266Sopenharmony_ci break; 10813498266Sopenharmony_ci case CURLINFO_TEXT: 10913498266Sopenharmony_ci case CURLINFO_HEADER_IN: 11013498266Sopenharmony_ci if(!newl) 11113498266Sopenharmony_ci log_line_start(output, idsbuf, type); 11213498266Sopenharmony_ci (void)fwrite(data, size, 1, output); 11313498266Sopenharmony_ci newl = (size && (data[size - 1] != '\n')) ? 1 : 0; 11413498266Sopenharmony_ci traced_data = 0; 11513498266Sopenharmony_ci break; 11613498266Sopenharmony_ci case CURLINFO_DATA_OUT: 11713498266Sopenharmony_ci case CURLINFO_DATA_IN: 11813498266Sopenharmony_ci case CURLINFO_SSL_DATA_IN: 11913498266Sopenharmony_ci case CURLINFO_SSL_DATA_OUT: 12013498266Sopenharmony_ci if(!traced_data) { 12113498266Sopenharmony_ci if(!newl) 12213498266Sopenharmony_ci log_line_start(output, idsbuf, type); 12313498266Sopenharmony_ci fprintf(output, "[%ld bytes data]\n", (long)size); 12413498266Sopenharmony_ci newl = 0; 12513498266Sopenharmony_ci traced_data = 1; 12613498266Sopenharmony_ci } 12713498266Sopenharmony_ci break; 12813498266Sopenharmony_ci default: /* nada */ 12913498266Sopenharmony_ci newl = 0; 13013498266Sopenharmony_ci traced_data = 1; 13113498266Sopenharmony_ci break; 13213498266Sopenharmony_ci } 13313498266Sopenharmony_ci 13413498266Sopenharmony_ci return 0; 13513498266Sopenharmony_ci} 13613498266Sopenharmony_ci 13713498266Sopenharmony_cistatic size_t write_cb(char *ptr, size_t size, size_t nmemb, void *opaque) 13813498266Sopenharmony_ci{ 13913498266Sopenharmony_ci (void)ptr; 14013498266Sopenharmony_ci (void)opaque; 14113498266Sopenharmony_ci return size * nmemb; 14213498266Sopenharmony_ci} 14313498266Sopenharmony_ci 14413498266Sopenharmony_cistatic void add_transfer(CURLM *multi, CURLSH *share, 14513498266Sopenharmony_ci struct curl_slist *resolve, const char *url) 14613498266Sopenharmony_ci{ 14713498266Sopenharmony_ci CURL *easy; 14813498266Sopenharmony_ci CURLMcode mc; 14913498266Sopenharmony_ci 15013498266Sopenharmony_ci easy = curl_easy_init(); 15113498266Sopenharmony_ci if(!easy) { 15213498266Sopenharmony_ci fprintf(stderr, "curl_easy_init failed\n"); 15313498266Sopenharmony_ci exit(1); 15413498266Sopenharmony_ci } 15513498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L); 15613498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_cb); 15713498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_URL, url); 15813498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_SHARE, share); 15913498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1L); 16013498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_AUTOREFERER, 1L); 16113498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L); 16213498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 16313498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb); 16413498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL); 16513498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L); 16613498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L); 16713498266Sopenharmony_ci if(resolve) 16813498266Sopenharmony_ci curl_easy_setopt(easy, CURLOPT_RESOLVE, resolve); 16913498266Sopenharmony_ci 17013498266Sopenharmony_ci 17113498266Sopenharmony_ci mc = curl_multi_add_handle(multi, easy); 17213498266Sopenharmony_ci if(mc != CURLM_OK) { 17313498266Sopenharmony_ci fprintf(stderr, "curl_multi_add_handle: %s\n", 17413498266Sopenharmony_ci curl_multi_strerror(mc)); 17513498266Sopenharmony_ci exit(1); 17613498266Sopenharmony_ci } 17713498266Sopenharmony_ci} 17813498266Sopenharmony_ci 17913498266Sopenharmony_ciint main(int argc, char *argv[]) 18013498266Sopenharmony_ci{ 18113498266Sopenharmony_ci const char *url; 18213498266Sopenharmony_ci CURLM *multi; 18313498266Sopenharmony_ci CURLMcode mc; 18413498266Sopenharmony_ci int running_handles = 0, numfds; 18513498266Sopenharmony_ci CURLMsg *msg; 18613498266Sopenharmony_ci CURLSH *share; 18713498266Sopenharmony_ci CURLU *cu; 18813498266Sopenharmony_ci struct curl_slist resolve; 18913498266Sopenharmony_ci char resolve_buf[1024]; 19013498266Sopenharmony_ci int msgs_in_queue; 19113498266Sopenharmony_ci int add_more, waits, ongoing = 0; 19213498266Sopenharmony_ci char *host, *port; 19313498266Sopenharmony_ci 19413498266Sopenharmony_ci if(argc != 2) { 19513498266Sopenharmony_ci fprintf(stderr, "%s URL\n", argv[0]); 19613498266Sopenharmony_ci exit(2); 19713498266Sopenharmony_ci } 19813498266Sopenharmony_ci 19913498266Sopenharmony_ci url = argv[1]; 20013498266Sopenharmony_ci cu = curl_url(); 20113498266Sopenharmony_ci if(!cu) { 20213498266Sopenharmony_ci fprintf(stderr, "out of memory\n"); 20313498266Sopenharmony_ci exit(1); 20413498266Sopenharmony_ci } 20513498266Sopenharmony_ci if(curl_url_set(cu, CURLUPART_URL, url, 0)) { 20613498266Sopenharmony_ci fprintf(stderr, "not a URL: '%s'\n", url); 20713498266Sopenharmony_ci exit(1); 20813498266Sopenharmony_ci } 20913498266Sopenharmony_ci if(curl_url_get(cu, CURLUPART_HOST, &host, 0)) { 21013498266Sopenharmony_ci fprintf(stderr, "could not get host of '%s'\n", url); 21113498266Sopenharmony_ci exit(1); 21213498266Sopenharmony_ci } 21313498266Sopenharmony_ci if(curl_url_get(cu, CURLUPART_PORT, &port, 0)) { 21413498266Sopenharmony_ci fprintf(stderr, "could not get port of '%s'\n", url); 21513498266Sopenharmony_ci exit(1); 21613498266Sopenharmony_ci } 21713498266Sopenharmony_ci 21813498266Sopenharmony_ci memset(&resolve, 0, sizeof(resolve)); 21913498266Sopenharmony_ci curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, 22013498266Sopenharmony_ci "%s:%s:127.0.0.1", host, port); 22113498266Sopenharmony_ci curl_slist_append(&resolve, resolve_buf); 22213498266Sopenharmony_ci 22313498266Sopenharmony_ci multi = curl_multi_init(); 22413498266Sopenharmony_ci if(!multi) { 22513498266Sopenharmony_ci fprintf(stderr, "curl_multi_init failed\n"); 22613498266Sopenharmony_ci exit(1); 22713498266Sopenharmony_ci } 22813498266Sopenharmony_ci 22913498266Sopenharmony_ci share = curl_share_init(); 23013498266Sopenharmony_ci if(!share) { 23113498266Sopenharmony_ci fprintf(stderr, "curl_share_init failed\n"); 23213498266Sopenharmony_ci exit(1); 23313498266Sopenharmony_ci } 23413498266Sopenharmony_ci curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); 23513498266Sopenharmony_ci 23613498266Sopenharmony_ci 23713498266Sopenharmony_ci add_transfer(multi, share, &resolve, url); 23813498266Sopenharmony_ci ++ongoing; 23913498266Sopenharmony_ci add_more = 6; 24013498266Sopenharmony_ci waits = 3; 24113498266Sopenharmony_ci do { 24213498266Sopenharmony_ci mc = curl_multi_perform(multi, &running_handles); 24313498266Sopenharmony_ci if(mc != CURLM_OK) { 24413498266Sopenharmony_ci fprintf(stderr, "curl_multi_perform: %s\n", 24513498266Sopenharmony_ci curl_multi_strerror(mc)); 24613498266Sopenharmony_ci exit(1); 24713498266Sopenharmony_ci } 24813498266Sopenharmony_ci 24913498266Sopenharmony_ci if(running_handles) { 25013498266Sopenharmony_ci mc = curl_multi_poll(multi, NULL, 0, 1000000, &numfds); 25113498266Sopenharmony_ci if(mc != CURLM_OK) { 25213498266Sopenharmony_ci fprintf(stderr, "curl_multi_poll: %s\n", 25313498266Sopenharmony_ci curl_multi_strerror(mc)); 25413498266Sopenharmony_ci exit(1); 25513498266Sopenharmony_ci } 25613498266Sopenharmony_ci } 25713498266Sopenharmony_ci 25813498266Sopenharmony_ci if(waits) { 25913498266Sopenharmony_ci --waits; 26013498266Sopenharmony_ci } 26113498266Sopenharmony_ci else { 26213498266Sopenharmony_ci while(add_more) { 26313498266Sopenharmony_ci add_transfer(multi, share, &resolve, url); 26413498266Sopenharmony_ci ++ongoing; 26513498266Sopenharmony_ci --add_more; 26613498266Sopenharmony_ci } 26713498266Sopenharmony_ci } 26813498266Sopenharmony_ci 26913498266Sopenharmony_ci /* Check for finished handles and remove. */ 27013498266Sopenharmony_ci while((msg = curl_multi_info_read(multi, &msgs_in_queue))) { 27113498266Sopenharmony_ci if(msg->msg == CURLMSG_DONE) { 27213498266Sopenharmony_ci long status = 0; 27313498266Sopenharmony_ci curl_off_t xfer_id; 27413498266Sopenharmony_ci curl_easy_getinfo(msg->easy_handle, CURLINFO_XFER_ID, &xfer_id); 27513498266Sopenharmony_ci curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &status); 27613498266Sopenharmony_ci if(msg->data.result == CURLE_SEND_ERROR || 27713498266Sopenharmony_ci msg->data.result == CURLE_RECV_ERROR) { 27813498266Sopenharmony_ci /* We get these if the server had a GOAWAY in transit on 27913498266Sopenharmony_ci * re-using a connection */ 28013498266Sopenharmony_ci } 28113498266Sopenharmony_ci else if(msg->data.result) { 28213498266Sopenharmony_ci fprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T 28313498266Sopenharmony_ci ": failed with %d\n", xfer_id, msg->data.result); 28413498266Sopenharmony_ci exit(1); 28513498266Sopenharmony_ci } 28613498266Sopenharmony_ci else if(status != 200) { 28713498266Sopenharmony_ci fprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T 28813498266Sopenharmony_ci ": wrong http status %ld (expected 200)\n", xfer_id, status); 28913498266Sopenharmony_ci exit(1); 29013498266Sopenharmony_ci } 29113498266Sopenharmony_ci curl_multi_remove_handle(multi, msg->easy_handle); 29213498266Sopenharmony_ci curl_easy_cleanup(msg->easy_handle); 29313498266Sopenharmony_ci --ongoing; 29413498266Sopenharmony_ci fprintf(stderr, "transfer #%" CURL_FORMAT_CURL_OFF_T" retiring " 29513498266Sopenharmony_ci "(%d now running)\n", xfer_id, running_handles); 29613498266Sopenharmony_ci } 29713498266Sopenharmony_ci } 29813498266Sopenharmony_ci 29913498266Sopenharmony_ci fprintf(stderr, "running_handles=%d, yet_to_start=%d\n", 30013498266Sopenharmony_ci running_handles, add_more); 30113498266Sopenharmony_ci 30213498266Sopenharmony_ci } while(ongoing || add_more); 30313498266Sopenharmony_ci 30413498266Sopenharmony_ci fprintf(stderr, "exiting\n"); 30513498266Sopenharmony_ci exit(EXIT_SUCCESS); 30613498266Sopenharmony_ci} 307