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