"Fossies" - the Fresh Open Source Software Archive

Member "HTTPing-2.9/main.c" (29 Oct 2022, 57788 Bytes) of package /linux/www/HTTPing-2.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 /* Released under AGPL v3 with exception for the OpenSSL library. See license.txt */
    2 
    3 #define _GNU_SOURCE
    4 #include <sys/ioctl.h>
    5 #include <stdio.h>
    6 #include <locale.h>
    7 #include <libintl.h>
    8 #include <stdlib.h>
    9 #include <errno.h>
   10 #include <math.h>
   11 #include <string.h>
   12 #include <signal.h>
   13 #include <unistd.h>
   14 #include <getopt.h>
   15 #include <sys/types.h>
   16 #include <sys/socket.h>
   17 #include <sys/ioctl.h>
   18 #include <netinet/in.h>
   19 #include <netinet/tcp.h>
   20 #include <netdb.h>
   21 #ifndef NO_SSL
   22 #include <openssl/ssl.h>
   23 #include "mssl.h"
   24 #endif
   25 #include <arpa/inet.h>
   26 #include <time.h>
   27 #include <sys/time.h>
   28 #if defined(sun) || defined(__sun)
   29 #include <sys/termios.h>
   30 #endif
   31 #ifdef NC
   32 #include <ncurses.h>
   33 #endif
   34 
   35 #include "gen.h"
   36 #include "help.h"
   37 #include "colors.h"
   38 #include "http.h"
   39 #include "io.h"
   40 #include "tcp.h"
   41 #include "res.h"
   42 #include "utils.h"
   43 #include "error.h"
   44 #include "socks5.h"
   45 #ifdef NC
   46 #include "nc.h"
   47 #endif
   48 #include "cookies.h"
   49 
   50 volatile int stop = 0;
   51 
   52 int quiet = 0;
   53 char machine_readable = 0;
   54 char json_output = 0;
   55 char show_ts = 0;
   56 
   57 int max_x = 80, max_y = 24;
   58 
   59 char nagios_mode = 0;
   60 char ncurses_mode = 0;
   61 
   62 int fd = -1;
   63 
   64 volatile char got_sigquit = 0;
   65 
   66 void handler_quit(int s)
   67 {
   68     signal(SIGQUIT, handler_quit);
   69 
   70     got_sigquit = 1;
   71 }
   72 
   73 void determine_terminal_size(int *max_y, int *max_x)
   74 {
   75         struct winsize size;
   76 
   77         *max_x = *max_y = 0;
   78 
   79     if (!isatty(1))
   80     {
   81         *max_y = 24;
   82         *max_x = 80;
   83     }
   84 #ifdef TIOCGWINSZ
   85         else if (ioctl(1, TIOCGWINSZ, &size) == 0)
   86         {
   87                 *max_y = size.ws_row;
   88                 *max_x = size.ws_col;
   89         }
   90 #endif
   91 
   92         if (!*max_x || !*max_y)
   93         {
   94                 char *dummy = getenv("COLUMNS");
   95                 if (dummy)
   96                         *max_x = atoi(dummy);
   97                 else
   98                         *max_x = 80;
   99 
  100                 dummy = getenv("LINES");
  101                 if (dummy)
  102                         *max_y = atoi(dummy);
  103                 else
  104                         *max_y = 24;
  105         }
  106 }
  107 
  108 void emit_statuslines(double run_time)
  109 {
  110 #ifdef NC
  111     if (ncurses_mode)
  112     {
  113         time_t t = time(NULL);
  114         char *t_str = ctime(&t);
  115         char *dummy = strchr(t_str, '\n');
  116 
  117         if (dummy)
  118             *dummy = 0x00;
  119 
  120         status_line(gettext("%s, run time: %.3fs, press ctrl + c to stop"), t_str, run_time);
  121     }
  122 #else
  123     (void)run_time;
  124 #endif
  125 }
  126 
  127 void emit_headers(char *in)
  128 {
  129 #ifdef NC
  130     static char shown = 0;
  131     int len_in = -1;
  132 
  133     if (!shown && ncurses_mode && in != NULL && (len_in = strlen(in) - 4) > 0)
  134     {
  135         int pos = 0, pos_out = 0;
  136         char *copy = (char *)malloc(len_in + 1), *dummy = NULL;
  137 
  138         for(pos=0; pos<len_in; pos++)
  139         {
  140             if (in[pos] != '\r')
  141                 copy[pos_out++] = in[pos];
  142         }
  143 
  144         copy[pos_out] = 0x00;
  145 
  146         /* in case more than the headers were sent */
  147         dummy = strstr(copy, "\n\n");
  148         if (dummy)
  149             *dummy = 0x00;
  150 
  151         slow_log("\n%s", copy);
  152 
  153         free(copy);
  154 
  155         shown = 1;
  156     }
  157 #else
  158     (void)in;
  159 #endif
  160 }
  161 
  162 void emit_json(char ok, int seq, double start_ts, stats_t *t_resolve, stats_t *t_connect, stats_t *t_request, int http_code, const char *msg, int header_size, int data_size, double Bps, const char *host, const char *ssl_fp, double toff_diff_ts, char tfo_success, stats_t *t_ssl, stats_t *t_write, stats_t *t_close, int n_cookies, stats_t *stats_to, stats_t *tcp_rtt_stats, int re_tx, int pmtu, int recv_tos, stats_t *t_total)
  163 {
  164     if (seq > 1)
  165         printf(", \n");
  166     printf("{ ");
  167     printf("\"status\" : \"%d\", ", ok);
  168     printf("\"seq\" : \"%d\", ", seq);
  169     printf("\"start_ts\" : \"%f\", ", start_ts);
  170     if (t_resolve!=NULL && t_resolve -> cur_valid)
  171         printf("\"resolve_ms\" : \"%e\", ", t_resolve -> cur);
  172     else
  173         printf("\"resolve_ms\" : \"%e\", ",-1.0);
  174     if (t_connect!=NULL && t_connect -> cur_valid)
  175         printf("\"connect_ms\" : \"%e\", ", t_connect -> cur);
  176     else
  177         printf("\"connect_ms\" : \"%e\", ",-1.0);
  178     if (t_request != NULL)
  179         printf("\"request_ms\" : \"%e\", ", t_request -> cur);
  180     if (t_total != NULL)
  181         printf("\"total_ms\" : \"%e\", ", t_total -> cur);
  182     printf("\"http_code\" : \"%d\", ", http_code);
  183     printf("\"msg\" : \"%s\", ", msg);
  184     printf("\"header_size\" : \"%d\", ", header_size);
  185     printf("\"data_size\" : \"%d\", ", data_size);
  186     printf("\"bps\" : \"%f\", ", Bps);
  187     printf("\"host\" : \"%s\", ", host);
  188     printf("\"ssl_fingerprint\" : \"%s\", ", ssl_fp ? ssl_fp : "");
  189     printf("\"time_offset\" : \"%f\", ", toff_diff_ts);
  190     printf("\"tfo_success\" : \"%s\", ", tfo_success ? "true" : "false");
  191     if (t_ssl != NULL && t_ssl -> cur_valid)
  192         printf("\"ssl_ms\" : \"%e\", ", t_ssl -> cur);
  193     printf("\"tfo_succes\" : \"%s\", ", tfo_success ? "true" : "false");
  194     if (t_ssl !=NULL && t_ssl -> cur_valid)
  195         printf("\"ssl_ms\" : \"%e\", ", t_ssl -> cur);
  196     if (t_write != NULL)
  197         printf("\"write\" : \"%e\", ", t_write -> cur);
  198     if (t_close != NULL)
  199         printf("\"close\" : \"%e\", ", t_close -> cur);
  200     printf("\"cookies\" : \"%d\", ", n_cookies);
  201     if (stats_to != NULL && stats_to -> cur_valid)
  202         printf("\"to\" : \"%e\", ", stats_to -> cur);
  203     if (tcp_rtt_stats !=NULL && tcp_rtt_stats -> cur_valid)
  204         printf("\"tcp_rtt_stats\" : \"%e\", ", tcp_rtt_stats -> cur);
  205     printf("\"re_tx\" : \"%d\", ", re_tx);
  206     printf("\"pmtu\" : \"%d\", ", pmtu);
  207     printf("\"tos\" : \"%02x\" ", recv_tos);
  208     printf("}");
  209 }
  210 
  211 char *get_ts_str(int verbose)
  212 {
  213     char buffer[4096] = { 0 };
  214     struct tm *tvm = NULL;
  215     struct timeval tv;
  216 
  217     (void)gettimeofday(&tv, NULL);
  218 
  219     tvm = localtime(&tv.tv_sec);
  220 
  221     if (verbose == 1)
  222         sprintf(buffer, "%04d/%02d/%02d ", tvm -> tm_year + 1900, tvm -> tm_mon + 1, tvm -> tm_mday);
  223     else if (verbose >= 2)
  224         sprintf(buffer, "%.6f", get_ts());
  225 
  226     if (verbose <= 1)
  227         sprintf(&buffer[strlen(buffer)], "%02d:%02d:%02d.%03d", tvm -> tm_hour, tvm -> tm_min, tvm -> tm_sec, (int)(tv.tv_usec / 1000));
  228 
  229     return strdup(buffer);
  230 }
  231 
  232 void emit_error(int verbose, int seq, double start_ts)
  233 {
  234     char *ts = show_ts ? get_ts_str(verbose) : NULL;
  235 
  236 #ifdef NC
  237     if (ncurses_mode)
  238     {
  239         slow_log("\n%s%s", ts ? ts : "", get_error());
  240         update_terminal();
  241     }
  242     else
  243 #endif
  244         if (!quiet && !machine_readable && !nagios_mode && !json_output)
  245             printf("%s%s%s%s\n", ts ? ts : "", c_error, get_error(), c_normal);
  246 
  247     if (json_output)
  248         emit_json(0, seq, start_ts, NULL, NULL, NULL, -1, get_error(), -1, -1, -1, "", "", -1, 0, NULL, NULL, NULL, 0, NULL, NULL, 0, 0, 0, NULL);
  249 
  250     clear_error();
  251 
  252     free(ts);
  253 
  254     fflush(NULL);
  255 }
  256 
  257 void handler(int sig)
  258 {
  259 #ifdef NC
  260     if (sig == SIGWINCH)
  261         win_resize = 1;
  262     else
  263 #endif
  264     {
  265         if (!json_output)
  266             fprintf(stderr, gettext("Got signal %d\n"), sig);
  267 
  268         stop = 1;
  269     }
  270 }
  271 
  272 char * read_file(const char *file)
  273 {
  274     char buffer[4096] = { 0 }, *lf = NULL;
  275     FILE *fh = fopen(file, "rb");
  276     if (!fh)
  277         error_exit(gettext("Cannot open password-file %s"), file);
  278 
  279     if (!fgets(buffer, sizeof buffer, fh))
  280         error_exit(gettext("Problem reading password from file %s"), file);
  281 
  282     fclose(fh);
  283 
  284     lf = strchr(buffer, '\n');
  285     if (lf)
  286         *lf = 0x00;
  287 
  288     return strdup(buffer);
  289 }
  290 
  291 char * create_http_request_header(const char *get, char use_proxy_host, char get_instead_of_head, char persistent_connections, const char *hostname, const char *useragent, const char *referer, char ask_compression, char no_cache, const char *auth_usr, const char *auth_password, char **static_cookies, int n_static_cookies, char **dynamic_cookies, int n_dynamic_cookies, const char *proxy_buster, const char *proxy_user, const char *proxy_password, char **additional_headers, int n_additional_headers, char http2, char is_ssl)
  292 {
  293     int index;
  294     char *request = NULL;
  295     char pb[128] = { 0 };
  296 
  297     if (proxy_buster)
  298     {
  299         if (strchr(get, '?'))
  300             pb[0] = '&';
  301         else
  302             pb[0] = '?';
  303 
  304         snprintf(pb + 1, sizeof pb - 1, "%s=%ld", proxy_buster, lrand48());
  305     }
  306 
  307     if (use_proxy_host)
  308         str_add(&request, "%s %s%s HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", get, pb, persistent_connections || http2 ? '1':'0');
  309     else
  310     {
  311         const char *dummy = get, *slash = NULL;
  312         if (strncasecmp(dummy, "http://", 7) == 0)
  313             dummy += 7;
  314         else if (strncasecmp(dummy, "https://", 7) == 0)
  315             dummy += 8;
  316 
  317         slash = strchr(dummy, '/');
  318         if (slash)
  319             str_add(&request, "%s %s HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", slash, persistent_connections || http2?'1':'0');
  320         else
  321             str_add(&request, "%s / HTTP/1.%c\r\n", get_instead_of_head?"GET":"HEAD", persistent_connections || http2 ? '1':'0');
  322     }
  323 
  324     if (hostname)
  325         str_add(&request, "Host: %s\r\n", hostname);
  326 
  327     if (useragent)
  328         str_add(&request, "User-Agent: %s\r\n", useragent);
  329     else
  330         str_add(&request, "User-Agent: HTTPing v" VERSION "\r\n");
  331 
  332     if (referer)
  333         str_add(&request, "Referer: %s\r\n", referer);
  334 
  335     if (ask_compression)
  336         str_add(&request, "Accept-Encoding: gzip,deflate\r\n");
  337 
  338     if (http2) {
  339         str_add(&request, "Connection: Upgrade, HTTP2-Settings\r\n");
  340         if (is_ssl) // https
  341             str_add(&request, "Upgrade: h2\r\n");
  342         else
  343             str_add(&request, "Upgrade: h2c\r\n");
  344         str_add(&request, "HTTP2-Settings: \r\n");
  345     }
  346 
  347     if (no_cache)
  348     {
  349         str_add(&request, "Pragma: no-cache\r\n");
  350         str_add(&request, "Cache-Control: no-cache\r\n");
  351     }
  352 
  353     /* Basic Authentification */
  354     if (auth_usr)
  355     { 
  356         char auth_string[256] = { 0 };
  357         char b64_auth_string[512] = { 0 };
  358 
  359         sprintf(auth_string, "%s:%s", auth_usr, auth_password); 
  360         enc_b64(auth_string, strlen(auth_string), b64_auth_string);
  361 
  362         str_add(&request, "Authorization: Basic %s\r\n", b64_auth_string);
  363     }
  364 
  365     /* proxy authentication */
  366     if (proxy_user)
  367     { 
  368         char ppa_string[256] = { 0 };
  369         char b64_ppa_string[512] = { 0 };
  370 
  371         sprintf(ppa_string, "%s:%s", proxy_user, proxy_password); 
  372         enc_b64(ppa_string, strlen(ppa_string), b64_ppa_string);
  373 
  374         str_add(&request, "Proxy-Authorization: Basic %s\r\n", b64_ppa_string);
  375     }
  376 
  377     /* Cookie insertion */
  378     for(index=0; index<n_static_cookies; index++)
  379         str_add(&request, "Cookie: %s\r\n", static_cookies[index]);
  380     for(index=0; index<n_dynamic_cookies; index++)
  381         str_add(&request, "Cookie: %s\r\n", dynamic_cookies[index]);
  382 
  383     for(index=0; index<n_additional_headers; index++)
  384         str_add(&request, "%s\r\n", additional_headers[index]);
  385 
  386     if (persistent_connections)
  387         str_add(&request, "Connection: keep-alive\r\n");
  388 
  389     str_add(&request, "\r\n");
  390 
  391     return request;
  392 }
  393 
  394 void interpret_url(const char *in, char **path, char **hostname, int *portnr, char use_ipv6, char use_ssl, char **complete_url, char **auth_user, char **auth_password)
  395 {
  396     char in_use[65536] = { 0 }, *dummy = NULL;
  397 
  398     if (strlen(in) >= sizeof in_use)
  399         error_exit(gettext("URL too big, HTTPing has a %d bytes limit"), sizeof in_use - 1);
  400 
  401     /* make url complete, if not already */
  402     if (strncasecmp(in, "http://", 7) == 0 || strncasecmp(in, "https://", 8) == 0) /* complete url? */
  403     {
  404         snprintf(in_use, sizeof in_use - 1, "%s", in);
  405 
  406         if (strchr(&in[8], '/') == NULL)
  407             in_use[strlen(in_use)] = '/';
  408     }
  409     else if (strchr(in, '/')) /* hostname + location without 'http://'? */
  410         sprintf(in_use, "http://%s", in);
  411     else if (use_ssl)
  412         sprintf(in_use, "https://%s/", in);
  413     else
  414         sprintf(in_use, "http://%s/", in);
  415 
  416     /* sanity check */
  417     if (strncasecmp(in_use, "http://", 7) == 0 && use_ssl)
  418         error_exit(gettext("using \"http://\" with SSL enabled (-l)"));
  419 
  420     *complete_url = strdup(in_use);
  421 
  422     /* fetch hostname */
  423     if (strncasecmp(in_use, "http://", 7) == 0)
  424         *hostname = strdup(&in_use[7]);
  425     else /* https */
  426         *hostname = strdup(&in_use[8]);
  427 
  428     dummy = strchr(*hostname, '/');
  429     if (dummy)
  430         *dummy = 0x00;
  431 
  432     /* fetch port number */
  433     if (use_ssl || strncasecmp(in, "https://", 8) == 0)
  434         *portnr = 443;
  435     else
  436         *portnr = 80;
  437 
  438     if (!use_ipv6)
  439     {
  440         char *at = strchr(*hostname, '@');
  441         char *colon = strchr(*hostname, ':');
  442         char *colon2 = colon ? strchr(colon + 1, ':') : NULL;
  443 
  444         if (colon2)
  445         {
  446             *colon2 = 0x00;
  447             *portnr = atoi(colon2 + 1);
  448 
  449             if (at)
  450             {
  451                 *colon = 0x00;
  452                 *at = 0x00;
  453 
  454                 *auth_user = strdup(*hostname);
  455                 *auth_password = strdup(colon + 1);
  456             }
  457         }
  458         else if (colon)
  459         {
  460             if (colon < at)
  461             {
  462                 *colon = 0x00;
  463                 *at = 0x00;
  464 
  465                 *auth_user = strdup(*hostname);
  466                 *auth_password = strdup(colon + 1);
  467             }
  468             else if (at)
  469             {
  470                 *at = 0x00;
  471                 *auth_user = strdup(*hostname);
  472             }
  473             else
  474             {
  475                 *colon = 0x00;
  476                 *portnr = atoi(colon + 1);
  477             }
  478         }
  479     }
  480 
  481     /* fetch path */
  482     dummy = strchr(&in_use[8], '/');
  483     if (dummy)
  484         *path = strdup(dummy);
  485     else
  486         *path = strdup("/");
  487 }
  488 
  489 typedef struct {
  490     int interval, last_ts;
  491     double value, sd, min, max;
  492     int n_values;
  493 } aggregate_t;
  494 
  495 void set_aggregate(char *in, int *n_aggregates, aggregate_t **aggregates)
  496 {
  497     char *dummy = in;
  498 
  499     *n_aggregates = 0;
  500 
  501     for(;dummy;)
  502     {
  503         (*n_aggregates)++;
  504 
  505         *aggregates = (aggregate_t *)realloc(*aggregates, *n_aggregates * sizeof(aggregate_t));
  506 
  507         memset(&(*aggregates)[*n_aggregates - 1], 0x00, sizeof(aggregate_t));
  508 
  509         (*aggregates)[*n_aggregates - 1].interval = atoi(dummy);
  510         (*aggregates)[*n_aggregates - 1].max = -MY_DOUBLE_INF;
  511         (*aggregates)[*n_aggregates - 1].min =  MY_DOUBLE_INF;
  512 
  513         dummy = strchr(dummy, ',');
  514         if (dummy)
  515             dummy++;
  516     }
  517 }
  518 
  519 void do_aggregates(double cur_ms, int cur_ts, int n_aggregates, aggregate_t *aggregates, int verbose, char show_ts)
  520 {
  521     int index=0;
  522 
  523     /* update measurements */
  524     for(index=0; index<n_aggregates; index++)
  525     {
  526         aggregates[index].value += cur_ms;
  527 
  528         if (cur_ms < aggregates[index].min)
  529             aggregates[index].min = cur_ms;
  530 
  531         if (cur_ms > aggregates[index].max)
  532             aggregates[index].max = cur_ms;
  533 
  534         aggregates[index].sd += cur_ms * cur_ms;
  535 
  536         aggregates[index].n_values++;
  537     }
  538 
  539     /* emit */
  540     for(index=0; index<n_aggregates && cur_ts > 0; index++)
  541     {
  542         aggregate_t *a = &aggregates[index];
  543 
  544         if (cur_ts - a -> last_ts >= a -> interval)
  545         {
  546             char *line = NULL;
  547             double avg = a -> n_values ? a -> value / (double)a -> n_values : -1.0;
  548             char *ts = get_ts_str(verbose);
  549 
  550             str_add(&line, "%s", show_ts ? ts : "");
  551             free(ts);
  552 
  553             str_add(&line, gettext("AGG[%d]: %d values, min/avg/max%s = %.1f/%.1f/%.1f"), a -> interval, a -> n_values, verbose ? gettext("/sd") : "", a -> min, avg, a -> max);
  554 
  555             if (verbose)
  556             {
  557                 double sd = -1.0;
  558 
  559                 if (a -> n_values)
  560                     sd = sqrt((a -> sd / (double)a -> n_values) - pow(avg, 2.0));
  561 
  562                 str_add(&line, "/%.1f", sd);
  563             }
  564 
  565             str_add(&line, " ms");
  566 
  567 #ifdef NC
  568             if (ncurses_mode)
  569                 slow_log("\n%s", line);
  570             else
  571 #endif
  572                 printf("%s\n", line);
  573 
  574             free(line);
  575 
  576             aggregates[index].value =
  577                 aggregates[index].sd    = 0.0;
  578             aggregates[index].min =  MY_DOUBLE_INF;
  579             aggregates[index].max = -MY_DOUBLE_INF;
  580             aggregates[index].n_values = 0;
  581             aggregates[index].last_ts = cur_ts;
  582         }
  583     }
  584 }
  585 
  586 void fetch_proxy_settings(char **proxy_user, char **proxy_password, char **proxy_host, int *proxy_port, char use_ssl, char use_ipv6)
  587 {
  588     char *str = getenv(use_ssl ? "https_proxy" : "http_proxy");
  589 
  590     if (!str)
  591     {
  592         /* FIXME from wgetrc/curlrc? */
  593     }
  594 
  595     if (str)
  596     {
  597         char *path = NULL, *url = NULL;
  598 
  599         interpret_url(str, &path, proxy_host, proxy_port, use_ipv6, use_ssl, &url, proxy_user, proxy_password);
  600 
  601         free(url);
  602         free(path);
  603     }
  604 }
  605 
  606 void parse_nagios_settings(const char *in, double *nagios_warn, double *nagios_crit)
  607 {
  608     char *dummy = strchr(in, ',');
  609     if (!dummy)
  610         error_exit(gettext("-n: missing parameter\n"));
  611 
  612     *nagios_warn = atof(in);
  613 
  614     *nagios_crit = atof(dummy + 1);
  615 }
  616 
  617 void parse_bind_to(const char *in, struct sockaddr_in *bind_to_4, struct sockaddr_in6 *bind_to_6, struct sockaddr_in **bind_to)
  618 {
  619     char *dummy = strchr(in, ':');
  620 
  621     if (dummy)
  622     {
  623         *bind_to = (struct sockaddr_in *)bind_to_6;
  624         memset(bind_to_6, 0x00, sizeof *bind_to_6);
  625         bind_to_6 -> sin6_family = AF_INET6;
  626 
  627         if (inet_pton(AF_INET6, in, &bind_to_6 -> sin6_addr) != 1)
  628             error_exit(gettext("cannot convert ip address '%s' (for -y)\n"), in);
  629     }
  630     else
  631     {
  632         *bind_to = (struct sockaddr_in *)bind_to_4;
  633         memset(bind_to_4, 0x00, sizeof *bind_to_4);
  634         bind_to_4 -> sin_family = AF_INET;
  635 
  636         if (inet_pton(AF_INET, in, &bind_to_4 -> sin_addr) != 1)
  637             error_exit(gettext("cannot convert ip address '%s' (for -y)\n"), in);
  638     }
  639 }
  640 
  641 time_t parse_date_from_response_headers(const char *in)
  642 {
  643     char *date = NULL, *komma = NULL;
  644     if (in == NULL)
  645         return -1;
  646 
  647     date = strstr(in, "\nDate:");
  648     komma = date ? strchr(date, ',') : NULL;
  649     if (date && komma)
  650     {
  651         struct tm tm;
  652         memset(&tm, 0x00, sizeof tm);
  653 
  654         /* 22 Feb 2015 09:13:56 */
  655         if (strptime(komma + 1, "%d %b %Y %H:%M:%S %Z", &tm))
  656             return mktime(&tm);
  657     }
  658 
  659     return -1;
  660 }
  661 
  662 int calc_page_age(const char *in, const time_t their_ts)
  663 {
  664     int age = -1;
  665 
  666     if (in != NULL && their_ts > 0)
  667     {
  668         char *date = strstr(in, "\nLast-Modified:");
  669         char *komma = date ? strchr(date, ',') : NULL;
  670         if (date && komma)
  671         {
  672             struct tm tm;
  673             memset(&tm, 0x00, sizeof tm);
  674 
  675             /* 22 Feb 2015 09:13:56 */
  676             if (strptime(komma + 1, "%d %b %Y %H:%M:%S %Z", &tm))
  677                 age = their_ts - mktime(&tm);
  678         }
  679     }
  680 
  681     return age;
  682 }
  683 
  684 const char *get_location(const char *host, int port, char use_ssl, char *reply)
  685 {
  686     if (reply)
  687     {
  688         char *copy = strdup(reply);
  689         char *head = strstr(copy, "\nLocation:");
  690         char *lf = head ? strchr(head + 1, '\n') : NULL;
  691 
  692         if (head)
  693         {
  694             char *buffer = NULL;
  695             char *dest = head + 11;
  696 
  697             if (lf)
  698                 *lf = 0x00;
  699 
  700             if (memcmp(dest, "http", 4) == 0)
  701                 str_add(&buffer, "%s", dest);
  702             else
  703                 str_add(&buffer, "http%s://%s:%d%s", use_ssl ? "s" : "", host, port, dest);
  704 
  705             free(copy);
  706 
  707             return buffer;
  708         }
  709 
  710         free(copy);
  711     }
  712 
  713     return NULL;
  714 }
  715 
  716 char check_compressed(const char *reply)
  717 {
  718     if (reply != NULL)
  719     {
  720         char *encoding = strstr(reply, "\nContent-Encoding:");
  721 
  722         if (encoding)
  723         {
  724             char *dummy = strchr(encoding + 1, '\r');
  725             if (dummy) *dummy = 0x00;
  726 
  727             dummy = strchr(encoding + 1, '\n');
  728             if (dummy) *dummy = 0x00;
  729 
  730             if (strstr(encoding, "gzip") == 0 || strstr(encoding, "deflate") == 0)
  731                 return 1;
  732         }
  733     }
  734 
  735     return 0;
  736 }
  737 
  738 int nagios_result(int ok, int nagios_mode, int nagios_exit_code, double avg_httping_time, double nagios_warn, double nagios_crit)
  739 {
  740     if (nagios_mode == 1)
  741     {
  742         if (ok == 0)
  743         {
  744             printf(gettext("CRITICAL - connecting failed: %s"), get_error());
  745             return 2;
  746         }
  747         else if (avg_httping_time >= nagios_crit)
  748         {
  749             printf(gettext("CRITICAL - average httping-time is %.1f\n"), avg_httping_time);
  750             return 2;
  751         }
  752         else if (avg_httping_time >= nagios_warn)
  753         {
  754             printf(gettext("WARNING - average httping-time is %.1f\n"), avg_httping_time);
  755             return 1;
  756         }
  757 
  758         printf(gettext("OK - average httping-time is %.1f (%s)|ping=%f\n"), avg_httping_time, get_error(), avg_httping_time);
  759 
  760         return 0;
  761     }
  762     else if (nagios_mode == 2)
  763     {
  764         const char *err = get_error();
  765 
  766         if (ok && err[0] == 0x00)
  767         {
  768             printf(gettext("OK - all fine, avg httping time is %.1f|ping=%f\n"), avg_httping_time, avg_httping_time);
  769             return 0;
  770         }
  771 
  772         printf(gettext("%s: - failed: %s"), nagios_exit_code == 1?"WARNING":(nagios_exit_code == 2?"CRITICAL":"ERROR"), err);
  773         return nagios_exit_code;
  774     }
  775 
  776     return -1;
  777 }
  778 
  779 void proxy_to_host_and_port(char *in, char **proxy_host, int *proxy_port)
  780 {
  781     if (in[0] == '[')
  782     {
  783         char *dummy = NULL;
  784 
  785         *proxy_host = strdup(in + 1);
  786 
  787         dummy = strchr(*proxy_host, ']');
  788         if (dummy)
  789         {
  790             *dummy = 0x00;
  791 
  792             /* +2: ']:' */
  793             *proxy_port = atoi(dummy + 2);
  794         }
  795     }
  796     else
  797     {
  798         char *dummy = strchr(in, ':');
  799 
  800         *proxy_host = in;
  801 
  802         if (dummy)
  803         {
  804             *dummy=0x00;
  805             *proxy_port = atoi(dummy + 1);
  806         }
  807     }
  808 }
  809 
  810 void stats_close(int *fd, stats_t *t_close, char is_failure)
  811 {
  812     double t_start = get_ts(), t_end = -1;;
  813 
  814     if (is_failure)
  815         failure_close(*fd);
  816     else
  817         close(*fd);
  818 
  819     *fd = -1;
  820 
  821     t_end = get_ts();
  822 
  823     update_statst(t_close, (t_end - t_start) * 1000.0);
  824 }
  825 
  826 void add_header(char ***additional_headers, int *n_additional_headers, const char *in)
  827 {
  828     *additional_headers = (char **)realloc(*additional_headers, (*n_additional_headers + 1) * sizeof(char **));
  829     (*additional_headers)[*n_additional_headers] = strdup(in);
  830 
  831     (*n_additional_headers)++;
  832 }
  833 
  834 void free_headers(char **additional_headers, int n_additional_headers)
  835 {
  836     int index = 0;
  837 
  838     for(index=0; index<n_additional_headers; index++)
  839         free(additional_headers[index]);
  840 
  841     free(additional_headers);
  842 }
  843 
  844 typedef struct
  845 {
  846     double Bps_min, Bps_max;
  847     long long int Bps_avg;
  848 } bps_t;
  849 
  850 void stats_line(const char with_header, const char *const complete_url, const int count, const int curncount, const int err, const int ok, double started_at, const char verbose, const stats_t *const t_total, const double avg_httping_time, bps_t *const bps)
  851 {
  852     double total_took = get_ts() - started_at;
  853     int dummy = count;
  854 
  855     if (with_header)
  856         printf(gettext("--- %s ping statistics ---\n"), complete_url);
  857 
  858     if (curncount == 0 && err > 0)
  859         fprintf(stderr, gettext("internal error! (curncount)\n"));
  860 
  861     if (count == -1)
  862         dummy = curncount;
  863 
  864     printf(gettext("%s%d%s connects, %s%d%s ok, %s%3.2f%%%s failed, time %s%s%.0fms%s\n"), c_yellow, curncount, c_normal, c_green, ok, c_normal, c_red, (((double)err) / ((double)dummy)) * 100.0, c_normal, c_blue, c_bright, total_took * 1000.0, c_normal);
  865 
  866     if (ok > 0)
  867     {
  868         printf(gettext("round-trip min/avg/max%s = %s%.1f%s/%s%.1f%s/%s%.1f%s"), verbose ? gettext("/sd") : "", c_bright, t_total -> min, c_normal, c_bright, avg_httping_time, c_normal, c_bright, t_total -> max, c_normal);
  869 
  870         if (verbose)
  871         {
  872             double sd_final = t_total -> n ? sqrt((t_total -> sd / (double)t_total -> n) - pow(avg_httping_time, 2.0)) : -1.0;
  873             printf("/%.1f", sd_final);
  874         }
  875 
  876         printf(" ms\n");
  877 
  878         if (bps)
  879             printf(gettext("Transfer speed: min/avg/max = %s%f%s/%s%f%s/%s%f%s KB\n"), c_bright, bps -> Bps_min / 1024, c_normal, c_bright, (bps -> Bps_avg / (double)ok) / 1024.0, c_normal, c_bright, bps -> Bps_max / 1024.0, c_normal);
  880     }
  881 }
  882 
  883 int main(int argc, char *argv[])
  884 {
  885     double started_at = -1;
  886     char do_fetch_proxy_settings = 0;
  887     char *hostname = NULL;
  888     char *proxy_host = NULL, *proxy_user = NULL, *proxy_password = NULL;
  889     int proxy_port = 8080;
  890     int portnr = 80;
  891     char *get = NULL, *request = NULL;
  892     int req_len = 0;
  893     int c = 0;
  894     int count = -1, curncount = 0;
  895     double wait = 1.0;
  896     char wait_set = 0;
  897     int audible = 0;
  898     int ok = 0, err = 0;
  899     double timeout = 30.0;
  900     char show_statuscodes = 0;
  901     char use_ssl = 0;
  902     const char *ok_str = "200";
  903     const char *err_str = "-1";
  904     const char *useragent = NULL;
  905     const char *referer = NULL;
  906     const char *auth_password = NULL;
  907     const char *auth_usr = NULL;
  908     char **static_cookies = NULL, **dynamic_cookies = NULL;
  909     int n_static_cookies = 0, n_dynamic_cookies = 0;
  910     char resolve_once = 0;
  911     char have_resolved = 0;
  912     double nagios_warn=0.0, nagios_crit=0.0;
  913     int nagios_exit_code = 2;
  914     double avg_httping_time = -1.0;
  915     int get_instead_of_head = 0;
  916     char show_Bps = 0, ask_compression = 0;
  917     bps_t bps;
  918     int Bps_limit = -1;
  919     char show_bytes_xfer = 0, show_fp = 0;
  920     SSL *ssl_h = NULL;
  921     BIO *s_bio = NULL;
  922     struct sockaddr_in *bind_to = NULL;
  923     struct sockaddr_in bind_to_4;
  924     struct sockaddr_in6 bind_to_6;
  925     char split = 0, use_ipv6 = 0;
  926     char persistent_connections = 0, persistent_did_reconnect = 0;
  927     char no_cache = 0;
  928     char use_tfo = 0;
  929     char abort_on_resolve_failure = 1;
  930     double offset_yellow = -1, offset_red = -1;
  931     char colors = 0;
  932     int verbose = 0;
  933     double offset_show = -1.0;
  934     char add_host_header = 1;
  935     char *proxy_buster = NULL;
  936     char proxy_is_socks5 = 0;
  937     char *url = NULL, *complete_url = NULL;
  938     int n_aggregates = 0;
  939     aggregate_t *aggregates = NULL;
  940     char *au_dummy = NULL, *ap_dummy = NULL;
  941     stats_t t_connect, t_request, t_total, t_resolve, t_write, t_ssl, t_close, stats_to, tcp_rtt_stats, stats_header_size;
  942     char first_resolve = 1;
  943     double graph_limit = MY_DOUBLE_INF;
  944     char nc_graph = 1;
  945     char adaptive_interval = 0;
  946     double show_slow_log = MY_DOUBLE_INF;
  947     char use_tcp_nodelay = 1;
  948     int max_mtu = -1;
  949     int write_sleep = 500; /* in us (microseconds), determines resolution of transmit time determination */
  950     char keep_cookies = 0;
  951     char abbreviate = 0;
  952     char *divert_connect = NULL;
  953     int recv_buffer_size = -1, tx_buffer_size = -1;
  954     int priority = -1, send_tos = -1;
  955     char **additional_headers = NULL;
  956     int n_additional_headers = 0;
  957 #ifndef NO_SSL
  958     SSL_CTX *client_ctx = NULL;
  959 #endif
  960     const char *ca_path = NULL;
  961     struct sockaddr_in6 addr;
  962     struct addrinfo *ai = NULL, *ai_use = NULL;
  963     struct addrinfo *ai_proxy = NULL, *ai_use_proxy = NULL;
  964     char http2 = 0;
  965 
  966     static struct option long_options[] =
  967     {
  968         {"aggregate",   1, NULL, 9 },
  969         {"url",     1, NULL, 'g' },
  970         {"hostname",    1, NULL, 'h' },
  971         {"port",    1, NULL, 'p' },
  972         {"proxy",   1, NULL, 'x' },
  973         {"count",   1, NULL, 'c' },
  974         {"persistent-connections",  0, NULL, 'Q' },
  975         {"interval",    1, NULL, 'i' },
  976         {"timeout", 1, NULL, 't' },
  977         {"ipv6",    0, NULL, '6' },
  978         {"show-statuscodes",    0, NULL, 's' },
  979         {"split-time",  0, NULL, 'S' },
  980         {"get-request", 0, NULL, 'G' },
  981         {"show-transfer-speed", 0, NULL, 'b' },
  982         {"show-xfer-speed-compressed",  0, NULL, 'B' },
  983         {"data-limit",  1, NULL, 'L' },
  984         {"show-kb", 0, NULL, 'X' },
  985         {"no-cache",    0, NULL, 'Z' },
  986 #ifndef NO_SSL
  987         {"use-ssl", 0, NULL, 'l' },
  988         {"show-fingerprint",    0, NULL, 'z' },
  989 #endif
  990         {"flood",   0, NULL, 'f' },
  991         {"audible-ping",    0, NULL, 'a' },
  992         {"parseable-output",    0, NULL, 'm' },
  993         {"ok-result-codes", 1, NULL, 'o' },
  994         {"result-string",   1, NULL, 'e' },
  995         {"user-agent",  1, NULL, 'I' },
  996         {"referer", 1, NULL, 'S' },
  997         {"resolve-once",0, NULL, 'r' },
  998         {"nagios-mode-1",   1, NULL, 'n' },
  999         {"nagios-mode-2",   1, NULL, 'n' },
 1000         {"bind-to", 1, NULL, 'y' },
 1001         {"quiet",   0, NULL, 'q' },
 1002         {"username",    1, NULL, 'U' },
 1003         {"password",    1, NULL, 'P' },
 1004         {"cookie",  1, NULL, 'C' },
 1005         {"colors",  0, NULL, 'Y' },
 1006         {"offset-yellow",   1, NULL, 1   },
 1007         {"threshold-yellow",    1, NULL, 1   },
 1008         {"offset-red",  1, NULL, 2   },
 1009         {"threshold-red",   1, NULL, 2   },
 1010         {"offset-show", 1, NULL, 3   },
 1011         {"show-offset", 1, NULL, 3   },
 1012         {"threshold-show",  1, NULL, 3   },
 1013         {"show-threshold",  1, NULL, 3   },
 1014         {"timestamp",   0, NULL, 4   },
 1015         {"ts",      0, NULL, 4   },
 1016         {"no-host-header",  0, NULL, 5 },
 1017         {"proxy-buster",    1, NULL, 6 },
 1018         {"proxy-user",  1, NULL, 7 },
 1019         {"proxy-password",  1, NULL, 8 },
 1020         {"proxy-password-file", 1, NULL, 10 },
 1021         {"graph-limit", 1, NULL, 11 },
 1022         {"adaptive-interval",   0, NULL, 12 },
 1023         {"ai",  0, NULL, 12 },
 1024         {"slow-log",    0, NULL, 13 },
 1025         {"draw-phase",  0, NULL, 14 },
 1026         {"no-tcp-nodelay",  0, NULL, 15 },
 1027         {"max-mtu", 1, NULL, 16 },
 1028         {"keep-cookies", 0, NULL, 17 },
 1029         {"abbreviate", 0, NULL, 18 },
 1030         {"divert-connect", 1, NULL, 19 },
 1031         {"recv-buffer", 1, NULL, 20 },
 1032         {"tx-buffer", 1, NULL, 21 },
 1033         {"priority", 1, NULL, 23 },
 1034         {"tos", 1, NULL, 24 },
 1035         {"header", 1, NULL, 25 },
 1036         {"ca-path", 1, NULL, 26 },
 1037 #ifdef NC
 1038         {"ncurses", 0, NULL, 'K' },
 1039         {"gui", 0, NULL, 'K' },
 1040 #ifdef FW
 1041         {"no-graph",    0, NULL, 'D' },
 1042 #endif
 1043 #endif
 1044         {"http2", 0, NULL, '2' },
 1045         {"version", 0, NULL, 'V' },
 1046         {"help",    0, NULL, 22 },
 1047         {NULL,      0, NULL, 0   }
 1048     };
 1049 
 1050     bps.Bps_min = 1 << 30;
 1051     bps.Bps_max = -bps.Bps_min;
 1052     bps.Bps_avg = 0;
 1053 
 1054     setlocale(LC_ALL, "");
 1055     bindtextdomain("httping", LOCALEDIR);
 1056     textdomain("httping");
 1057 
 1058     init_statst(&t_resolve);
 1059     init_statst(&t_connect);
 1060     init_statst(&t_write);
 1061     init_statst(&t_request);
 1062     init_statst(&t_total);
 1063     init_statst(&t_ssl);
 1064     init_statst(&t_close);
 1065 
 1066     init_statst(&stats_to);
 1067 #if defined(linux) || defined(__FreeBSD__)
 1068     init_statst(&tcp_rtt_stats);
 1069 #endif
 1070     init_statst(&stats_header_size);
 1071 
 1072     determine_terminal_size(&max_y, &max_x);
 1073 
 1074     signal(SIGPIPE, SIG_IGN);
 1075 
 1076     while((c = getopt_long(argc, argv, "2DKEA5MvYWT:ZQ6Sy:XL:bBg:h:p:c:i:Gx:t:o:e:falqsmV?I:R:rn:N:zP:U:C:F", long_options, NULL)) != -1)
 1077     {
 1078         switch(c)
 1079         {
 1080             case '2':
 1081                 http2 = 1;
 1082                 break;
 1083 
 1084             case 26:
 1085                 ca_path = optarg;
 1086                 break;
 1087 
 1088             case 25:
 1089                 add_header(&additional_headers, &n_additional_headers, optarg);
 1090                 break;
 1091 
 1092             case 24:
 1093                 send_tos = atoi(optarg);
 1094                 break;
 1095 
 1096             case 23:
 1097 #ifdef linux
 1098                 priority = atoi(optarg);
 1099 #else
 1100                 error_exit("Setting the network priority is only supported on Linux.\n");
 1101 #endif
 1102                 break;
 1103 
 1104             case 21:
 1105                 tx_buffer_size = atoi(optarg);
 1106                 break;
 1107 
 1108             case 20:
 1109                 recv_buffer_size = atoi(optarg);
 1110                 break;
 1111 
 1112             case 19:
 1113                 divert_connect = optarg;
 1114                 break;
 1115 
 1116             case 18:
 1117                 abbreviate = 1;
 1118                 break;
 1119 
 1120             case 17:
 1121                 keep_cookies = 1;
 1122                 break;
 1123 
 1124             case 16:
 1125                 max_mtu = atoi(optarg);
 1126                 break;
 1127 
 1128             case 15:
 1129                 use_tcp_nodelay = 0;
 1130                 break;
 1131 
 1132 #ifdef NC
 1133             case 14:
 1134                 draw_phase = 1;
 1135                 break;
 1136 #endif
 1137 
 1138             case 13:
 1139                 show_slow_log = atof(optarg);
 1140                 break;
 1141 
 1142             case 12:
 1143                 adaptive_interval = 1;
 1144                 break;
 1145 
 1146             case 11:
 1147                 graph_limit = atof(optarg);
 1148                 break;
 1149 
 1150 #ifdef NC
 1151             case 'K':
 1152                 ncurses_mode = 1;
 1153                 adaptive_interval = 1;
 1154                 if (!wait_set)
 1155                     wait = 0.5;
 1156                 break;
 1157 #ifdef FW
 1158             case 'D':
 1159                 nc_graph = 0;
 1160                 break;
 1161 #endif
 1162 #endif
 1163 
 1164             case 'E':
 1165                 do_fetch_proxy_settings = 1;
 1166                 break;
 1167 
 1168             case 'A':
 1169                 fprintf(stderr, gettext("\n *** -A is no longer required ***\n\n"));
 1170                 break;
 1171 
 1172             case 'M':
 1173                 json_output = 1;
 1174                 break;
 1175 
 1176             case 'v':
 1177                 verbose++;
 1178                 break;
 1179 
 1180             case 1:
 1181                 offset_yellow = atof(optarg);
 1182                 break;
 1183 
 1184             case 2:
 1185                 offset_red = atof(optarg);
 1186                 break;
 1187 
 1188             case 3:
 1189                 offset_show = atof(optarg);
 1190                 break;
 1191 
 1192             case 4:
 1193                 show_ts = 1;
 1194                 break;
 1195 
 1196             case 5:
 1197                 add_host_header = 0;
 1198                 break;
 1199 
 1200             case 6:
 1201                 proxy_buster = optarg;
 1202                 break;
 1203 
 1204             case '5':
 1205                 proxy_is_socks5 = 1;
 1206                 break;
 1207 
 1208             case 7:
 1209                 proxy_user = optarg;
 1210                 break;
 1211 
 1212             case 8:
 1213                 proxy_password = optarg;
 1214                 break;
 1215 
 1216             case 9:
 1217                 set_aggregate(optarg, &n_aggregates, &aggregates);
 1218                 break;
 1219 
 1220             case 10:
 1221                 proxy_password = read_file(optarg);
 1222                 break;
 1223 
 1224             case 'Y':
 1225                 colors = 1;
 1226                 break;
 1227 
 1228             case 'W':
 1229                 abort_on_resolve_failure = 0;
 1230                 break;
 1231 
 1232             case 'T':
 1233                 auth_password = read_file(optarg);
 1234                 break;
 1235 
 1236             case 'Z':
 1237                 no_cache = 1;
 1238                 break;
 1239 
 1240             case '6':
 1241                 use_ipv6 = 1;
 1242                 break;
 1243 
 1244             case 'S':
 1245                 split = 1;
 1246                 break;
 1247 
 1248             case 'Q':
 1249                 persistent_connections = 1;
 1250                 break;
 1251 
 1252             case 'y':
 1253                 parse_bind_to(optarg, &bind_to_4, &bind_to_6, &bind_to);
 1254                 break;
 1255 
 1256             case 'z':
 1257                 show_fp = 1;
 1258                 break;
 1259 
 1260             case 'X':
 1261                 show_bytes_xfer = 1;
 1262                 break;
 1263 
 1264             case 'L':
 1265                 Bps_limit = atoi(optarg);
 1266                 break;
 1267 
 1268             case 'B':
 1269                 show_Bps = 1;
 1270                 ask_compression = 1;
 1271                 break;
 1272 
 1273             case 'b':
 1274                 show_Bps = 1;
 1275                 break;
 1276 
 1277             case 'e':
 1278                 err_str = optarg;
 1279                 break;
 1280 
 1281             case 'o':
 1282                 ok_str = optarg;
 1283                 break;
 1284 
 1285             case 'x':
 1286                 proxy_to_host_and_port(optarg, &proxy_host, &proxy_port);
 1287                 break;
 1288 
 1289             case 'g':
 1290                 url = optarg;
 1291                 break;
 1292 
 1293             case 'r':
 1294                 resolve_once = 1;
 1295                 break;
 1296 
 1297             case 'h':
 1298                 free(url);
 1299                 url = NULL;
 1300                 str_add(&url, "http://%s/", optarg);
 1301                 break;
 1302 
 1303             case 'p':
 1304                 portnr = atoi(optarg);
 1305                 break;
 1306 
 1307             case 'c':
 1308                 count = atoi(optarg);
 1309                 break;
 1310 
 1311             case 'i':
 1312                 wait = atof(optarg);
 1313                 if (wait < 0.0)
 1314                     error_exit(gettext("-i cannot have a value smaller than zero"));
 1315                 wait_set = 1;
 1316                 break;
 1317 
 1318             case 't':
 1319                 timeout = atof(optarg);
 1320                 break;
 1321 
 1322             case 'I':
 1323                 useragent = optarg;
 1324                 break;
 1325 
 1326             case 'R':
 1327                 referer = optarg;
 1328                 break;
 1329 
 1330             case 'a':
 1331                 audible = 1;
 1332                 break;
 1333 
 1334             case 'f':
 1335                 wait = 0;
 1336                 wait_set = 1;
 1337                 adaptive_interval = 0;
 1338                 break;
 1339 
 1340             case 'G':
 1341                 get_instead_of_head = 1;
 1342                 break;
 1343 
 1344 #ifndef NO_SSL
 1345             case 'l':
 1346                 use_ssl = 1;
 1347                 break;
 1348 #endif
 1349 
 1350             case 'm':
 1351                 machine_readable = 1;
 1352                 break;
 1353 
 1354             case 'q':
 1355                 quiet = 1;
 1356                 break;
 1357 
 1358             case 's':
 1359                 show_statuscodes = 1;
 1360                 break;
 1361 
 1362             case 'V':
 1363                 version();
 1364                 return 0;
 1365 
 1366             case 'n':
 1367                 if (nagios_mode)
 1368                     error_exit(gettext("-n and -N are mutual exclusive\n"));
 1369                 else
 1370                     nagios_mode = 1;
 1371 
 1372                 parse_nagios_settings(optarg, &nagios_warn, &nagios_crit);
 1373                 break;
 1374 
 1375             case 'N':
 1376                 if (nagios_mode) error_exit(gettext("-n and -N are mutual exclusive\n"));
 1377                 nagios_mode = 2;
 1378                 nagios_exit_code = atoi(optarg);
 1379                 break;
 1380 
 1381             case 'P':
 1382                 auth_password = optarg;
 1383                 break;
 1384 
 1385             case 'U':
 1386                 auth_usr = optarg;
 1387                 break;
 1388 
 1389             case 'C':
 1390                 add_cookie(&static_cookies, &n_static_cookies, optarg);
 1391                 break;
 1392 
 1393             case 'F':
 1394 #ifdef TCP_TFO
 1395                 use_tfo = 1;
 1396 #else
 1397                 fprintf(stderr, gettext("Warning: TCP TFO is not supported. Disabling.\n"));
 1398 #endif
 1399                 break;
 1400 
 1401             case 22:
 1402                 version();
 1403 
 1404                 usage(argv[0]);
 1405 
 1406                 return 0;
 1407 
 1408             case '?':
 1409             default:
 1410                 fprintf(stderr, "\n");
 1411                 version();
 1412 
 1413                 fprintf(stderr, gettext("\n\nPlease run:\n\t%s --help\nto see a list of options.\n\n"), argv[0]);
 1414 
 1415                 return 1;
 1416         }
 1417     }
 1418 
 1419     if (do_fetch_proxy_settings)
 1420         fetch_proxy_settings(&proxy_user, &proxy_password, &proxy_host, &proxy_port, use_ssl, use_ipv6);
 1421 
 1422     if (optind < argc)
 1423         url = argv[optind];
 1424 
 1425     if (!url)
 1426     {
 1427         fprintf(stderr, gettext("No URL/host to ping given\n\n"));
 1428         return 1;
 1429     }
 1430 
 1431     if (machine_readable + json_output + ncurses_mode > 1)
 1432         error_exit(gettext("Cannot combine -m, -M and -K"));
 1433 
 1434     if ((machine_readable || json_output) && n_aggregates > 0)
 1435         error_exit(gettext("Aggregates can only be used in non-machine/json-output mode"));
 1436 
 1437     clear_error();
 1438 
 1439     if (!(get_instead_of_head || use_ssl) && show_Bps)
 1440         error_exit(gettext("-b/-B can only be used when also using -G (GET instead of HEAD) or -l (use SSL)\n"));
 1441 
 1442     if (colors)
 1443         set_colors(ncurses_mode);
 1444 
 1445     if (!machine_readable && !json_output)
 1446         printf("%s%s", c_normal, c_white);
 1447 
 1448     interpret_url(url, &get, &hostname, &portnr, use_ipv6, use_ssl, &complete_url, &au_dummy, &ap_dummy);
 1449     if (!auth_usr)
 1450         auth_usr = au_dummy;
 1451     if (!auth_password)
 1452         auth_password = ap_dummy;
 1453 
 1454 #ifdef NC
 1455     if (ncurses_mode)
 1456     {
 1457         if (wait == 0.0)
 1458             wait = 0.001;
 1459 
 1460         init_ncurses_ui(graph_limit, 1.0 / wait, colors);
 1461     }
 1462 #endif
 1463 
 1464     if (strncmp(complete_url, "https://", 8) == 0 && !use_ssl)
 1465     {
 1466         use_ssl = 1;
 1467 #ifdef NC
 1468         if (ncurses_mode)
 1469         {
 1470             slow_log(gettext("\nAuto enabling SSL due to https-URL\n"));
 1471             update_terminal();
 1472         }
 1473         else
 1474 #endif
 1475         {
 1476             fprintf(stderr, gettext("Auto enabling SSL due to https-URL\n"));
 1477         }
 1478     }
 1479 
 1480     if (use_tfo && use_ssl)
 1481         error_exit(gettext("TCP Fast open and SSL not supported together\n"));
 1482 
 1483     if (verbose)
 1484     {
 1485 #ifdef NC
 1486         if (ncurses_mode)
 1487         {
 1488             slow_log(gettext("\nConnecting to host %s, port %d and requesting file %s"), hostname, portnr, get);
 1489 
 1490             if (proxy_host)
 1491                 slow_log(gettext("\nUsing proxyserver: %s:%d"), proxy_host, proxy_port);
 1492         }
 1493         else
 1494 #endif
 1495         {
 1496             printf(gettext("Connecting to host %s, port %d and requesting file %s\n\n"), hostname, portnr, get);
 1497 
 1498             if (proxy_host)
 1499                 fprintf(stderr, gettext("Using proxyserver: %s:%d\n"), proxy_host, proxy_port);
 1500         }
 1501     }
 1502 
 1503 #ifndef NO_SSL
 1504     if (use_ssl)
 1505     {
 1506         client_ctx = initialize_ctx(ask_compression, ca_path);
 1507         if (!client_ctx)
 1508         {
 1509             set_error(gettext("problem creating SSL context"));
 1510             goto error_exit;
 1511         }
 1512     }
 1513 #endif
 1514 
 1515     if (!quiet && !machine_readable && !nagios_mode && !json_output)
 1516     {
 1517 #ifdef NC
 1518         if (ncurses_mode)
 1519             slow_log("\nPING %s:%d (%s):", hostname, portnr, get);
 1520         else
 1521 #endif
 1522             printf("PING %s%s:%s%d%s (%s):\n", c_green, hostname, c_bright, portnr, c_normal, get);
 1523     }
 1524 
 1525     if (json_output)
 1526         printf("[\n");
 1527 
 1528     if (adaptive_interval && wait <= 0.0)
 1529         error_exit(gettext("Interval must be > 0 when using adaptive interval"));
 1530 
 1531     signal(SIGINT, handler);
 1532     signal(SIGTERM, handler);
 1533 
 1534     signal(SIGQUIT, handler_quit);
 1535 
 1536     timeout *= 1000.0;  /* change to ms */
 1537 
 1538     /*
 1539        if (follow_30x)
 1540        {
 1541        get headers
 1542 
 1543        const char *get_location(const char *host, int port, char use_ssl, char *reply)
 1544 
 1545        set new host/port/path/etc
 1546        }
 1547      */
 1548 
 1549     started_at = get_ts();
 1550     if (proxy_host)
 1551     {
 1552 #ifdef NC
 1553         if (ncurses_mode)
 1554         {
 1555             slow_log(gettext("\nResolving hostname %s"), proxy_host);
 1556             update_terminal();
 1557         }
 1558 #endif
 1559 
 1560         if (resolve_host(proxy_host, &ai_proxy, use_ipv6, proxy_port) == -1)
 1561             error_exit(get_error());
 1562 
 1563         ai_use_proxy = select_resolved_host(ai_proxy, use_ipv6);
 1564         if (!ai_use_proxy)
 1565             error_exit(gettext("No valid IPv4 or IPv6 address found for %s"), proxy_host);
 1566     }
 1567     else if (resolve_once)
 1568     {
 1569         char *res_host = divert_connect ? divert_connect : hostname;
 1570 #ifdef NC
 1571         if (ncurses_mode)
 1572         {
 1573             slow_log(gettext("\nResolving hostname %s"), res_host);
 1574             update_terminal();
 1575         }
 1576 #endif
 1577 
 1578         if (resolve_host(res_host, &ai, use_ipv6, portnr) == -1)
 1579         {
 1580             err++;
 1581             emit_error(verbose, -1, started_at);
 1582             have_resolved = 0;
 1583             if (abort_on_resolve_failure)
 1584                 error_exit(get_error());
 1585         }
 1586 
 1587         ai_use = select_resolved_host(ai, use_ipv6);
 1588         if (!ai_use)
 1589         {
 1590             set_error(gettext("No valid IPv4 or IPv6 address found for %s"), res_host);
 1591 
 1592             if (abort_on_resolve_failure)
 1593                 error_exit(get_error());
 1594 
 1595             /* do not emit the resolve-error here: as 'have_resolved' is set to 0
 1596                next, the program will try to resolve again anyway
 1597                this prevents a double error-message while err is increased only
 1598                once
 1599              */
 1600             have_resolved = 0;
 1601         }
 1602 
 1603         if (have_resolved)
 1604             get_addr(ai_use, &addr);
 1605     }
 1606 
 1607     if (persistent_connections)
 1608         fd = -1;
 1609 
 1610     while((curncount < count || count == -1) && stop == 0)
 1611     {
 1612         double dstart = -1.0, dend = -1.0, dafter_connect = 0.0, dafter_resolve = 0.0, dafter_write_complete = 0.0;
 1613         char *reply = NULL;
 1614         double Bps = 0;
 1615         char is_compressed = 0;
 1616         long long int bytes_transferred = 0;
 1617         time_t their_ts = 0;
 1618         int age = -1;
 1619         char *sc = NULL, *scdummy = NULL;
 1620         char *fp = NULL;
 1621         int re_tx = 0, pmtu = 0, recv_tos = 0;
 1622         socklen_t recv_tos_len = sizeof recv_tos;
 1623 
 1624         dstart = get_ts();
 1625 
 1626         for(;;)
 1627         {
 1628             char did_reconnect = 0;
 1629             int rc = -1;
 1630             int persistent_tries = 0;
 1631             int len = 0, overflow = 0, headers_len = 0;
 1632             char req_sent = 0;
 1633             double dummy_ms = 0.0;
 1634             double their_est_ts = -1.0, toff_diff_ts = -1.0;
 1635             char tfo_success = 0;
 1636             double ssl_handshake = 0.0;
 1637             char cur_have_resolved = 0;
 1638 #if defined(linux) || defined(__FreeBSD__)
 1639             struct tcp_info info;
 1640             socklen_t info_len = sizeof(struct tcp_info);
 1641 #endif
 1642 
 1643             curncount++;
 1644 
 1645 persistent_loop:
 1646             if ((!resolve_once || (resolve_once == 1 && have_resolved == 0)) && fd == -1 && proxy_host == NULL)
 1647             {
 1648                 char *res_host = divert_connect ? divert_connect : hostname;
 1649 
 1650                 memset(&addr, 0x00, sizeof addr);
 1651 
 1652 #ifdef NC
 1653                 if (ncurses_mode && first_resolve)
 1654                 {
 1655                     slow_log(gettext("\nResolving hostname %s"), res_host);
 1656                     update_terminal();
 1657                     first_resolve = 0;
 1658                 }
 1659 #endif
 1660 
 1661                 if (ai)
 1662                 {
 1663                     freeaddrinfo(ai);
 1664 
 1665                     ai_use = ai = NULL;
 1666                 }
 1667 
 1668                 if (resolve_host(res_host, &ai, use_ipv6, portnr) == -1)
 1669                 {
 1670                     err++;
 1671                     emit_error(verbose, curncount, dstart);
 1672 
 1673                     if (abort_on_resolve_failure)
 1674                         error_exit(get_error());
 1675                     break;
 1676                 }
 1677 
 1678                 ai_use = select_resolved_host(ai, use_ipv6);
 1679                 if (!ai_use)
 1680                 {
 1681                     set_error(gettext("No valid IPv4 or IPv6 address found for %s"), res_host);
 1682                     emit_error(verbose, curncount, dstart);
 1683                     err++;
 1684 
 1685                     if (abort_on_resolve_failure)
 1686                         error_exit(get_error());
 1687 
 1688                     break;
 1689                 }
 1690 
 1691                 get_addr(ai_use, &addr);
 1692 
 1693                 cur_have_resolved = have_resolved = 1;
 1694             }
 1695 
 1696             if (cur_have_resolved)
 1697             {
 1698                 dafter_resolve = get_ts();
 1699                 dummy_ms = (dafter_resolve - dstart) * 1000.0;
 1700                 update_statst(&t_resolve, dummy_ms);
 1701             }
 1702 
 1703             free(request);
 1704             request = create_http_request_header(proxy_host ? complete_url : get, proxy_host ? 1 : 0, get_instead_of_head, persistent_connections, add_host_header ? hostname : NULL, useragent, referer, ask_compression, no_cache, auth_usr, auth_password, static_cookies, n_static_cookies, dynamic_cookies, keep_cookies ? n_dynamic_cookies : 0, proxy_buster, proxy_user, proxy_password, additional_headers, n_additional_headers, http2, use_ssl);
 1705             req_len = strlen(request);
 1706 
 1707             if (req_len >= 4096)
 1708             {
 1709                 char *line = NULL;
 1710                 static int notify_cnt = 0;
 1711 
 1712                 notify_cnt++;
 1713 
 1714                 if (notify_cnt == MAX_SHOW_SUPPRESSION + 1)
 1715                     str_add(&line, gettext("Will no longer inform about request headers too large."));
 1716                 else if (notify_cnt <= MAX_SHOW_SUPPRESSION)
 1717                     str_add(&line, gettext("Request headers > 4KB! (%d bytes) This may give failures with some HTTP servers."), req_len);
 1718 
 1719                 if (line)
 1720                 {
 1721 #ifdef NC
 1722                     if (ncurses_mode)
 1723                         slow_log("\n%s", line);
 1724                     else
 1725 #endif
 1726                         printf("%s\n", line);
 1727                 }
 1728 
 1729                 free(line);
 1730             }
 1731 
 1732             if ((persistent_connections && fd < 0) || !persistent_connections)
 1733             {
 1734                 int rc = -1;
 1735                 struct addrinfo *ai_dummy = proxy_host ? ai_use_proxy : ai_use;
 1736 
 1737                 fd = create_socket((struct sockaddr *)bind_to, ai_dummy, recv_buffer_size, tx_buffer_size, max_mtu, use_tcp_nodelay, priority, send_tos);
 1738                 if (fd < 0)
 1739                     rc = fd; /* FIXME need to fix this, this is ugly */
 1740                 else if (proxy_host)
 1741                 {
 1742                     if (proxy_is_socks5)
 1743                         rc = socks5connect(fd, ai_dummy, timeout, proxy_user, proxy_password, hostname, portnr, abort_on_resolve_failure);
 1744 #ifndef NO_SSL
 1745                     else if (use_ssl)
 1746                         rc = connect_ssl_proxy(fd, ai_dummy, timeout, proxy_user, proxy_password, hostname, portnr, &use_tfo);
 1747 #endif
 1748                     else
 1749                         rc = connect_to(fd, ai_dummy, timeout, &use_tfo, request, req_len, &req_sent);
 1750                 }
 1751                 else
 1752                 {
 1753 
 1754                     rc = connect_to(fd, ai_dummy, timeout, &use_tfo, request, req_len, &req_sent);
 1755                 }
 1756 
 1757                 if (rc < 0)
 1758                 {
 1759                     failure_close(fd);
 1760                     fd = rc; /* FIXME need to fix this */
 1761                 }
 1762 
 1763                 did_reconnect = 1;
 1764             }
 1765 
 1766             if (fd == RC_CTRLC) /* ^C pressed */
 1767                 break;
 1768 
 1769             if (fd < 0)
 1770             {
 1771                 fd = -1;
 1772             }
 1773 
 1774             if (fd >= 0)
 1775             {
 1776                 /* set fd blocking */
 1777                 if (set_fd_blocking(fd) == -1) /* FIXME redundant? already in connect_to etc? */
 1778                 {
 1779                     stats_close(&fd, &t_close, 1);
 1780                     break;
 1781                 }
 1782 
 1783 #ifndef NO_SSL
 1784                 if (use_ssl && ssl_h == NULL)
 1785                 {
 1786                     int rc = connect_ssl(fd, client_ctx, &ssl_h, &s_bio, timeout, &ssl_handshake, hostname);
 1787                     if (rc == 0)
 1788                         update_statst(&t_ssl, ssl_handshake);
 1789                     else
 1790                     {
 1791                         stats_close(&fd, &t_close, 1);
 1792                         fd = rc;
 1793 
 1794                         if (persistent_connections && ++persistent_tries < 2)
 1795                         {
 1796                             persistent_did_reconnect = 1;
 1797 
 1798                             goto persistent_loop;
 1799                         }
 1800                     }
 1801                 }
 1802 #endif
 1803             }
 1804 
 1805             dafter_connect = get_ts();
 1806 
 1807             if (did_reconnect)
 1808             {
 1809                 if (cur_have_resolved)
 1810                     dummy_ms = (dafter_connect - dafter_resolve) * 1000.0;
 1811                 else
 1812                     dummy_ms = (dafter_connect - dstart) * 1000.0;
 1813 
 1814                 update_statst(&t_connect, dummy_ms - ssl_handshake);
 1815             }
 1816 
 1817             if (fd < 0)
 1818             {
 1819                 if (fd == RC_TIMEOUT)
 1820                     set_error(gettext("timeout connecting to host"));
 1821 
 1822                 emit_error(verbose, curncount, dstart);
 1823                 err++;
 1824 
 1825                 fd = -1;
 1826 
 1827                 break;
 1828             }
 1829 
 1830 #ifndef NO_SSL
 1831             if (use_ssl)
 1832                 rc = WRITE_SSL(ssl_h, request, req_len, timeout);
 1833             else
 1834 #endif
 1835             {
 1836                 if (!req_sent)
 1837                     rc = mywrite(fd, request, req_len, timeout);
 1838                 else
 1839                     rc = req_len;
 1840             }
 1841 
 1842             /* wait for data transmit(!) to complete,
 1843                e.g. until the transmitbuffers are empty and the data was
 1844                sent to the next hop
 1845              */
 1846 #ifdef linux
 1847             for(;;)
 1848             {
 1849                 int bytes_left = 0;
 1850                 int i_rc = ioctl(fd, TIOCOUTQ, &bytes_left);
 1851 
 1852                 if (i_rc == -1 || bytes_left == 0 || stop)
 1853                     break;
 1854 
 1855                 dafter_write_complete = get_ts();
 1856                 if ((dafter_write_complete - dafter_connect) * 1000.0 >= timeout)
 1857                     break;
 1858 
 1859                 /* this keeps it somewhat from becoming a busy loop
 1860                  * I know of no other way to wait for the kernel to
 1861                  * finish the transmission
 1862                  */
 1863                 myusleep(write_sleep);
 1864             }
 1865 #endif
 1866 
 1867             dafter_write_complete = get_ts();
 1868 
 1869             dummy_ms = (dafter_write_complete - dafter_connect) * 1000.0;
 1870             update_statst(&t_write, dummy_ms);
 1871 
 1872             if (rc != req_len)
 1873             {
 1874                 if (persistent_connections)
 1875                 {
 1876                     if (++persistent_tries < 2)
 1877                     {
 1878                         stats_close(&fd, &t_close, 0);
 1879                         persistent_did_reconnect = 1;
 1880                         goto persistent_loop;
 1881                     }
 1882                 }
 1883 
 1884                 if (rc == -1)
 1885                     set_error(gettext("error sending request to host"));
 1886                 else if (rc == RC_TIMEOUT)
 1887                     set_error(gettext("timeout sending to host"));
 1888                 else if (rc == RC_INVAL)
 1889                     set_error(gettext("retrieved invalid data from host"));
 1890                 else if (rc == RC_CTRLC)
 1891                 {/* ^C */}
 1892                 else if (rc == 0)
 1893                     set_error(gettext("connection prematurely closed by peer"));
 1894 
 1895                 emit_error(verbose, curncount, dstart);
 1896 
 1897                 stats_close(&fd, &t_close, 1);
 1898                 err++;
 1899 
 1900                 break;
 1901             }
 1902 
 1903 #if defined(linux) || defined(__FreeBSD__)
 1904 #ifdef NC
 1905             if (!use_ssl && ncurses_mode)
 1906             {
 1907                 struct timeval tv;
 1908                 int t_rc = -1;
 1909 
 1910                 fd_set rfds;
 1911                 FD_ZERO(&rfds);
 1912                 FD_SET(fd, &rfds);
 1913 
 1914                 tv.tv_sec = (long)(timeout / 1000.0) % 1000000;
 1915                 tv.tv_usec = (long)(timeout * 1000.0) % 1000000;
 1916 
 1917                 t_rc = select(fd + 1, &rfds, NULL, NULL, &tv);
 1918 
 1919 #ifdef linux
 1920                 if (t_rc == 1 && \
 1921                         FD_ISSET(fd, &rfds) && \
 1922                         getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) == 0 && \
 1923                         info.tcpi_unacked > 0)
 1924                 {
 1925                     static int in_transit_cnt = 0;
 1926 
 1927                     in_transit_cnt++;
 1928                     if (in_transit_cnt == MAX_SHOW_SUPPRESSION + 1)
 1929                         slow_log(gettext("\nNo longer emitting message about \"still data in transit\""));
 1930                     else if (in_transit_cnt <= MAX_SHOW_SUPPRESSION)
 1931                         slow_log(gettext("\nHTTP server started sending data with %d bytes still in transit"), info.tcpi_unacked);
 1932                 }
 1933 #endif
 1934 
 1935                 if (t_rc == 0)
 1936                 {
 1937                     stats_close(&fd, &t_close, 1);
 1938 
 1939                     rc = RC_TIMEOUT;
 1940                     set_error(gettext("timeout sending to host"));
 1941 
 1942                     emit_error(verbose, curncount, dstart);
 1943 
 1944                     err++;
 1945 
 1946                     break;
 1947                 }
 1948             }
 1949 #endif
 1950 
 1951             if (getsockopt(fd, IPPROTO_IP, IP_TOS, &recv_tos, &recv_tos_len) == -1)
 1952             {
 1953                 set_error(gettext("failed to obtain TOS info"));
 1954                 recv_tos = -1;
 1955             }
 1956 #endif
 1957 
 1958             rc = get_HTTP_headers(fd, ssl_h, &reply, &overflow, timeout);
 1959 
 1960 #ifdef NC
 1961             if (ncurses_mode && !get_instead_of_head && overflow > 0)
 1962             {
 1963                 static int more_data_cnt = 0;
 1964 
 1965                 more_data_cnt++;
 1966                 if (more_data_cnt == MAX_SHOW_SUPPRESSION + 1)
 1967                     slow_log(gettext("\nNo longer emitting message about \"more data than response headers\""));
 1968                 else if (more_data_cnt <= MAX_SHOW_SUPPRESSION)
 1969                     slow_log(gettext("\nHTTP server sent more data than just the response headers"));
 1970             }
 1971 #endif
 1972 
 1973             emit_headers(reply);
 1974 
 1975             if (reply)
 1976             {
 1977                 free_cookies(dynamic_cookies, n_dynamic_cookies);
 1978                 dynamic_cookies = NULL;
 1979                 n_dynamic_cookies = 0;
 1980 
 1981                 get_cookies(reply, &dynamic_cookies, &n_dynamic_cookies, &static_cookies, &n_static_cookies);
 1982             }
 1983 
 1984             if ((show_statuscodes || machine_readable || json_output || ncurses_mode) && reply != NULL)
 1985             {
 1986                 /* statuscode is in first line behind
 1987                  * 'HTTP/1.x'
 1988                  */
 1989                 char *dummy = strchr(reply, ' ');
 1990 
 1991                 if (dummy)
 1992                 {
 1993                     sc = strdup(dummy + 1);
 1994 
 1995                     /* lines are normally terminated with a
 1996                      * CR/LF
 1997                      */
 1998                     dummy = strchr(sc, '\r');
 1999                     if (dummy)
 2000                         *dummy = 0x00;
 2001                     dummy = strchr(sc, '\n');
 2002                     if (dummy)
 2003                         *dummy = 0x00;
 2004                 }
 2005             }
 2006 
 2007             their_ts = parse_date_from_response_headers(reply);
 2008 
 2009             age = calc_page_age(reply, their_ts);
 2010 
 2011             is_compressed = check_compressed(reply);
 2012 
 2013             if (persistent_connections && show_bytes_xfer && reply != NULL)
 2014             {
 2015                 char *length = strstr(reply, "\nContent-Length:");
 2016                 if (!length)
 2017                 {
 2018                     set_error(gettext("'Content-Length'-header missing!"));
 2019                     emit_error(verbose, curncount, dstart);
 2020                     stats_close(&fd, &t_close, 1);
 2021                     break;
 2022                 }
 2023 
 2024                 len = atoi(&length[17]);
 2025             }
 2026 
 2027             if (http2 && get_instead_of_head) {
 2028                 printf("%s\n", reply);
 2029                 printf("%s\n", request);
 2030                 if (strncmp(reply, "HTTP/1.1 101", 12) != 0)
 2031                     printf("Server did not want to switch protocols\n");
 2032                 else if (strcasestr(reply, "Connection: Upgrade") == NULL)
 2033                     printf("Server did not want to upgrade connection\n");
 2034                 else if (strcasestr(reply, "Upgrade: h2c") == NULL)
 2035                     printf("Server did not want to upgrade connection to HTTP/2\n");
 2036             }
 2037 
 2038             headers_len = 0;
 2039             if (reply)
 2040             {
 2041                 headers_len = strlen(reply) + 4 - overflow;
 2042                 free(reply);
 2043                 reply = NULL;
 2044             }
 2045 
 2046             update_statst(&stats_header_size, headers_len);
 2047 
 2048             if (rc < 0)
 2049             {
 2050                 if (persistent_connections)
 2051                 {
 2052                     if (++persistent_tries < 2)
 2053                     {
 2054                         stats_close(&fd, &t_close, 0);
 2055                         persistent_did_reconnect = 1;
 2056                         goto persistent_loop;
 2057                     }
 2058                 }
 2059 
 2060                 if (rc == RC_SHORTREAD)
 2061                     set_error(gettext("short read during receiving reply-headers from host"));
 2062                 else if (rc == RC_TIMEOUT)
 2063                     set_error(gettext("timeout while receiving reply-headers from host"));
 2064 
 2065                 emit_error(verbose, curncount, dstart);
 2066 
 2067                 stats_close(&fd, &t_close, 1);
 2068                 err++;
 2069 
 2070                 break;
 2071             }
 2072 
 2073             ok++;
 2074 
 2075             if (get_instead_of_head && show_Bps)
 2076             {
 2077                 int buffer_size = RECV_BUFFER_SIZE;
 2078                 char *buffer = (char *)malloc(buffer_size);
 2079                 double dl_start = get_ts(), dl_end;
 2080                 double cur_limit = Bps_limit;
 2081 
 2082                 if (persistent_connections)
 2083                 {
 2084                     if (cur_limit == -1 || len < cur_limit)
 2085                         cur_limit = len - overflow;
 2086                 }
 2087 
 2088                 for(;;)
 2089                 {
 2090                     int n = cur_limit != -1 ? min(cur_limit - bytes_transferred, buffer_size) : buffer_size;
 2091                     int rc = read(fd, buffer, n);
 2092 
 2093                     if (rc == -1)
 2094                     {
 2095                         if (errno != EINTR && errno != EAGAIN)
 2096                             error_exit(gettext("read of response body dataa failed"));
 2097                     }
 2098                     else if (rc == 0)
 2099                     {
 2100                         break;
 2101                     }
 2102 
 2103                     bytes_transferred += rc;
 2104 
 2105                     if (cur_limit != -1 && bytes_transferred >= cur_limit)
 2106                         break;
 2107                 }
 2108 
 2109                 free(buffer);
 2110 
 2111                 dl_end = get_ts();
 2112 
 2113                 Bps = (double)bytes_transferred / max(dl_end - dl_start, 0.000001);
 2114                 bps.Bps_min = min(bps.Bps_min, Bps);
 2115                 bps.Bps_max = max(bps.Bps_max, Bps);
 2116                 bps.Bps_avg += Bps;
 2117             }
 2118 
 2119             dend = get_ts();
 2120 
 2121 #ifndef NO_SSL
 2122             if (use_ssl)
 2123             {
 2124                 if ((show_fp || json_output || ncurses_mode) && ssl_h != NULL)
 2125                     fp = get_fingerprint(ssl_h);
 2126 
 2127                 if (!persistent_connections)
 2128                 {
 2129                     if (close_ssl_connection(ssl_h) == -1)
 2130                     {
 2131                         set_error(gettext("error shutting down ssl"));
 2132                         emit_error(verbose, curncount, dstart);
 2133                     }
 2134 
 2135                     SSL_free(ssl_h);
 2136                     ssl_h = NULL;
 2137                     s_bio = NULL;
 2138                 }
 2139             }
 2140 #endif
 2141 
 2142 #if defined(linux) || defined(__FreeBSD__)
 2143             if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) == 0)
 2144             {
 2145 #ifdef TCP_TFO
 2146                 if (info.tcpi_options & TCPI_OPT_SYN_DATA)
 2147                     tfo_success = 1;
 2148 #endif
 2149 
 2150                 update_statst(&tcp_rtt_stats, (double)info.tcpi_rtt / 1000.0);
 2151 
 2152 #ifdef linux
 2153                 re_tx = info.tcpi_retransmits;
 2154                 pmtu = info.tcpi_pmtu;
 2155 #endif
 2156             }
 2157 #endif
 2158 
 2159             if (!persistent_connections)
 2160                 stats_close(&fd, &t_close, 0);
 2161 
 2162             dummy_ms = (dend - dafter_write_complete) * 1000.0;
 2163             update_statst(&t_request, dummy_ms);
 2164 
 2165             dummy_ms = (dend - dstart) * 1000.0;
 2166             update_statst(&t_total, dummy_ms);
 2167 
 2168             their_est_ts = (dend + dafter_connect) / 2.0; /* estimate of when other end started replying */
 2169             toff_diff_ts = ((double)their_ts - their_est_ts) * 1000.0;
 2170             update_statst(&stats_to, toff_diff_ts);
 2171 
 2172             if (json_output)
 2173             {
 2174                 char current_host[4096] = { 0 };
 2175 
 2176                 if (proxy_host)
 2177                     snprintf(current_host, sizeof current_host, "%s", hostname);
 2178                 else if (getnameinfo((const struct sockaddr *)&addr, sizeof addr, current_host, sizeof current_host, NULL, 0, NI_NUMERICHOST) == -1)
 2179                     snprintf(current_host, sizeof current_host, gettext("getnameinfo() failed: %d (%s)"), errno, strerror(errno));
 2180 
 2181                 emit_json(1, curncount, dstart, &t_resolve, &t_connect, &t_request, atoi(sc ? sc : "-1"), sc ? sc : "?", headers_len, len, Bps, current_host, fp, toff_diff_ts, tfo_success, &t_ssl, &t_write, &t_close, n_dynamic_cookies, &stats_to, &tcp_rtt_stats, re_tx, pmtu, recv_tos, &t_total);
 2182             }
 2183             else if (machine_readable)
 2184             {
 2185                 if (sc)
 2186                 {
 2187                     char *dummy = strchr(sc, ' ');
 2188                     if (dummy)
 2189                         *dummy = 0x00;
 2190 
 2191                     if (strstr(ok_str, sc))
 2192                         printf("%f", t_total.cur);
 2193                     else
 2194                         printf("%s", err_str);
 2195 
 2196                     if (show_statuscodes)
 2197                         printf(" %s", sc);
 2198                 }
 2199                 else
 2200                 {
 2201                     printf("%s", err_str);
 2202                 }
 2203 
 2204                 if(audible)
 2205                     putchar('\a');
 2206 
 2207                 printf("\n");
 2208             }
 2209             else if (!quiet && !nagios_mode && t_total.cur >= offset_show)
 2210             {
 2211                 char *tot_str = NULL;
 2212                 const char *i6_bs = "", *i6_be = "";
 2213                 char *line = NULL;
 2214                 const char *ms_color = c_green;
 2215                 char current_host[4096] = { 0 };
 2216                 char *operation = !persistent_connections ? gettext("connected to") : gettext("pinged host");
 2217                 const char *sep = c_bright, *unsep = c_normal;
 2218 
 2219                 if (show_ts || ncurses_mode)
 2220                 {
 2221                     char *ts = get_ts_str(verbose);
 2222 
 2223                     if (ncurses_mode)
 2224                         str_add(&line, "[%s] ", ts);
 2225                     else
 2226                         str_add(&line, "%s ", ts);
 2227 
 2228                     free(ts);
 2229                 }
 2230 
 2231                 if (curncount & 1)
 2232                 {
 2233                     str_add(&line, "%s", c_bright);
 2234 
 2235                     sep = c_normal;
 2236                     unsep = c_bright;
 2237                 }
 2238 
 2239                 if (proxy_host)
 2240                     snprintf(current_host, sizeof current_host, "%s", hostname);
 2241                 else if (getnameinfo((const struct sockaddr *)&addr, sizeof addr, current_host, sizeof current_host, NULL, 0, NI_NUMERICHOST) == -1)
 2242                     snprintf(current_host, sizeof current_host, gettext("getnameinfo() failed: %d (%s)"), errno, strerror(errno));
 2243 
 2244                 if (addr.sin6_family == AF_INET6)
 2245                 {
 2246                     i6_bs = "[";
 2247                     i6_be = "]";
 2248                 }
 2249 
 2250                 if (offset_red > 0.0 && t_total.cur >= offset_red)
 2251                     ms_color = c_red;
 2252                 else if (offset_yellow > 0.0 && t_total.cur >= offset_yellow)
 2253                     ms_color = c_yellow;
 2254 
 2255                 if (!ncurses_mode)
 2256                     str_add(&line, "%s%s ", c_white, operation);
 2257 
 2258                 if (persistent_connections && show_bytes_xfer)
 2259                     str_add(&line, gettext("%s%s%s%s%s:%s%d%s (%d/%d bytes), seq=%s%d%s "), c_red, i6_bs, current_host, i6_be, c_white, c_yellow, portnr, c_white, headers_len, len, c_blue, curncount-1, c_white);
 2260                 else
 2261                     str_add(&line, gettext("%s%s%s%s%s:%s%d%s (%d bytes), seq=%s%d%s "), c_red, i6_bs, current_host, i6_be, c_white, c_yellow, portnr, c_white, headers_len, c_blue, curncount-1, c_white);
 2262 
 2263                 tot_str = format_value(t_total.cur, 6, 2, abbreviate);
 2264 
 2265                 if (split)
 2266                 {
 2267                     char *res_str = t_resolve.cur_valid ? format_value(t_resolve.cur, 6, 2, abbreviate) : strdup(gettext("   n/a"));
 2268                     char *con_str = t_connect.cur_valid ? format_value(t_connect.cur, 6, 2, abbreviate) : strdup(gettext("   n/a"));
 2269                     char *wri_str = format_value(t_write.cur, 6, 2, abbreviate);
 2270                     char *req_str = format_value(t_request.cur, 6, 2, abbreviate);
 2271                     char *clo_str = format_value(t_close.cur, 6, 2, abbreviate);
 2272 
 2273                     str_add(&line, gettext("time=%s+%s+%s+%s+%s%s=%s%s%s%s ms %s%s%s"), res_str, con_str, wri_str, req_str, clo_str, sep, unsep, ms_color, tot_str, c_white, c_cyan, sc?sc:"", c_white);
 2274 
 2275                     free(clo_str);
 2276                     free(req_str);
 2277                     free(wri_str);
 2278                     free(con_str);
 2279                     free(res_str);
 2280                 }
 2281                 else
 2282                 {
 2283                     str_add(&line, gettext("time=%s%s%s ms %s%s%s"), ms_color, tot_str, c_white, c_cyan, sc?sc:"", c_white);
 2284                 }
 2285 
 2286                 free(tot_str);
 2287 
 2288                 if (persistent_did_reconnect)
 2289                 {
 2290                     str_add(&line, " %sC%s", c_magenta, c_white);
 2291                     persistent_did_reconnect = 0;
 2292                 }
 2293 
 2294                 if (show_Bps)
 2295                 {
 2296                     str_add(&line, " %dKB/s", (int)Bps / 1024);
 2297                     if (show_bytes_xfer)
 2298                         str_add(&line, " %dKB", (int)(bytes_transferred / 1024));
 2299                     if (ask_compression)
 2300                     {
 2301                         str_add(&line, " (");
 2302                         if (!is_compressed)
 2303                             str_add(&line, gettext("not "));
 2304                         str_add(&line, gettext("compressed)"));
 2305                     }
 2306                 }
 2307 
 2308                 if (use_ssl && show_fp && fp != NULL)
 2309                 {
 2310                     str_add(&line, " %s", fp);
 2311                 }
 2312 
 2313                 if (verbose > 0 && their_ts > 0)
 2314                 {
 2315                     /*  if diff_ts > 0, then their clock is running too fast */
 2316                     str_add(&line, gettext(" toff=%d"), (int)toff_diff_ts);
 2317                 }
 2318 
 2319                 if (verbose > 0 && age > 0)
 2320                     str_add(&line, gettext(" age=%d"), age);
 2321 
 2322                 str_add(&line, "%s", c_normal);
 2323 
 2324                 if (audible)
 2325                 {
 2326 #ifdef NC
 2327                     my_beep();
 2328 #else
 2329                     putchar('\a');
 2330 #endif
 2331                 }
 2332 
 2333 #ifdef TCP_TFO
 2334                 if (tfo_success)
 2335                     str_add(&line, " F");
 2336 #endif
 2337 
 2338 #ifdef NC
 2339                 if (ncurses_mode)
 2340                 {
 2341                     if (dummy_ms >= show_slow_log)
 2342                         slow_log("\n%s", line);
 2343                     else
 2344                         fast_log("\n%s", line);
 2345                 }
 2346                 else
 2347 #endif
 2348                 {
 2349                     printf("%s\n", line);
 2350                 }
 2351 
 2352                 do_aggregates(t_total.cur, (int)(get_ts() - started_at), n_aggregates, aggregates, verbose, show_ts);
 2353 
 2354                 free(line);
 2355             }
 2356 
 2357             if (show_statuscodes && ok_str != NULL && sc != NULL)
 2358             {
 2359                 scdummy = strchr(sc, ' ');
 2360                 if (scdummy) *scdummy = 0x00;
 2361 
 2362                 if (strstr(ok_str, sc) == NULL)
 2363                 {
 2364                     ok--;
 2365                     err++;
 2366                 }
 2367             }
 2368 
 2369             if (got_sigquit && !quiet && !machine_readable && !nagios_mode && !json_output)
 2370             {
 2371                 got_sigquit = 0;
 2372                 stats_line(0, complete_url, count, curncount, err, ok, started_at, verbose, &t_total, avg_httping_time, show_Bps ? &bps : NULL);
 2373             }
 2374 
 2375             break;
 2376         }
 2377 
 2378         emit_statuslines(get_ts() - started_at);
 2379 #ifdef NC
 2380         if (ncurses_mode)
 2381             update_stats(&t_resolve, &t_connect, &t_request, &t_total, &t_ssl, curncount, err, sc, fp, use_tfo, nc_graph, &stats_to, &tcp_rtt_stats, re_tx, pmtu, recv_tos, &t_close, &t_write, n_dynamic_cookies, abbreviate, &stats_header_size);
 2382 #endif
 2383 
 2384         free(sc);
 2385         free(fp);
 2386 
 2387 #ifdef NC
 2388         if (ncurses_mode)
 2389             update_terminal();
 2390         else
 2391 #endif
 2392             fflush(NULL);
 2393 
 2394         if (!stop && wait > 0)
 2395         {
 2396             double cur_sleep = wait;
 2397 
 2398             if (adaptive_interval)
 2399             {
 2400                 double now = get_ts();
 2401                 double interval_left = fmod(now - started_at, wait);
 2402 
 2403                 if (interval_left <= 0.0)
 2404                     cur_sleep = wait;
 2405                 else
 2406                     cur_sleep = wait - interval_left;
 2407             }
 2408 
 2409             myusleep((useconds_t)(cur_sleep * 1000000.0));
 2410         }
 2411 
 2412         reset_statst_cur(&t_resolve);
 2413         reset_statst_cur(&t_connect);
 2414         reset_statst_cur(&t_ssl);
 2415         reset_statst_cur(&t_write);
 2416         reset_statst_cur(&t_request);
 2417         reset_statst_cur(&t_close);
 2418         reset_statst_cur(&t_total);
 2419         reset_statst_cur(&stats_to);
 2420 #if defined(linux) || defined(__FreeBSD__)
 2421         reset_statst_cur(&tcp_rtt_stats);
 2422 #endif
 2423     }
 2424 
 2425 #ifdef NC
 2426     if (ncurses_mode)
 2427         end_ncurses();
 2428 #endif
 2429 
 2430     if (colors)
 2431         set_colors(0);
 2432 
 2433     if (ok)
 2434         avg_httping_time = t_total.avg / (double)t_total.n;
 2435     else
 2436         avg_httping_time = -1.0;
 2437 
 2438     if (!quiet && !machine_readable && !nagios_mode && !json_output)
 2439         stats_line(1, complete_url, count, curncount, err, ok, started_at, verbose, &t_total, avg_httping_time, show_Bps ? &bps : NULL);
 2440 
 2441 error_exit:
 2442     if (nagios_mode)
 2443         return nagios_result(ok, nagios_mode, nagios_exit_code, avg_httping_time, nagios_warn, nagios_crit);
 2444 
 2445     if (!json_output && !machine_readable)
 2446         printf("%s", c_very_normal);
 2447 
 2448     if (json_output)
 2449         printf("\n]\n");
 2450 
 2451     free_cookies(static_cookies, n_static_cookies);
 2452     free_cookies(dynamic_cookies, n_dynamic_cookies);
 2453     freeaddrinfo(ai);
 2454     free(request);
 2455     free(get);
 2456     free(hostname);
 2457     free(complete_url);
 2458 
 2459     free_headers(additional_headers, n_additional_headers);
 2460 
 2461     free(aggregates);
 2462 
 2463 #ifndef NO_SSL
 2464     if (use_ssl)
 2465     {
 2466         SSL_CTX_free(client_ctx);
 2467 
 2468         shutdown_ssl();
 2469     }
 2470 #endif
 2471 
 2472     fflush(NULL);
 2473 
 2474     if (ok)
 2475         return 0;
 2476 
 2477     return 127;
 2478 }