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 #define _GNU_SOURCE 2 #include <stdio.h> 3 #include <libintl.h> 4 #include <math.h> 5 #include <poll.h> 6 #include <stdarg.h> 7 #include <signal.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <sys/ioctl.h> 11 12 #include <ncurses.h> 13 14 #include "error.h" 15 #include "colors.h" 16 #include "gen.h" 17 #include "main.h" 18 #include "kalman.h" 19 #ifdef FW 20 #include "fft.h" 21 #endif 22 #include "utils.h" 23 24 char win_resize = 0; 25 WINDOW *w_stats = NULL, *w_line1 = NULL, *w_slow = NULL, *w_line2 = NULL, *w_fast = NULL; 26 int stats_h = 10; 27 int logs_n = 0, slow_n = 0, fast_n = 0; 28 char **slow_history = NULL, **fast_history = NULL; 29 int window_history_n = 0; 30 char use_colors = 0; 31 32 double graph_limit = MY_DOUBLE_INF; 33 double hz = 1.0; 34 35 double *history = NULL, *history_temp = NULL, *history_fft_magn = NULL, *history_fft_phase = NULL; 36 char *history_set = NULL; 37 int history_n = 0; 38 39 char draw_phase = 0; 40 41 char pause_graphs = 0; 42 43 typedef enum { C_WHITE = 0, C_GREEN, C_YELLOW, C_BLUE, C_MAGENTA, C_CYAN, C_RED } color_t; 44 45 void update_terminal(void) 46 { 47 wnoutrefresh(w_stats); 48 wnoutrefresh(w_slow); 49 wnoutrefresh(w_fast); 50 51 doupdate(); 52 } 53 54 void create_windows(void) 55 { 56 char *r_a = gettext("realloc issue"); 57 int nr = 0; 58 59 if (w_stats) 60 { 61 delwin(w_stats); 62 delwin(w_line1); 63 delwin(w_slow); 64 delwin(w_line2); 65 delwin(w_fast); 66 } 67 68 #ifdef FW 69 fft_free(); 70 fft_init(max_x); 71 #endif 72 73 if (max_x > history_n) 74 { 75 history = (double *)realloc(history, sizeof(double) * max_x); 76 if (!history) 77 error_exit(r_a); 78 79 history_temp = (double *)realloc(history_temp, sizeof(double) * max_x); 80 if (!history_temp) 81 error_exit(r_a); 82 83 /* halve of it is enough really */ 84 history_fft_magn = (double *)realloc(history_fft_magn, sizeof(double) * max_x); 85 if (!history_fft_magn) 86 error_exit(r_a); 87 88 history_fft_phase = (double *)realloc(history_fft_phase, sizeof(double) * max_x); 89 if (!history_fft_phase) 90 error_exit(r_a); 91 92 history_set = (char *)realloc(history_set, sizeof(char) * max_x); 93 if (!history_set) 94 error_exit(r_a); 95 96 memset(&history[history_n], 0x00, (max_x - history_n) * sizeof(double)); 97 memset(&history_set[history_n], 0x00, (max_x - history_n) * sizeof(char)); 98 99 history_n = max_x; 100 } 101 102 if ((int)max_y > window_history_n) 103 { 104 slow_history = (char **)realloc(slow_history, sizeof(char *) * max_y); 105 if (!slow_history) 106 error_exit(r_a); 107 108 fast_history = (char **)realloc(fast_history, sizeof(char *) * max_y); 109 if (!fast_history) 110 error_exit(r_a); 111 112 memset(&slow_history[window_history_n], 0x00, (max_y - window_history_n) * sizeof(char *)); 113 memset(&fast_history[window_history_n], 0x00, (max_y - window_history_n) * sizeof(char *)); 114 115 window_history_n = max_y; 116 } 117 118 w_stats = newwin(stats_h, max_x, 0, 0); 119 scrollok(w_stats, false); 120 121 w_line1 = newwin(1, max_x, stats_h, 0); 122 scrollok(w_line1, false); 123 wnoutrefresh(w_line1); 124 125 logs_n = max_y - (stats_h + 1 + 1); 126 fast_n = logs_n * 11 / 20; 127 slow_n = logs_n - fast_n; 128 129 w_slow = newwin(slow_n, max_x, (stats_h + 1), 0); 130 scrollok(w_slow, true); 131 132 w_line2 = newwin(1, max_x, (stats_h + 1) + slow_n, 0); 133 scrollok(w_line2, false); 134 wnoutrefresh(w_line2); 135 136 w_fast = newwin(fast_n, max_x, (stats_h + 1) + slow_n + 1, 0); 137 scrollok(w_fast, true); 138 139 wattron(w_line1, A_REVERSE); 140 wattron(w_line2, A_REVERSE); 141 for(nr=0; nr<max_x; nr++) 142 { 143 wprintw(w_line1, " "); 144 wprintw(w_line2, " "); 145 } 146 wattroff(w_line2, A_REVERSE); 147 wattroff(w_line1, A_REVERSE); 148 149 wnoutrefresh(w_line1); 150 wnoutrefresh(w_line2); 151 152 doupdate(); 153 154 signal(SIGWINCH, handler); 155 } 156 157 void myprintloc(WINDOW *w, int y, int x, const char *fmt, ...) 158 { 159 char *line = NULL; 160 int line_len = 0; 161 va_list ap; 162 163 va_start(ap, fmt); 164 line_len = vasprintf(&line, fmt, ap); 165 va_end(ap); 166 167 wmove(w, y, x); 168 169 if (use_colors) 170 { 171 int index = 0; 172 173 for(index=0; index<line_len; index++) 174 { 175 static int clr = C_WHITE, att = A_NORMAL; 176 177 if (line[index] == COLOR_ESCAPE[0]) 178 { 179 switch(line[++index]) 180 { 181 case '1': 182 clr = C_RED; 183 break; 184 case '2': 185 clr = C_BLUE; 186 break; 187 case '3': 188 clr = C_GREEN; 189 break; 190 case '4': 191 clr = C_YELLOW; 192 break; 193 case '5': 194 clr = C_MAGENTA; 195 break; 196 case '6': 197 clr = C_CYAN; 198 break; 199 case '7': 200 clr = C_WHITE; 201 break; 202 case '8': 203 att = A_BOLD; 204 break; 205 case '9': 206 att = A_NORMAL; 207 break; 208 } 209 210 wattr_set(w, att, clr, NULL); 211 } 212 else 213 { 214 waddch(w, line[index]); 215 } 216 } 217 } 218 else 219 { 220 mvwprintw(w, y, x, "%s", line); 221 } 222 223 free(line); 224 } 225 226 void myprint(WINDOW *w, const char *what) 227 { 228 if (use_colors) 229 { 230 int y = -1, x = -1; 231 232 getyx(w, y, x); 233 234 myprintloc(w, y, x, what); 235 } 236 else 237 { 238 wprintw(w, "%s", what); 239 } 240 } 241 242 void recreate_terminal(void) 243 { 244 int index = 0; 245 246 determine_terminal_size(&max_y, &max_x); 247 248 resizeterm(max_y, max_x); 249 250 endwin(); 251 refresh(); 252 253 create_windows(); 254 255 for(index = window_history_n - 1; index >= 0; index--) 256 { 257 if (slow_history[index]) 258 myprint(w_slow, slow_history[index]); 259 if (fast_history[index]) 260 myprint(w_fast, fast_history[index]); 261 } 262 263 doupdate(); 264 265 win_resize = 0; 266 } 267 268 void init_ncurses_ui(double graph_limit_in, double hz_in, char use_colors_in) 269 { 270 graph_limit = graph_limit_in; 271 hz = hz_in; 272 use_colors = use_colors_in; 273 274 initscr(); 275 start_color(); 276 keypad(stdscr, TRUE); 277 intrflush(stdscr, FALSE); 278 noecho(); 279 refresh(); 280 nodelay(stdscr, FALSE); 281 meta(stdscr, TRUE); /* enable 8-bit input */ 282 idlok(stdscr, TRUE); /* may give a little clunky screenredraw */ 283 idcok(stdscr, TRUE); /* may give a little clunky screenredraw */ 284 leaveok(stdscr, FALSE); 285 286 init_pair(C_WHITE, COLOR_WHITE, COLOR_BLACK); 287 init_pair(C_CYAN, COLOR_CYAN, COLOR_BLACK); 288 init_pair(C_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); 289 init_pair(C_BLUE, COLOR_BLUE, COLOR_BLACK); 290 init_pair(C_YELLOW, COLOR_YELLOW, COLOR_BLACK); 291 init_pair(C_GREEN, COLOR_GREEN, COLOR_BLACK); 292 init_pair(C_RED, COLOR_RED, COLOR_BLACK); 293 294 kalman_init(0.0); 295 296 recreate_terminal(); 297 } 298 299 void end_ncurses(void) 300 { 301 int index = 0; 302 303 for(index=0; index<window_history_n; index++) 304 { 305 free(slow_history[index]); 306 free(fast_history[index]); 307 } 308 309 free(slow_history); 310 free(fast_history); 311 312 if (w_stats) 313 { 314 delwin(w_stats); 315 delwin(w_line1); 316 delwin(w_slow); 317 delwin(w_line2); 318 delwin(w_fast); 319 } 320 321 endwin(); 322 323 free(history); 324 free(history_set); 325 326 #ifdef FW 327 fft_free(); 328 fft_stop(); 329 #endif 330 free(history_temp); 331 free(history_fft_phase); 332 free(history_fft_magn); 333 } 334 335 void fast_log(const char *fmt, ...) 336 { 337 char buffer[4096] = { 0 }; 338 va_list ap; 339 340 va_start(ap, fmt); 341 vsnprintf(buffer, sizeof buffer, fmt, ap); 342 va_end(ap); 343 344 free(fast_history[window_history_n - 1]); 345 memmove(&fast_history[1], &fast_history[0], (window_history_n - 1) * sizeof(char *)); 346 fast_history[0] = strdup(buffer); 347 348 myprint(w_fast, buffer); 349 350 if (win_resize) 351 recreate_terminal(); 352 } 353 354 void slow_log(const char *fmt, ...) 355 { 356 char buffer[4096] = { 0 }; 357 va_list ap; 358 359 va_start(ap, fmt); 360 vsnprintf(buffer, sizeof buffer, fmt, ap); 361 va_end(ap); 362 363 free(slow_history[window_history_n - 1]); 364 memmove(&slow_history[1], &slow_history[0], (window_history_n - 1) * sizeof(char *)); 365 slow_history[0] = strdup(buffer); 366 367 myprint(w_slow, buffer); 368 369 if (win_resize) 370 recreate_terminal(); 371 } 372 373 void my_beep(void) 374 { 375 beep(); 376 } 377 378 void status_line(char *fmt, ...) 379 { 380 char *line = NULL; 381 va_list ap; 382 383 wattron(w_line2, A_REVERSE); 384 385 wmove(w_line2, 0, 0); 386 387 va_start(ap, fmt); 388 389 vasprintf(&line, fmt, ap); 390 myprint(w_line2, line); 391 free(line); 392 393 va_end(ap); 394 395 wattroff(w_line2, A_REVERSE); 396 397 wnoutrefresh(w_line2); 398 399 if (win_resize) 400 recreate_terminal(); 401 } 402 403 void draw_column(WINDOW *win, int x, int height, char overflow, char limitter) 404 { 405 void *dummy = NULL; 406 int y = 0, end_y = 0, win_h = 0, win_w = 0; 407 408 getmaxyx(win, win_h, win_w); 409 (void)win_w; /* silence warnings */ 410 411 end_y = max(0, win_h - height); 412 413 for(y=win_h - 1; y >= end_y; y--) 414 mvwchgat(win, y, x, 1, A_REVERSE, C_YELLOW, dummy); 415 416 if (limitter) 417 mvwchgat(win, 0, x, 1, A_REVERSE, C_BLUE, dummy); 418 else if (overflow) 419 mvwchgat(win, 0, x, 1, A_REVERSE, C_RED, dummy); 420 else if (height == 0) 421 mvwchgat(win, win_h - 1, x, 1, A_REVERSE, C_GREEN, dummy); 422 } 423 424 void draw_rad_column(WINDOW *win, int x, double val) 425 { 426 void *dummy = NULL; 427 int y = 0, end_y = 0, win_h = 0, win_w = 0; 428 int center_y = 0; 429 430 getmaxyx(win, win_h, win_w); 431 (void)win_w; /* silence warnings */ 432 433 center_y = win_h / 2; 434 end_y = (int)((double)(win_h / 2) * ((val / PI) + 1.0)); 435 436 if (end_y > center_y) 437 { 438 for(y=center_y; y<end_y; y++) 439 mvwchgat(win, y, x, 1, A_REVERSE, C_YELLOW, dummy); 440 } 441 else 442 { 443 for(y=end_y; y<center_y; y++) 444 mvwchgat(win, y, x, 1, A_REVERSE, C_YELLOW, dummy); 445 } 446 } 447 448 double get_cur_scc() 449 { 450 double scc_val = 0.0; 451 double prev_val = 0.0, u0 = 0.0; 452 double t[3] = { 0 }; 453 int loop = 0, n = 0; 454 char first = 1; 455 456 t[0] = t[1] = t[2] = 0.0; 457 458 for(loop=0; loop<history_n; loop++) 459 { 460 double cur_val = history[loop]; 461 462 if (!history_set[loop]) 463 continue; 464 465 if (first) 466 { 467 prev_val = 0; 468 u0 = cur_val; 469 first = 0; 470 } 471 else 472 { 473 t[0] += prev_val * cur_val; 474 } 475 476 t[1] = t[1] + cur_val; 477 t[2] = t[2] + (cur_val * cur_val); 478 prev_val = cur_val; 479 480 n++; 481 } 482 483 t[0] = t[0] + prev_val * u0; 484 t[1] = t[1] * t[1]; 485 486 scc_val = (double)n * t[2] - t[1]; 487 488 if (scc_val == 0.0) 489 return -1.0; 490 491 return ((double)n * t[0] - t[1]) / scc_val; 492 } 493 494 #ifdef FW 495 void draw_fft(void) 496 { 497 double mx_mag = 0.0; 498 int index = 0, highest = 0; 499 int cx = 0, cy = 0; 500 /* double max_freq = hz / 2.0; */ 501 double highest_freq = 0, avg_freq_index = 0.0, total_val = 0.0, avg_freq = 0.0; 502 int dummy = 0; 503 504 getyx(w_slow, cy, cx); 505 506 for(index=0; index<max_x; index++) 507 { 508 double val = 0.0; 509 510 if (history_set[index]) 511 val = history[index]; 512 else 513 val = index > 0 ? history[index - 1] : 0; 514 515 if (val > graph_limit) 516 val = graph_limit; 517 518 history_temp[index] = val; 519 } 520 521 fft_do(history_temp, history_fft_magn, history_fft_phase); 522 523 for(index=1; index<max_x/2; index++) 524 { 525 avg_freq_index += (double)index * history_fft_magn[index]; 526 total_val += history_fft_magn[index]; 527 528 if (history_fft_magn[index] > mx_mag) 529 { 530 mx_mag = history_fft_magn[index]; 531 highest = index; 532 } 533 } 534 535 highest_freq = (hz / (double)max_x) * (double)highest; 536 537 avg_freq_index /= total_val; 538 avg_freq = (hz / (double)max_x) * avg_freq_index; 539 540 wattron(w_line1, A_REVERSE); 541 myprintloc(w_line1, 0, 38, gettext("highest: %6.2fHz, avg: %6.2fHz"), highest_freq, avg_freq); 542 wattroff(w_line1, A_REVERSE); 543 wnoutrefresh(w_line1); 544 545 dummy = max_x / 2 + 1; 546 547 if (draw_phase) 548 { 549 int y = 0; 550 551 for(y=0; y<slow_n; y++) 552 mvwchgat(w_slow, y, dummy, 1, A_REVERSE, C_WHITE, NULL); 553 554 for(index=0; index<slow_n; index++) 555 mvwchgat(w_slow, index, 0, max_x, A_NORMAL, C_WHITE, NULL); 556 557 for(index=1; index<dummy - 1; index++) 558 draw_rad_column(w_slow, index - 1, history_fft_phase[index]); 559 } 560 else 561 { 562 for(index=0; index<slow_n; index++) 563 mvwchgat(w_slow, index, max_x / 2, max_x / 2, A_NORMAL, C_WHITE, NULL); 564 } 565 566 for(index=1; index<dummy; index++) 567 { 568 int height_magn = (int)((double)slow_n * (history_fft_magn[index] / mx_mag)); 569 draw_column(w_slow, max_x / 2 + index - 1, height_magn, 0, 0); 570 } 571 572 wmove(w_slow, cy, cx); 573 574 wnoutrefresh(w_slow); 575 } 576 #endif 577 578 double calc_trend() 579 { 580 int half = history_n / 2, index = 0; 581 double v1 = 0.0, v2 = 0.0; 582 int n_v1 = 0, n_v2 = 0; 583 584 for(index=0; index<half; index++) 585 { 586 if (!history_set[index]) 587 continue; 588 589 v1 += history[index]; 590 n_v1++; 591 } 592 593 for(index=half; index<history_n; index++) 594 { 595 if (!history_set[index]) 596 continue; 597 598 v2 += history[index]; 599 n_v2++; 600 } 601 602 if (n_v2 == 0 || n_v1 == 0) 603 return 0; 604 605 v1 /= (double)n_v1; 606 v2 /= (double)n_v2; 607 608 return (v1 - v2) / (v2 / 100.0); 609 } 610 611 void draw_graph(double val) 612 { 613 int index = 0, loop_n = min(max_x, history_n), n = 0, n2 = 0; 614 double avg = 0, sd = 0; 615 double avg2 = 0, sd2 = 0; 616 double mi = MY_DOUBLE_INF, ma = -MY_DOUBLE_INF, diff = 0.0; 617 618 for(index=0; index<loop_n; index++) 619 { 620 double val = history[index]; 621 622 if (!history_set[index]) 623 continue; 624 625 mi = min(val, mi); 626 ma = max(val, ma); 627 628 avg += val; 629 sd += val * val; 630 n++; 631 } 632 633 if (!n) 634 return; 635 636 avg /= (double)n; 637 sd = sqrt((sd / (double)n) - pow(avg, 2.0)); 638 639 mi = max(mi, avg - sd); 640 ma = min(ma, avg + sd); 641 642 for(index=0; index<loop_n; index++) 643 { 644 double val = history[index]; 645 646 if (!history_set[index]) 647 continue; 648 649 if (val < mi || val > ma) 650 continue; 651 652 avg2 += val; 653 sd2 += val * val; 654 n2++; 655 } 656 657 if (n2) 658 { 659 avg2 /= (double)n2; 660 sd2 = sqrt((sd2 / (double)n2) - pow(avg2, 2.0)); 661 662 mi = max(mi, avg2 - sd2); 663 ma = min(ma, avg2 + sd2); 664 diff = ma - mi; 665 666 if (diff == 0.0) 667 diff = 1.0; 668 669 wattron(w_line1, A_REVERSE); 670 myprintloc(w_line1, 0, 0, gettext("graph range: %7.2fms - %7.2fms "), mi, ma); 671 wattroff(w_line1, A_REVERSE); 672 wnoutrefresh(w_line1); 673 674 /* fprintf(stderr, "%d| %f %f %f %f\n", h_stats.n, mi, avg, ma, sd); */ 675 676 for(index=0; index<loop_n; index++) 677 { 678 char overflow = 0, limitter = 0; 679 double val = 0, height = 0; 680 int i_h = 0, x = max_x - (1 + index); 681 682 if (!history_set[index]) 683 { 684 mvwchgat(w_stats, stats_h - 1, x, 1, A_REVERSE, C_CYAN, NULL); 685 continue; 686 } 687 688 if (history[index] < graph_limit) 689 val = history[index]; 690 else 691 { 692 val = graph_limit; 693 limitter = 1; 694 } 695 696 height = (val - mi) / diff; 697 698 if (height > 1.0) 699 { 700 height = 1.0; 701 overflow = 1; 702 } 703 704 i_h = (int)(height * stats_h); 705 /* fprintf(stderr, "%d %f %f %d %d\n", index, history[index], height, i_h, overflow); */ 706 707 draw_column(w_stats, x, i_h, overflow, limitter); 708 } 709 } 710 } 711 712 void show_stats_t(int y, int x, char *header, stats_t *data, char abbreviate) 713 { 714 if (data -> valid) 715 { 716 char *cur_str = format_value(data -> cur, 6, 2, abbreviate); 717 char *min_str = format_value(data -> min, 6, 2, abbreviate); 718 char *avg_str = format_value(data -> avg / (double)data -> n, 6, 2, abbreviate); 719 char *max_str = format_value(data -> max, 6, 2, abbreviate); 720 char *sd_str = format_value(calc_sd(data), 6, 2, abbreviate); 721 722 myprintloc(w_stats, y, x, "%s: %s %s %s %s %s", header, 723 data -> cur_valid ? cur_str : gettext(" n/a"), 724 min_str, avg_str, max_str, sd_str); 725 726 free(sd_str); 727 free(max_str); 728 free(avg_str); 729 free(min_str); 730 free(cur_str); 731 } 732 else 733 { 734 myprintloc(w_stats, y, x, gettext("%s: n/a"), header); 735 } 736 } 737 738 void update_stats(stats_t *resolve, stats_t *connect, stats_t *request, stats_t *total, stats_t *ssl_setup, int n_ok, int n_fail, const char *last_connect_str, const char *fp, char use_tfo, char dg, stats_t *st_to, stats_t *tcp_rtt_stats, int re_tx, int pmtu, int tos, stats_t *close_st, stats_t *t_write, int n_cookies, char abbreviate, stats_t *stats_header_size) 739 { 740 double k = 0.0; 741 char force_redraw = 0; 742 struct pollfd p = { 0, POLLIN, 0 }; 743 744 werase(w_stats); 745 746 if (n_ok) 747 { 748 char buffer[4096] = { 0 }, *scc_str = NULL, *kalman_str = NULL; 749 int buflen = 0; 750 751 myprintloc(w_stats, 0, 0, " %6s %6s %6s %6s %6s", gettext("latest"), gettext("min"), gettext("avg"), gettext("max"), gettext("sd")); 752 show_stats_t(1, 0, gettext("resolve"), resolve, abbreviate); 753 show_stats_t(2, 0, gettext("connect"), connect, abbreviate); 754 show_stats_t(3, 0, gettext("ssl "), ssl_setup, abbreviate); 755 show_stats_t(4, 0, gettext("send "), t_write, abbreviate); 756 show_stats_t(5, 0, gettext("request"), request, abbreviate); 757 show_stats_t(6, 0, gettext("close "), close_st, abbreviate); 758 show_stats_t(7, 0, gettext("total "), total, abbreviate); 759 760 scc_str = format_value(get_cur_scc(), 5, 3, abbreviate); 761 kalman_str = format_value(kalman_do(total -> cur), 5, 3, abbreviate); 762 myprintloc(w_stats, 8, 0, gettext("ok: %3d, fail: %3d%s, scc: %s, kalman: %s"), n_ok, n_fail, use_tfo ? gettext(", with TFO") : "", scc_str, kalman_str); 763 free(kalman_str); 764 free(scc_str); 765 766 if (max_x >= 44 * 2 + 1) 767 { 768 double trend = calc_trend(); 769 char trend_dir = ' '; 770 771 myprintloc(w_stats, 0, 45, " %6s %6s %6s %6s %6s", gettext("cur"), gettext("min"), gettext("avg"), gettext("max"), gettext("sd")); 772 show_stats_t(1, 45, gettext("t offst"), st_to, abbreviate); 773 774 #if defined(linux) || defined(__FreeBSD__) 775 show_stats_t(2, 45, gettext("tcp rtt"), tcp_rtt_stats, abbreviate); 776 #endif 777 show_stats_t(3, 45, gettext("headers"), stats_header_size, abbreviate); 778 779 if (trend < 0) 780 trend_dir = '-'; 781 else if (trend > 0) 782 trend_dir = '+'; 783 784 myprintloc(w_stats, 8, 48, gettext("# cookies: %d"), n_cookies); 785 786 #ifdef linux 787 myprintloc(w_stats, 9, 48, gettext("trend: %c%6.2f%%, re-tx: %2d, pmtu: %5d, TOS: %02x"), trend_dir, fabs(trend), re_tx, pmtu, tos); 788 #else 789 myprintloc(w_stats, 9, 48, gettext("trend: %c%6.2f%%, TOS: %02x"), trend_dir, fabs(trend), tos); 790 #endif 791 } 792 793 buflen = snprintf(buffer, sizeof buffer, gettext("HTTP rc: %s, SSL fp: %s"), last_connect_str, fp ? fp : gettext("n/a")); 794 795 if (buflen <= max_x) 796 myprintloc(w_stats, 9, 0, "%s", buffer); 797 else 798 { 799 static char prev_sf[48] = { 0 }; 800 801 myprintloc(w_stats, 9, 0, gettext("http result code: %s"), last_connect_str); 802 803 if (fp && strcmp(prev_sf, fp)) 804 { 805 slow_log(gettext("\nSSL fingerprint: %s"), fp); 806 807 memcpy(prev_sf, fp, 47); 808 } 809 } 810 } 811 812 memmove(&history[1], &history[0], (history_n - 1) * sizeof(double)); 813 memmove(&history_set[1], &history_set[0], (history_n - 1) * sizeof(char)); 814 815 history[0]= total -> cur; 816 history_set[0] = 1; 817 818 if (poll(&p, 1, 0) == 1 && p.revents == POLLIN) 819 { 820 int c = getch(); 821 822 if (c == 12) /* ^L */ 823 force_redraw = 1; 824 825 if (c == 'H') 826 pause_graphs = !pause_graphs; 827 828 if (c == 'q') 829 stop = 1; 830 } 831 832 if (dg && !pause_graphs) 833 { 834 draw_graph(k); 835 #ifdef FW 836 draw_fft(); 837 #endif 838 } 839 840 wnoutrefresh(w_stats); 841 842 if (win_resize || force_redraw) 843 recreate_terminal(); 844 }