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 }