"Fossies" - the Fresh Open Source Software Archive

Member "HTTPing-2.9/nc.c" (29 Oct 2022, 18275 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 "nc.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 #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 }