From f5a6f751680a6f93bb66bbcb5891e9fb60c1542e Mon Sep 17 00:00:00 2001 From: lordrasmus Date: Fri, 2 Jun 2023 14:53:24 +0200 Subject: [PATCH] first try for a top like view --- src/Makefile.am | 2 +- src/data_types.h | 45 +++++++++++++++ src/fping.c | 131 +++++++++++++++++++++++--------------------- src/top_view.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ src/top_view.h | 8 +++ 5 files changed, 262 insertions(+), 63 deletions(-) create mode 100644 src/data_types.h create mode 100644 src/top_view.c create mode 100644 src/top_view.h diff --git a/src/Makefile.am b/src/Makefile.am index c58e474..f92e1ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ AM_CFLAGS = -Wall -Wextra -Wno-sign-compare sbin_PROGRAMS = fping -fping_SOURCES = fping.c seqmap.c socket4.c fping.h options.h seqmap.h optparse.c optparse.h +fping_SOURCES = fping.c seqmap.c socket4.c fping.h options.h seqmap.h optparse.c optparse.h top_view.c fping_DEPENDENCIES = ../config.h if IPV6 diff --git a/src/data_types.h b/src/data_types.h new file mode 100644 index 0000000..33cb14f --- /dev/null +++ b/src/data_types.h @@ -0,0 +1,45 @@ + +#ifndef FPING_DATA_TYPES_H +#define FPING_DATA_TYPES_H + +#include +#include + +struct event; +typedef struct host_entry { + int i; /* index into array */ + char *name; /* name as given by user */ + char *host; /* text description of host */ + struct sockaddr_storage saddr; /* internet address */ + socklen_t saddr_len; + int64_t timeout; /* time to wait for response */ + int64_t last_send_time; /* time of last packet sent */ + int num_sent; /* number of ping packets sent (for statistics) */ + int num_recv; /* number of pings received (duplicates ignored) */ + int num_recv_total; /* number of pings received, including duplicates */ + int64_t max_reply; /* longest response time */ + int64_t min_reply; /* shortest response time */ + int64_t total_time; /* sum of response times */ + /* _i -> splits (reset on every report interval) */ + int num_sent_i; /* number of ping packets sent */ + int num_recv_i; /* number of pings received */ + int64_t max_reply_i; /* longest response time */ + int64_t min_reply_i; /* shortest response time */ + int64_t total_time_i; /* sum of response times */ + int64_t *resp_times; /* individual response times */ + + int top_view_print_pos; + int top_view_last_timeouts; + int top_view_last_timeouts_count; + int top_view_last_timeouts_seq; + char last_timeout_time[100]; + + /* to avoid allocating two struct events each time that we send a ping, we + * preallocate here two struct events for each ping that we might send for + * this host. */ + struct event *event_storage_ping; + struct event *event_storage_timeout; +} HOST_ENTRY; + + +#endif diff --git a/src/fping.c b/src/fping.c index 9bda407..59f9d0d 100644 --- a/src/fping.c +++ b/src/fping.c @@ -38,6 +38,8 @@ extern "C" { #include "config.h" #include "options.h" #include "optparse.h" +#include "top_view.h" +#include "data_types.h" #include #include @@ -213,35 +215,7 @@ char *icmp_unreach_str[16] = { #define ICMP_UNREACH_MAXTYPE 15 -struct event; -typedef struct host_entry { - int i; /* index into array */ - char *name; /* name as given by user */ - char *host; /* text description of host */ - struct sockaddr_storage saddr; /* internet address */ - socklen_t saddr_len; - int64_t timeout; /* time to wait for response */ - int64_t last_send_time; /* time of last packet sent */ - int num_sent; /* number of ping packets sent (for statistics) */ - int num_recv; /* number of pings received (duplicates ignored) */ - int num_recv_total; /* number of pings received, including duplicates */ - int64_t max_reply; /* longest response time */ - int64_t min_reply; /* shortest response time */ - int64_t total_time; /* sum of response times */ - /* _i -> splits (reset on every report interval) */ - int num_sent_i; /* number of ping packets sent */ - int num_recv_i; /* number of pings received */ - int64_t max_reply_i; /* longest response time */ - int64_t min_reply_i; /* shortest response time */ - int64_t total_time_i; /* sum of response times */ - int64_t *resp_times; /* individual response times */ - - /* to avoid allocating two struct events each time that we send a ping, we - * preallocate here two struct events for each ping that we might send for - * this host. */ - struct event *event_storage_ping; - struct event *event_storage_timeout; -} HOST_ENTRY; + int event_storage_count; /* how many events can be stored in host_entry->event_storage_xxx */ @@ -357,6 +331,7 @@ int multif_flag, timeout_flag; int outage_flag = 0; int timestamp_flag = 0; int random_data_flag = 0; +int top_view = 0; #if defined(DEBUG) || defined(_DEBUG) int randomly_lose_flag, trace_flag, print_per_system_flag; int lose_factor; @@ -535,6 +510,7 @@ int main(int argc, char **argv) { NULL, 'T', OPTPARSE_REQUIRED }, { "unreach", 'u', OPTPARSE_NONE }, { "version", 'v', OPTPARSE_NONE }, + { "top", 'k', OPTPARSE_NONE }, { "reachable", 'x', OPTPARSE_REQUIRED }, #if defined(DEBUG) || defined(_DEBUG) { NULL, 'z', OPTPARSE_REQUIRED }, @@ -825,6 +801,9 @@ int main(int argc, char **argv) outage_flag = 1; break; + case 'k': + top_view = 1; + break; case '?': fprintf(stderr, "%s: %s\n", argv[0], optparse_state.errmsg); fprintf(stderr, "see 'fping -h' for usage information\n"); @@ -833,6 +812,7 @@ int main(int argc, char **argv) } } + /* permanently drop privileges */ if (suid != getuid() && setuid(getuid())) { perror("fatal: failed to permanently drop privileges"); @@ -1303,8 +1283,11 @@ void main_loop() struct event *event; struct host_entry *h; + + while (event_queue_ping.first || event_queue_timeout.first) { dbg_printf("%s", "# main_loop\n"); + /* timeout event ? */ if (event_queue_timeout.first && event_queue_timeout.first->ev_time - current_time_ns <= 0) { @@ -1319,23 +1302,28 @@ void main_loop() if (timestamp_flag) { printf("[%.5f] ", (double)current_time_ns / 1e9); } - printf("%-*s : [%d], timed out", - max_hostname_len, h->host, event->ping_index); - if (h->num_recv > 0) { - printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv)); - } - else { - printf(" (NaN avg, "); - } - if (h->num_recv <= h->num_sent) { - printf("%d%% loss)", - ((h->num_sent - h->num_recv) * 100) / h->num_sent); - } - else { - printf("%d%% return)", - (h->num_recv_total * 100) / h->num_sent); + if( top_view == 0 ){ + printf("%-*s : [%d], timed out", + max_hostname_len, h->host, event->ping_index); + + if (h->num_recv > 0) { + printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv)); + } + else { + printf(" (NaN avg, "); + } + if (h->num_recv <= h->num_sent) { + printf("%d%% loss)", + ((h->num_sent - h->num_recv) * 100) / h->num_sent); + } + else { + printf("%d%% return)", + (h->num_recv_total * 100) / h->num_sent); + } + printf("\n"); + }else{ + print_top_view( h, 1 ); } - printf("\n"); } /* do we need to send a retry? */ @@ -1355,6 +1343,7 @@ void main_loop() continue; } + /* ping event ? */ if (event_queue_ping.first && event_queue_ping.first->ev_time - current_time_ns <= 0) { /* Make sure that we don't ping more than once every "interval" */ @@ -1410,6 +1399,7 @@ void main_loop() dbg_printf("next timeout event in %.0f ms (%s)\n", wait_time_timeout / 1e6, event_queue_timeout.first->host->host); } + /* When is the next report due? */ if (report_interval && (loop_flag || count_flag)) { int64_t wait_time_next_report = next_report_time - current_time_ns; @@ -1441,8 +1431,10 @@ void main_loop() ; /* process other replies in the queue */ } + update_current_time(); + if (status_snapshot) { status_snapshot = 0; print_per_system_splits(); @@ -1450,6 +1442,7 @@ void main_loop() /* Print report */ if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) { + if (netdata_flag) print_netdata(); else @@ -1460,6 +1453,10 @@ void main_loop() } } } + + if ( top_view == 1 ){ + top_view_end(); + } } /************************************************************ @@ -2272,6 +2269,8 @@ int decode_icmp_ipv6( } #endif + + int wait_for_reply(int64_t wait_time) { int result; @@ -2430,26 +2429,34 @@ int wait_for_reply(int64_t wait_time) printf("[%.5f] ", (double)recv_time / 1e9); } avg = h->total_time / h->num_recv; - printf("%-*s : [%d], %d bytes, %s ms", - max_hostname_len, h->host, this_count, result, sprint_tm(this_reply)); - printf(" (%s avg, ", sprint_tm(avg)); - if (h->num_recv <= h->num_sent) { - printf("%d%% loss)", - ((h->num_sent - h->num_recv) * 100) / h->num_sent); - } - else { - printf("%d%% return)", - (h->num_recv_total * 100) / h->num_sent); - } + - if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) { - char buf[INET6_ADDRSTRLEN]; - getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); - fprintf(stderr, " [<- %s]", buf); - } + if ( top_view == 0 ){ + + printf("%-*s : [%d], %d bytes, %s ms", + max_hostname_len, h->host, this_count, result, sprint_tm(this_reply)); + printf(" (%s avg, ", sprint_tm(avg)); + + if (h->num_recv <= h->num_sent) { + printf("%d%% loss)", + ((h->num_sent - h->num_recv) * 100) / h->num_sent); + } + else { + printf("%d%% return)", + (h->num_recv_total * 100) / h->num_sent); + } - printf("\n"); + if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) { + char buf[INET6_ADDRSTRLEN]; + getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); + fprintf(stderr, " [<- %s]", buf); + } + + printf("\n"); + }else{ + print_top_view( h, 0 ); + } } return 1; diff --git a/src/top_view.c b/src/top_view.c new file mode 100644 index 0000000..ef10d50 --- /dev/null +++ b/src/top_view.c @@ -0,0 +1,139 @@ + +#include +#include +#include + +#include "top_view.h" + +static char out_buffer[1000]; + +static int print_top_view_init_printed = 0; +static int next_view_pos = 1; + +extern int64_t perhost_interval; + +static void pos_printf(uint8_t col, uint8_t row, char* format, ...) +{ + + int pos = 0; + + va_list argp; + va_start(argp, format); + + + memset(out_buffer, 0, sizeof(out_buffer)); + + pos += sprintf(&out_buffer[pos], "\033[%d;%df", col, row); + + pos += vsnprintf(&out_buffer[pos], sizeof(out_buffer) - pos, format, argp); + + puts( out_buffer ); +} + +static void line_clear(uint8_t col) +{ + + int pos = 0; + + memset(out_buffer, 0, sizeof(out_buffer)); + + pos += sprintf(&out_buffer[pos], "\033[%d;%df\033[2K", col, 1); + + //pos += vsnprintf(&out_buffer[pos], sizeof(out_buffer) - pos, format, argp); + + puts( out_buffer ); +} + +#define HOST_POS 2 +#define SEND_POS 20 +#define RECV_POS 30 +#define LOST_POS 40 +#define TIMEOUT_POS 50 +#define TIMEOUT_TOTAL_POS 60 +#define TIMEOUT_SEQ_POS 70 +#define TIMEOUT_TIME_POS 80 + + + +void top_view_end( void ){ + // Cursor deaktivieren + puts( "\033[?25h"); +} + +static void print_top_view_init( void ){ + if ( print_top_view_init_printed == 1 ) return; + + print_top_view_init_printed = 1; + + int pos = 0; + // Screen löschen und Farbe deaktivieren + pos += sprintf(&out_buffer[pos], "\033[00m\033[2J"); + + // Cursor deaktivieren + pos += sprintf(&out_buffer[pos], "\033[?25l"); + + puts( out_buffer ); + + pos_printf( 2 , 10 , "fping top view ( period : %d ms )", ( perhost_interval / 1000 / 1000 )); + + pos_printf( 4 , HOST_POS , "host"); + pos_printf( 4 , SEND_POS , "send"); + pos_printf( 4 , RECV_POS , "recv"); + pos_printf( 4 , LOST_POS , "lost"); + pos_printf( 4 , TIMEOUT_POS , "timeouts: "); + pos_printf( 4 , TIMEOUT_TOTAL_POS , "total"); + pos_printf( 4 , TIMEOUT_SEQ_POS , "seq"); + pos_printf( 4 , TIMEOUT_TIME_POS , "time"); + + +} + + + +void print_top_view( HOST_ENTRY *h, int timeout ){ + + print_top_view_init(); + + if ( h->top_view_print_pos == 0 ){ + h->top_view_print_pos = next_view_pos++; + sprintf(h->last_timeout_time, "0 ms" ); + + } + + + + + if ( timeout == 1 ){ + h->top_view_last_timeouts++; + h->top_view_last_timeouts_seq = h->top_view_last_timeouts; + + sprintf(h->last_timeout_time, "%d ms ", h->top_view_last_timeouts * ( perhost_interval / 1000 / 1000 ) ); + + }else{ + + if ( h->top_view_last_timeouts > 0 ){ + h->top_view_last_timeouts_count++; + } + + h->top_view_last_timeouts = 0; + } + + line_clear( 5 + h->top_view_print_pos ); + + pos_printf( 5 + h->top_view_print_pos, HOST_POS , "%s", h->host); + + pos_printf( 5 + h->top_view_print_pos, SEND_POS , "%d", h->num_sent); + pos_printf( 5 + h->top_view_print_pos, RECV_POS , "%d", h->num_recv); + pos_printf( 5 + h->top_view_print_pos, LOST_POS , "%d", ( h->num_sent - h->num_recv )); + pos_printf( 5 + h->top_view_print_pos, TIMEOUT_TOTAL_POS , "%d", h->top_view_last_timeouts_count); + + pos_printf( 5 + h->top_view_print_pos, TIMEOUT_SEQ_POS , "%d", h->top_view_last_timeouts_seq); + pos_printf( 5 + h->top_view_print_pos, TIMEOUT_TIME_POS , "%s", h->last_timeout_time); + + + //pos_printf( 5 + h->top_view_print_pos, 2 , "%*d %*d lost: %*d %s ", , h->last_timeout_time ); + + + + +} diff --git a/src/top_view.h b/src/top_view.h new file mode 100644 index 0000000..bb79da4 --- /dev/null +++ b/src/top_view.h @@ -0,0 +1,8 @@ + +#include "data_types.h" + + +void print_top_view( HOST_ENTRY *h, int timeout ); + + +void top_view_end( void );