]> git.gsnw.org Git - fping.git/commitdiff
Move printing functions and stats functions (global stats) to a separate file
authorGerman Service Network <support@gsnw.de>
Sat, 17 Jan 2026 08:53:31 +0000 (09:53 +0100)
committerSebastian <176771227+gsnw-sebast@users.noreply.github.com>
Fri, 23 Jan 2026 07:19:53 +0000 (08:19 +0100)
CHANGELOG.md
src/Makefile.am
src/fping.c
src/fping.h
src/output.c [new file with mode: 0644]
src/output.h [new file with mode: 0644]
src/stats.c [new file with mode: 0644]
src/stats.h [new file with mode: 0644]

index 6d5743ad9e51064cee77a70e4f71ccf9caa87018..0bdb3dfe18b033071f19860595d403a0c69b9d9c 100644 (file)
@@ -10,7 +10,8 @@ Next
   recvmsg with MSG_DONTWAIT instead (#449)
 - Improved compatibility with NetBSD (#452, thanks @auerswal)
 - Consistent variable names for command-line options (#453, thanks @gsnw-sebast)
-- Move the most function declarations from fping.c to fping.h (#454, thanks @gsnw-sebast)
+- Move printing functions, stats functions (global stats) and
+  function declarations to a separate file (#454, thanks @gsnw-sebast)
 - Avoid crash with option `-0` (#457, thanks @auerswal)
 
 fping 5.5 (2025-12-31)
index c58e47481f524aa12953ed641354efb7e3b78db7..7336192771f5c14a627175d80ec24cff37ea99e6 100644 (file)
@@ -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 output.c stats.c seqmap.c socket4.c fping.h options.h output.h stats.h seqmap.h optparse.c optparse.h
 fping_DEPENDENCIES = ../config.h
 
 if IPV6
index 3623ce0af6751184e9ac7e124b82dc2695a3423f..ab674a19db6f3cb2bd58d1fb46b4ff9b1ed7c98c 100644 (file)
@@ -49,6 +49,8 @@ extern "C" {
 #include <time.h>
 
 #include "seqmap.h"
+#include "output.h"
+#include "stats.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -263,80 +265,11 @@ char *icmp6_param_prob_str[ICMP6_PARAM_PROB_MAXCODE + 1] = {
 };
 #endif
 
-typedef struct ip_header_result {
-    int tos;
-    int ttl;
-    uint32_t otime_ms;
-    uint32_t rtime_ms;
-    uint32_t ttime_ms;
-} IP_HEADER_RESULT;
-
 IP_HEADER_RESULT default_ip_header_result() {
     return (IP_HEADER_RESULT){-1, -1, 0x80000000U, 0x80000000U, 0x80000000U};
 }
 
-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 */
-
-/* basic algorithm to ensure that we have correct data at all times:
- *
- * 1. when a ping is sent:
- *    - two events get added into event_queue:
- *      - t+PERIOD: ping event
- *      - t+TIMEOUT: timeout event
- *
- * 2. when a ping is received:
- *    - record statistics (increase num_sent and num_received)
- *    - remove timeout event (we store the event in seqmap, so that we can retrieve it when the response is received)
- *
- * 3. when a timeout happens:
- *    - record statistics (increase num_sent only)
- */
-
-#define EV_TYPE_PING 1
-#define EV_TYPE_TIMEOUT 2
-
-struct event {
-    struct event *ev_prev;
-    struct event *ev_next;
-    int64_t ev_time;
-    struct host_entry *host;
-    int ping_index;
-};
-
-struct event_queue {
-    struct event *first;
-    struct event *last;
-};
+int event_storage_count;
 
 /*** globals ***/
 
@@ -457,9 +390,6 @@ unsigned int fwmark = 0;
 
 char *filename = NULL; /* file containing hosts to ping */
 
-/*** forward declarations ***/
-static uint32_t ms_since_midnight_utc(int64_t time_val);
-
 /************************************************************
 
   Function: p_setsockopt
@@ -2023,605 +1953,6 @@ void finish()
     exit(0);
 }
 
-/************************************************************
-
-  Function: print_recv
-
-*************************************************************
-
-  Inputs: HOST_ENTRY *h, int64_t recv_time, int result,
-          int this_count, int64_t this_reply, int avg
-
-  Description:
-
-************************************************************/
-
-void print_recv(HOST_ENTRY *h, int64_t recv_time, int result, int this_count, int64_t this_reply, int avg) {
-    if (opt_print_json_on) {
-        printf("{\"resp\": {");
-
-        if (opt_timestamp_on)
-            print_timestamp_format(recv_time, opt_timestamp_format);
-
-        printf("\"host\": \"%s\", ", h->host);
-        printf("\"seq\": %d, ", this_count);
-        printf("\"size\": %d, ", result);
-        printf("\"rtt\": %s", sprint_tm(this_reply));
-        return;
-    }
-
-    /* Normal Output */
-    if (opt_timestamp_on)
-        print_timestamp_format(recv_time, opt_timestamp_format);
-
-    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);
-    }
-}
-
-/************************************************************
-
-  Function: print_timeout
-
-*************************************************************
-
-  Inputs: HOST_ENTRY *h, int ping_index
-
-  Description:
-
-************************************************************/
-
-void print_timeout(HOST_ENTRY *h, int ping_index) {
-    if (opt_print_json_on) {
-        printf("{\"timeout\": {");
-        if (opt_timestamp_on)
-            print_timestamp_format(current_time_ns, opt_timestamp_format);
-
-        printf("\"host\": \"%s\", ", h->host);
-        printf("\"seq\": %d", ping_index);
-        printf("}}\n");
-        return;
-    }
-
-    /* Normal Output */
-    if (opt_timestamp_on)
-        print_timestamp_format(current_time_ns, opt_timestamp_format);
-
-    printf("%-*s : [%d], timed out",
-        max_hostname_len, h->host, 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");
-}
-
-/************************************************************
-
-  Function: print_recv_ext
-
-*************************************************************
-
-  Inputs:  IP_HEADER_RESULT *ip_header_res,
-           int64_t recv_time, int64_t this_reply
-
-  Description:
-
-************************************************************/
-
-void print_recv_ext(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply) { 
-    if (opt_icmp_request_typ == 13) {
-        printf("%s timestamps: Originate=%u Receive=%u Transmit=%u Localreceive=%u",
-            opt_alive_on ? "" : ",",
-            ip_header_res->otime_ms, ip_header_res->rtime_ms, ip_header_res->ttime_ms,
-            ms_since_midnight_utc(recv_time));
-    }
-
-    if(opt_print_tos_on) {
-        if(ip_header_res->tos != -1) {
-            printf(" (TOS %d)", ip_header_res->tos);
-        }
-        else {
-            printf(" (TOS unknown)");
-        }
-    }
-
-    if (opt_print_ttl_on) {
-        if(ip_header_res->ttl != -1) {
-            printf(" (TTL %d)", ip_header_res->ttl);
-        }
-        else {
-            printf(" (TTL unknown)");
-        }
-    }
-
-    if (opt_elapsed_on && !opt_per_recv_on)
-        printf(" (%s ms)", sprint_tm(this_reply));
-    
-    printf("\n");
-}
-
-/************************************************************
-
-  Function: print_recv_ext_json
-
-*************************************************************
-
-  Inputs:  IP_HEADER_RESULT *ip_header_res,
-           int64_t recv_time, int64_t this_reply
-
-  Description:
-
-************************************************************/
-
-void print_recv_ext_json(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply) {
-    if (opt_icmp_request_typ == 13) {
-        printf(", \"timestamps\": {");
-        printf("\"originate\": %u, ", ip_header_res->otime_ms);
-        printf("\"receive\": %u, ", ip_header_res->rtime_ms);
-        printf("\"transmit\": %u, ", ip_header_res->ttime_ms);
-        printf("\"localreceive\": %u}", ms_since_midnight_utc(recv_time));
-    }
-
-    if(opt_print_tos_on) {
-        if(ip_header_res->tos != -1) {
-            printf(", \"tos\": %d", ip_header_res->tos);
-        }
-        else {
-            printf(", \"tos\": -1");
-        }
-    }
-
-    if (opt_print_ttl_on) {
-        if(ip_header_res->ttl != -1) {
-            printf(", \"ttl\": %d", ip_header_res->ttl);
-        }
-        else {
-            printf(", \"ttl\": -1");
-        }
-    }
-
-    if (opt_elapsed_on && !opt_per_recv_on)
-        printf(" (%s ms)", sprint_tm(this_reply));
-
-    printf("}}");
-    printf("\n");
-}
-
-/************************************************************
-
-  Function: print_per_system_stats
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_per_system_stats(void)
-{
-    int i, j, avg, outage_ms;
-    HOST_ENTRY *h;
-    int64_t resp;
-
-    if (opt_verbose_on || opt_per_recv_on)
-        fprintf(stderr, "\n");
-
-    for (i = 0; i < num_hosts; i++) {
-        h = table[i];
-        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
-
-        if (opt_report_all_rtts_on) {
-            for (j = 0; j < h->num_sent; j++) {
-                if ((resp = h->resp_times[j]) >= 0)
-                    fprintf(stderr, " %s", sprint_tm(resp));
-                else
-                    fprintf(stderr, " -");
-            }
-
-            fprintf(stderr, "\n");
-        }
-        else {
-            if (h->num_recv <= h->num_sent) {
-                fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
-                    h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
-
-                if (opt_outage_on) {
-                    /* Time outage total */
-                    outage_ms = (h->num_sent - h->num_recv) * opt_perhost_interval / 1e6;
-                    fprintf(stderr, ", outage(ms) = %d", outage_ms);
-                }
-            }
-            else {
-                fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
-                    h->num_sent, h->num_recv,
-                    h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
-            }
-
-            if (h->num_recv) {
-                avg = h->total_time / h->num_recv;
-                fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
-                fprintf(stderr, "/%s", sprint_tm(avg));
-                fprintf(stderr, "/%s", sprint_tm(h->max_reply));
-            }
-
-            fprintf(stderr, "\n");
-        }
-    }
-}
-
-/************************************************************
-
-  Function: print_per_system_stats_json
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_per_system_stats_json(void)
-{
-    int i, j, avg, outage_ms;
-    HOST_ENTRY *h;
-    int64_t resp;
-
-    for (i = 0; i < num_hosts; i++) {
-        h = table[i];
-
-        if (opt_report_all_rtts_on)
-            fprintf(stdout, "{\"vSum\": {");
-        else
-            fprintf(stdout, "{\"summary\": {");
-
-        fprintf(stdout, "\"host\": \"%s\", ", h->host);
-
-        if (opt_report_all_rtts_on) {
-            fprintf(stdout, "\"values\": [");
-            for (j = 0; j < h->num_sent; j++) {
-                if (j > 0)
-                  fprintf(stdout, ", ");
-                
-                if ((resp = h->resp_times[j]) >= 0)
-                    fprintf(stdout, "%s", sprint_tm(resp));
-                else
-                    fprintf(stdout, "null");
-            }
-
-            fprintf(stdout, "]}");
-        }
-        else {
-            if (h->num_recv <= h->num_sent) {
-                fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
-                fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
-                fprintf(stdout, "\"loss\": %d", h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
-
-                if (opt_outage_on) {
-                    /* Time outage total */
-                    outage_ms = (h->num_sent - h->num_recv) * opt_perhost_interval / 1e6;
-                    fprintf(stdout, ", \"outage(ms)\": %d", outage_ms);
-                }
-            }
-            else {
-                fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
-                fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
-                fprintf(stdout, "\"return\": %d", h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
-            }
-
-            if (h->num_recv) {
-                avg = h->total_time / h->num_recv;
-                fprintf(stdout, ", \"rttMin\": %s", sprint_tm(h->min_reply));
-                fprintf(stdout, ", \"rttAvg\": %s", sprint_tm(avg));
-                fprintf(stdout, ", \"rttMax\": %s", sprint_tm(h->max_reply));
-            }
-
-            fprintf(stdout, "}");
-        }
-        fprintf(stdout, "}\n");
-    }
-}
-
-/************************************************************
-
-  Function: print_netdata
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_netdata(void)
-{
-    static int sent_charts = 0;
-
-    int i;
-    int64_t avg;
-    HOST_ENTRY *h;
-
-    for (i = 0; i < num_hosts; i++) {
-        h = table[i];
-
-        if (!sent_charts) {
-            printf("CHART fping.%s_packets '' 'FPing Packets' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, report_interval / 1e9);
-            printf("DIMENSION xmt sent absolute 1 1\n");
-            printf("DIMENSION rcv received absolute 1 1\n");
-        }
-
-        printf("BEGIN fping.%s_packets\n", h->name);
-        printf("SET xmt = %d\n", h->num_sent_i);
-        printf("SET rcv = %d\n", h->num_recv_i);
-        printf("END\n");
-
-        if (!sent_charts) {
-            printf("CHART fping.%s_quality '' 'FPing Quality' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, report_interval / 1e9);
-            printf("DIMENSION returned '' absolute 1 1\n");
-            /* printf("DIMENSION lost '' absolute 1 1\n"); */
-        }
-
-        printf("BEGIN fping.%s_quality\n", h->name);
-        /*
-        if( h->num_recv_i <= h->num_sent_i )
-            printf("SET lost = %d\n", h->num_sent_i > 0 ? ( ( h->num_sent_i - h->num_recv_i ) * 100 ) / h->num_sent_i : 0 );
-        else
-            printf("SET lost = 0\n");
-*/
-
-        printf("SET returned = %d\n", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
-        printf("END\n");
-
-        if (!sent_charts) {
-            printf("CHART fping.%s_latency '' 'FPing Latency' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, report_interval / 1e9);
-            printf("DIMENSION min minimum absolute 1 1000000\n");
-            printf("DIMENSION max maximum absolute 1 1000000\n");
-            printf("DIMENSION avg average absolute 1 1000000\n");
-        }
-
-        printf("BEGIN fping.%s_latency\n", h->name);
-        if (h->num_recv_i) {
-            avg = h->total_time_i / h->num_recv_i;
-            printf("SET min = %" PRId64 "\n", h->min_reply_i);
-            printf("SET avg = %" PRId64 "\n", avg);
-            printf("SET max = %" PRId64 "\n", h->max_reply_i);
-        }
-        printf("END\n");
-
-        stats_reset_interval(h);
-    }
-
-    sent_charts = 1;
-}
-
-/************************************************************
-
-  Function: print_per_system_splits
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_per_system_splits(void)
-{
-    int i, avg, outage_ms_i;
-    HOST_ENTRY *h;
-    struct tm *curr_tm;
-
-    if (opt_verbose_on || opt_per_recv_on)
-        fprintf(stderr, "\n");
-
-    update_current_time();
-    curr_tm = localtime((time_t *)&current_time.tv_sec);
-    fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
-        curr_tm->tm_min, curr_tm->tm_sec);
-
-    for (i = 0; i < num_hosts; i++) {
-        h = table[i];
-        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
-
-        if (h->num_recv_i <= h->num_sent_i) {
-            fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
-                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
-
-            if (opt_outage_on) {
-                /* Time outage  */
-                outage_ms_i = (h->num_sent_i - h->num_recv_i) * opt_perhost_interval / 1e6;
-                fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
-            }
-        }
-        else {
-            fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
-                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
-        }
-
-        if (h->num_recv_i) {
-            avg = h->total_time_i / h->num_recv_i;
-            fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
-            fprintf(stderr, "/%s", sprint_tm(avg));
-            fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
-        }
-
-        fprintf(stderr, "\n");
-        if (!opt_cumulative_stats_on) {
-            stats_reset_interval(h);
-        }
-    }
-}
-
-/************************************************************
-
-  Function: print_per_system_splits_json
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_per_system_splits_json(void)
-{
-    int i, avg, outage_ms_i;
-    HOST_ENTRY *h;
-
-    update_current_time();
-
-    for (i = 0; i < num_hosts; i++) {
-        h = table[i];
-        fprintf(stdout, "{\"intSum\": {");
-        fprintf(stdout, "\"time\": %" PRId64 ",", current_time.tv_sec);
-        fprintf(stdout, "\"host\": \"%s\", ", h->host);
-
-        if (h->num_recv_i <= h->num_sent_i) {
-            fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
-            fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
-            fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
-
-            if (opt_outage_on) {
-                /* Time outage  */
-                outage_ms_i = (h->num_sent_i - h->num_recv_i) * opt_perhost_interval / 1e6;
-                fprintf(stdout, ", \"outage(ms)\": %d", outage_ms_i);
-            }
-        }
-        else {
-            fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
-            fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
-            fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
-        }
-
-        if (h->num_recv_i) {
-            avg = h->total_time_i / h->num_recv_i;
-            fprintf(stdout, ", \"rttMin\": %s, ", sprint_tm(h->min_reply_i));
-            fprintf(stdout, "\"rttAvg\": %s, ", sprint_tm(avg));
-            fprintf(stdout, "\"rttMax\": %s", sprint_tm(h->max_reply_i));
-        }
-
-        fprintf(stdout, "}}\n");
-        if (!opt_cumulative_stats_on) {
-            stats_reset_interval(h);
-        }
-    }
-}
-
-/************************************************************
-
-  Function: print_global_stats
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_global_stats(void)
-{
-    fprintf(stderr, "\n");
-    fprintf(stderr, " %7d targets\n", num_hosts);
-    fprintf(stderr, " %7d alive\n", num_alive);
-    fprintf(stderr, " %7d unreachable\n", num_unreachable);
-    fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
-    fprintf(stderr, "\n");
-    fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
-    fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
-    fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
-    fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
-    fprintf(stderr, "\n");
-
-    if (total_replies == 0) {
-        min_reply = 0;
-        max_reply = 0;
-        total_replies = 1;
-        sum_replies = 0;
-    }
-
-    fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
-    fprintf(stderr, " %s ms (avg round trip time)\n",
-        sprint_tm(sum_replies / total_replies));
-    fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
-    fprintf(stderr, " %12.3f sec (elapsed real time)\n",
-        (end_time - start_time) / 1e9);
-    fprintf(stderr, "\n");
-}
-
-/************************************************************
-
-  Function: print_global_stats_json
-
-*************************************************************
-
-  Inputs:  void (none)
-
-  Description:
-
-
-************************************************************/
-
-void print_global_stats_json(void)
-{
-    fprintf(stdout, "{\"stats\": {");
-    fprintf(stdout, "\"targets\": %d, ", num_hosts);
-    fprintf(stdout, "\"alive\": %d, ", num_alive);
-    fprintf(stdout, "\"unreachable\": %d, ", num_unreachable);
-    fprintf(stdout, "\"unknownAddresses\": %d, ", num_noaddress);
-    fprintf(stdout, "\"timeouts\": %d, ", num_timeout);
-    fprintf(stdout, "\"icmpEchosSent\": %d, ", num_pingsent);
-    fprintf(stdout, "\"icmpEchoRepliesReceived\": %d, ", num_pingreceived);
-    fprintf(stdout, "\"otherIcmpReceived\": %d, ", num_othericmprcvd);
-
-    if (total_replies == 0) {
-        min_reply = 0;
-        max_reply = 0;
-        total_replies = 1;
-        sum_replies = 0;
-    }
-
-    fprintf(stdout, "\"rttMin\": %s, ", sprint_tm(min_reply));
-    fprintf(stdout, "\"rttAvg\": %s, ", sprint_tm(sum_replies / total_replies));
-    fprintf(stdout, "\"rttMax\": %s, ", sprint_tm(max_reply));
-    fprintf(stdout, "\"elapsed\": %.3f", (end_time - start_time) / 1e9);
-    fprintf(stdout, "}}\n");
-}
-
 /************************************************************
 
   Function: send_ping
@@ -3601,48 +2932,7 @@ void print_warning(char *format, ...)
     }
 }
 
-/************************************************************
 
-  Function: sprint_tm
-
-*************************************************************
-
-  render nanosecond int64_t value into milliseconds string with three digits of
-  precision.
-
-************************************************************/
-
-const char *sprint_tm(int64_t ns)
-{
-    static char buf[10];
-    double t = (double)ns / 1e6;
-
-    if (t < 0.0) {
-        /* negative (unexpected) */
-        snprintf(buf, sizeof(buf), "%.2g", t);
-    }
-    else if (t < 1.0) {
-        /* <= 0.99 ms */
-        snprintf(buf, sizeof(buf), "%.3f", t);
-    }
-    else if (t < 10.0) {
-        /* 1.00 - 9.99 ms */
-        snprintf(buf, sizeof(buf), "%.2f", t);
-    }
-    else if (t < 100.0) {
-        /* 10.0 - 99.9 ms */
-        snprintf(buf, sizeof(buf), "%.1f", t);
-    }
-    else if (t < 1000000.0) {
-        /* 100 - 1'000'000 ms */
-        snprintf(buf, sizeof(buf), "%.0f", t);
-    }
-    else {
-        snprintf(buf, sizeof(buf), "%.3e", t);
-    }
-
-    return (buf);
-}
 
 /************************************************************
 
@@ -3795,72 +3085,7 @@ void ev_remove(struct event_queue *queue, struct event *event)
     event->ev_next = NULL;
 }
 
-/************************************************************
-
-  Function: print_human_readable_time from current_time_ns
-
-*************************************************************/
-void print_timestamp_format(int64_t current_time_ns, int timestamp_format)
-{
-    char time_buffer[100];
-    time_t current_time_s;
-    struct tm *local_time;
-
-    current_time_s = current_time_ns / 1000000000;
-    local_time = localtime(&current_time_s);
-    switch(timestamp_format) {
-        case 1:
-            // timestamp-format ctime
-            strftime(time_buffer, sizeof(time_buffer), "%c", local_time);
-            if (opt_print_json_on)
-                printf("\"timestamp\": \"%s\", ", time_buffer);
-            else
-                printf("[%s] ", time_buffer);
-            break;
-        case 2:
-            // timestamp-format iso
-            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%T%z", local_time);
-            if (opt_print_json_on)
-                printf("\"timestamp\": \"%s\", ", time_buffer);
-            else
-                printf("[%s] ", time_buffer);
-            break;
-        case 3:
-            // timestamp-format rfc3339
-            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
-            if (opt_print_json_on)
-                printf("\"timestamp\": \"%s\", ", time_buffer);
-            else
-                printf("[%s] ", time_buffer);
-            break;
-        default:
-            if (opt_print_json_on)
-                printf("\"timestamp\": \"%.5f\", ", (double)current_time_ns / 1e9);
-            else
-                printf("[%.5f] ", (double)current_time_ns / 1e9);
-    }
-}
-
-/************************************************************
-
-  Function: ms_since_midnight_utc
-
-*************************************************************
-
-  Input: int64_t: current UTC time in ns
-
-  Output: uint32_t: current time in ms since midnight UTC
 
-  Description:
-
-  Return ICMP Timestamp value corresponding to the given time value.
-  The given time value must be in UTC.
-
-*************************************************************/
-static uint32_t ms_since_midnight_utc(int64_t time_val)
-{
-    return (uint32_t)((time_val / 1000000) % (24 * 60 * 60 * 1000));
-}
 
 /************************************************************
 
index 419b56e89a8ebb5ad946f63eb81998bc671324e5..fad6e7e781cdec1be405d5edaa68cc770c3c1c28 100644 (file)
@@ -7,10 +7,98 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <netinet/in.h>
+#include <inttypes.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+/* Structure definitions */
+typedef struct ip_header_result {
+    int tos;
+    int ttl;
+    uint32_t otime_ms;
+    uint32_t rtime_ms;
+    uint32_t ttime_ms;
+} IP_HEADER_RESULT;
+
+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;
+
+struct event {
+    HOST_ENTRY *host; /* pointer to associated host */
+    int ping_index; /* index/sequence for this ping within the host */
+    int64_t ev_time; /* time of the event */
+    struct event *ev_next; /* next event in linked list */
+    struct event *ev_prev; /* previous event in linked list */
+};
+
+struct event_queue {
+    struct event *first;
+    struct event *last;
+};
+
+/* Global variables */
+extern HOST_ENTRY **table;
+extern int num_hosts;
+extern int max_hostname_len;
+extern int64_t current_time_ns;
+extern struct timespec current_time;
+extern int64_t start_time;
+extern int64_t end_time;
+extern int64_t opt_perhost_interval;
+extern int64_t report_interval;
+
+// Stats globals
+extern int num_alive, num_unreachable, num_noaddress, num_timeout;
+extern int num_pingsent, num_pingreceived, num_othericmprcvd;
+extern int64_t max_reply, min_reply, total_replies, sum_replies;
+
+// Options
+extern int opt_print_json_on;
+extern int opt_timestamp_on;
+extern int opt_timestamp_format;
+extern int opt_alive_on;
+extern int opt_quiet_on;
+extern int opt_per_recv_on;
+extern int opt_verbose_on;
+extern int opt_print_tos_on;
+extern int opt_print_ttl_on;
+extern int opt_elapsed_on;
+extern int opt_icmp_request_typ;
+extern int opt_report_all_rtts_on;
+extern int opt_outage_on;
+extern int opt_cumulative_stats_on;
+extern int opt_print_netdata_on;
+extern int opt_random_data_on;
+
 
 /* this requires variadic macros, part of C99 */
 #if (defined(DEBUG) || defined(_DEBUG))
-extern int64_t current_time_ns;
 extern int opt_debug_trace_on;
 #define dbg_printf(fmt, ...) do { if (opt_debug_trace_on) { fprintf(stderr, "[%10.5f] ", (double)(current_time_ns / 1000)/1000000); fprintf(stderr, fmt, __VA_ARGS__); } } while (0)
             
@@ -18,14 +106,7 @@ extern int opt_debug_trace_on;
 #define dbg_printf(fmt, ...)
 #endif
 
-
 /* fping.c */
-typedef struct host_entry HOST_ENTRY;
-struct event;
-struct event_queue;
-typedef struct ip_header_result IP_HEADER_RESULT;
-extern int opt_random_data_on;
-
 void add_name(char *name);
 void add_addr(char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len);
 char *na_cat(char *name, struct in_addr ipaddr);
@@ -33,18 +114,7 @@ char *get_host_by_address(struct in_addr in);
 int send_ping(HOST_ENTRY *h, int index);
 void usage(int);
 int wait_for_reply(int64_t);
-void print_recv(HOST_ENTRY *h, int64_t recv_time, int result, int this_count, int64_t this_reply, int avg);
-void print_timeout(HOST_ENTRY *h, int ping_index);
-void print_recv_ext(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply);
-void print_recv_ext_json(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply);
-void print_per_system_stats(void);
-void print_per_system_stats_json(void);
-void print_per_system_splits(void);
-void print_per_system_splits_json(void);
 void stats_reset_interval(HOST_ENTRY *h);
-void print_netdata(void);
-void print_global_stats(void);
-void print_global_stats_json(void);
 void main_loop();
 void signal_handler(int);
 void finish();
diff --git a/src/output.c b/src/output.c
new file mode 100644 (file)
index 0000000..c8eec90
--- /dev/null
@@ -0,0 +1,485 @@
+#include "output.h"
+#include "fping.h"
+#include <stdio.h>
+#include <time.h>
+#include <inttypes.h>
+
+/************************************************************
+
+  Function: ms_since_midnight_utc
+
+*************************************************************
+
+  Input: int64_t: current UTC time in ns
+
+  Output: uint32_t: current time in ms since midnight UTC
+
+  Description:
+
+  Return ICMP Timestamp value corresponding to the given time value.
+  The given time value must be in UTC.
+
+*************************************************************/
+static uint32_t ms_since_midnight_utc(int64_t time_val)
+{
+    return (uint32_t)((time_val / 1000000) % (24 * 60 * 60 * 1000));
+}
+
+/************************************************************
+
+  Function: sprint_tm
+
+*************************************************************
+
+  render nanosecond int64_t value into milliseconds string with three digits of
+  precision.
+
+************************************************************/
+
+const char *sprint_tm(int64_t ns)
+{
+    static char buf[10];
+    double t = (double)ns / 1e6;
+
+    if (t < 0.0) {
+        /* negative (unexpected) */
+        snprintf(buf, sizeof(buf), "%.2g", t);
+    }
+    else if (t < 1.0) {
+        /* <= 0.99 ms */
+        snprintf(buf, sizeof(buf), "%.3f", t);
+    }
+    else if (t < 10.0) {
+        /* 1.00 - 9.99 ms */
+        snprintf(buf, sizeof(buf), "%.2f", t);
+    }
+    else if (t < 100.0) {
+        /* 10.0 - 99.9 ms */
+        snprintf(buf, sizeof(buf), "%.1f", t);
+    }
+    else if (t < 1000000.0) {
+        /* 100 - 1'000'000 ms */
+        snprintf(buf, sizeof(buf), "%.0f", t);
+    }
+    else {
+        snprintf(buf, sizeof(buf), "%.3e", t);
+    }
+
+    return (buf);
+}
+
+/************************************************************
+
+  Function: print_human_readable_time from current_time_ns
+
+*************************************************************/
+void print_timestamp_format(int64_t current_time_ns, int timestamp_format)
+{
+    char time_buffer[100];
+    time_t current_time_s;
+    struct tm *local_time;
+
+    current_time_s = current_time_ns / 1000000000;
+    local_time = localtime(&current_time_s);
+    switch(timestamp_format) {
+        case 1:
+            // timestamp-format ctime
+            strftime(time_buffer, sizeof(time_buffer), "%c", local_time);
+            if (opt_print_json_on)
+                printf("\"timestamp\": \"%s\", ", time_buffer);
+            else
+                printf("[%s] ", time_buffer);
+            break;
+        case 2:
+            // timestamp-format iso
+            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%T%z", local_time);
+            if (opt_print_json_on)
+                printf("\"timestamp\": \"%s\", ", time_buffer);
+            else
+                printf("[%s] ", time_buffer);
+            break;
+        case 3:
+            // timestamp-format rfc3339
+            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
+            if (opt_print_json_on)
+                printf("\"timestamp\": \"%s\", ", time_buffer);
+            else
+                printf("[%s] ", time_buffer);
+            break;
+        default:
+            if (opt_print_json_on)
+                printf("\"timestamp\": \"%.5f\", ", (double)current_time_ns / 1e9);
+            else
+                printf("[%.5f] ", (double)current_time_ns / 1e9);
+    }
+}
+
+/************************************************************
+
+  Function: print_recv
+
+*************************************************************
+
+  Inputs: HOST_ENTRY *h, int64_t recv_time, int result,
+          int this_count, int64_t this_reply, int avg
+
+  Description:
+
+************************************************************/
+
+void print_recv(HOST_ENTRY *h, int64_t recv_time, int result, int this_count, int64_t this_reply, int avg) {
+    if (opt_print_json_on) {
+        printf("{\"resp\": {");
+
+        if (opt_timestamp_on)
+            print_timestamp_format(recv_time, opt_timestamp_format);
+
+        printf("\"host\": \"%s\", ", h->host);
+        printf("\"seq\": %d, ", this_count);
+        printf("\"size\": %d, ", result);
+        printf("\"rtt\": %s", sprint_tm(this_reply));
+        return;
+    }
+
+    /* Normal Output */
+    if (opt_timestamp_on)
+        print_timestamp_format(recv_time, opt_timestamp_format);
+
+    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);
+    }
+}
+
+/************************************************************
+
+  Function: print_timeout
+
+*************************************************************
+
+  Inputs: HOST_ENTRY *h, int ping_index
+
+  Description:
+
+************************************************************/
+
+void print_timeout(HOST_ENTRY *h, int ping_index) {
+    if (opt_print_json_on) {
+        printf("{\"timeout\": {");
+        if (opt_timestamp_on)
+            print_timestamp_format(current_time_ns, opt_timestamp_format);
+
+        printf("\"host\": \"%s\", ", h->host);
+        printf("\"seq\": %d", ping_index);
+        printf("}}\n");
+        return;
+    }
+
+    /* Normal Output */
+    if (opt_timestamp_on)
+        print_timestamp_format(current_time_ns, opt_timestamp_format);
+
+    printf("%-*s : [%d], timed out",
+        max_hostname_len, h->host, 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");
+}
+
+/************************************************************
+
+  Function: print_recv_ext
+
+*************************************************************
+
+  Inputs:  IP_HEADER_RESULT *ip_header_res,
+           int64_t recv_time, int64_t this_reply
+
+  Description:
+
+************************************************************/
+
+void print_recv_ext(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply) { 
+    if (opt_icmp_request_typ == 13) {
+        printf("%s timestamps: Originate=%u Receive=%u Transmit=%u Localreceive=%u",
+            opt_alive_on ? "" : ",",
+            ip_header_res->otime_ms, ip_header_res->rtime_ms, ip_header_res->ttime_ms,
+            ms_since_midnight_utc(recv_time));
+    }
+
+    if(opt_print_tos_on) {
+        if(ip_header_res->tos != -1) {
+            printf(" (TOS %d)", ip_header_res->tos);
+        }
+        else {
+            printf(" (TOS unknown)");
+        }
+    }
+
+    if (opt_print_ttl_on) {
+        if(ip_header_res->ttl != -1) {
+            printf(" (TTL %d)", ip_header_res->ttl);
+        }
+        else {
+            printf(" (TTL unknown)");
+        }
+    }
+
+    if (opt_elapsed_on && !opt_per_recv_on)
+        printf(" (%s ms)", sprint_tm(this_reply));
+    
+    printf("\n");
+}
+
+/************************************************************
+
+  Function: print_recv_ext_json
+
+*************************************************************
+
+  Inputs:  IP_HEADER_RESULT *ip_header_res,
+           int64_t recv_time, int64_t this_reply
+
+  Description:
+
+************************************************************/
+
+void print_recv_ext_json(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply) {
+    if (opt_icmp_request_typ == 13) {
+        printf(", \"timestamps\": {");
+        printf("\"originate\": %u, ", ip_header_res->otime_ms);
+        printf("\"receive\": %u, ", ip_header_res->rtime_ms);
+        printf("\"transmit\": %u, ", ip_header_res->ttime_ms);
+        printf("\"localreceive\": %u}", ms_since_midnight_utc(recv_time));
+    }
+
+    if(opt_print_tos_on) {
+        if(ip_header_res->tos != -1) {
+            printf(", \"tos\": %d", ip_header_res->tos);
+        }
+        else {
+            printf(", \"tos\": -1");
+        }
+    }
+
+    if (opt_print_ttl_on) {
+        if(ip_header_res->ttl != -1) {
+            printf(", \"ttl\": %d", ip_header_res->ttl);
+        }
+        else {
+            printf(", \"ttl\": -1");
+        }
+    }
+
+    if (opt_elapsed_on && !opt_per_recv_on)
+        printf(" (%s ms)", sprint_tm(this_reply));
+
+    printf("}}");
+    printf("\n");
+}
+
+/************************************************************
+
+  Function: print_netdata
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_netdata(void)
+{
+    static int sent_charts = 0;
+
+    int i;
+    int64_t avg;
+    HOST_ENTRY *h;
+
+    for (i = 0; i < num_hosts; i++) {
+        h = table[i];
+
+        if (!sent_charts) {
+            printf("CHART fping.%s_packets '' 'FPing Packets' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, report_interval / 1e9);
+            printf("DIMENSION xmt sent absolute 1 1\n");
+            printf("DIMENSION rcv received absolute 1 1\n");
+        }
+
+        printf("BEGIN fping.%s_packets\n", h->name);
+        printf("SET xmt = %d\n", h->num_sent_i);
+        printf("SET rcv = %d\n", h->num_recv_i);
+        printf("END\n");
+
+        if (!sent_charts) {
+            printf("CHART fping.%s_quality '' 'FPing Quality' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, report_interval / 1e9);
+            printf("DIMENSION returned '' absolute 1 1\n");
+        }
+
+        printf("BEGIN fping.%s_quality\n", h->name);
+        printf("SET returned = %d\n", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
+        printf("END\n");
+
+        if (!sent_charts) {
+            printf("CHART fping.%s_latency '' 'FPing Latency' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, report_interval / 1e9);
+            printf("DIMENSION min minimum absolute 1 1000000\n");
+            printf("DIMENSION max maximum absolute 1 1000000\n");
+            printf("DIMENSION avg average absolute 1 1000000\n");
+        }
+
+        printf("BEGIN fping.%s_latency\n", h->name);
+        if (h->num_recv_i) {
+            avg = h->total_time_i / h->num_recv_i;
+            printf("SET min = %" PRId64 "\n", h->min_reply_i);
+            printf("SET avg = %" PRId64 "\n", avg);
+            printf("SET max = %" PRId64 "\n", h->max_reply_i);
+        }
+        printf("END\n");
+
+        stats_reset_interval(h);
+    }
+
+    sent_charts = 1;
+}
+
+/************************************************************
+
+  Function: print_per_system_splits
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_per_system_splits(void)
+{
+    int i, avg, outage_ms_i;
+    HOST_ENTRY *h;
+    struct tm *curr_tm;
+
+    if (opt_verbose_on || opt_per_recv_on)
+        fprintf(stderr, "\n");
+
+    update_current_time();
+    curr_tm = localtime((time_t *)&current_time.tv_sec);
+    fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
+        curr_tm->tm_min, curr_tm->tm_sec);
+
+    for (i = 0; i < num_hosts; i++) {
+        h = table[i];
+        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
+
+        if (h->num_recv_i <= h->num_sent_i) {
+            fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
+                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
+
+            if (opt_outage_on) {
+                /* Time outage  */
+                outage_ms_i = (h->num_sent_i - h->num_recv_i) * opt_perhost_interval / 1e6;
+                fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
+            }
+        }
+        else {
+            fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
+                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
+        }
+
+        if (h->num_recv_i) {
+            avg = h->total_time_i / h->num_recv_i;
+            fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
+            fprintf(stderr, "/%s", sprint_tm(avg));
+            fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
+        }
+
+        fprintf(stderr, "\n");
+        if (!opt_cumulative_stats_on) {
+            stats_reset_interval(h);
+        }
+    }
+}
+
+/************************************************************
+
+  Function: print_per_system_splits_json
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_per_system_splits_json(void)
+{
+    int i, avg, outage_ms_i;
+    HOST_ENTRY *h;
+
+    update_current_time();
+
+    for (i = 0; i < num_hosts; i++) {
+        h = table[i];
+        fprintf(stdout, "{\"intSum\": {");
+        fprintf(stdout, "\"time\": %" PRId64 ",", current_time.tv_sec);
+        fprintf(stdout, "\"host\": \"%s\", ", h->host);
+
+        if (h->num_recv_i <= h->num_sent_i) {
+            fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
+            fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
+            fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
+
+            if (opt_outage_on) {
+                /* Time outage  */
+                outage_ms_i = (h->num_sent_i - h->num_recv_i) * opt_perhost_interval / 1e6;
+                fprintf(stdout, ", \"outage(ms)\": %d", outage_ms_i);
+            }
+        }
+        else {
+            fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
+            fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
+            fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
+        }
+
+        if (h->num_recv_i) {
+            avg = h->total_time_i / h->num_recv_i;
+            fprintf(stdout, ", \"rttMin\": %s, ", sprint_tm(h->min_reply_i));
+            fprintf(stdout, "\"rttAvg\": %s, ", sprint_tm(avg));
+            fprintf(stdout, "\"rttMax\": %s", sprint_tm(h->max_reply_i));
+        }
+
+        fprintf(stdout, "}}\n");
+        if (!opt_cumulative_stats_on) {
+            stats_reset_interval(h);
+        }
+    }
+}
diff --git a/src/output.h b/src/output.h
new file mode 100644 (file)
index 0000000..c5d4043
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _OUTPUT_H
+#define _OUTPUT_H
+
+#include "fping.h"
+
+void print_recv(HOST_ENTRY *h, int64_t recv_time, int result, int this_count, int64_t this_reply, int avg);
+void print_timeout(HOST_ENTRY *h, int ping_index);
+void print_recv_ext(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply);
+void print_recv_ext_json(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t this_reply);
+void print_netdata(void);
+void print_per_system_splits(void);
+void print_per_system_splits_json(void);
+
+const char *sprint_tm(int64_t ns);
+void print_timestamp_format(int64_t current_time_ns, int timestamp_format);
+#endif
diff --git a/src/stats.c b/src/stats.c
new file mode 100644 (file)
index 0000000..fd9bae0
--- /dev/null
@@ -0,0 +1,226 @@
+#include "stats.h"
+#include "output.h"
+#include "fping.h"
+#include <stdio.h>
+#include <inttypes.h>
+
+/************************************************************
+
+  Function: print_per_system_stats
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_per_system_stats(void)
+{
+    int i, j, avg, outage_ms;
+    HOST_ENTRY *h;
+    int64_t resp;
+
+    if (opt_verbose_on || opt_per_recv_on)
+        fprintf(stderr, "\n");
+
+    for (i = 0; i < num_hosts; i++) {
+        h = table[i];
+        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
+
+        if (opt_report_all_rtts_on) {
+            for (j = 0; j < h->num_sent; j++) {
+                if ((resp = h->resp_times[j]) >= 0)
+                    fprintf(stderr, " %s", sprint_tm(resp));
+                else
+                    fprintf(stderr, " -");
+            }
+
+            fprintf(stderr, "\n");
+        }
+        else {
+            if (h->num_recv <= h->num_sent) {
+                fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
+                    h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
+
+                if (opt_outage_on) {
+                    /* Time outage total */
+                    outage_ms = (h->num_sent - h->num_recv) * opt_perhost_interval / 1e6;
+                    fprintf(stderr, ", outage(ms) = %d", outage_ms);
+                }
+            }
+            else {
+                fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
+                    h->num_sent, h->num_recv,
+                    h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
+            }
+
+            if (h->num_recv) {
+                avg = h->total_time / h->num_recv;
+                fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
+                fprintf(stderr, "/%s", sprint_tm(avg));
+                fprintf(stderr, "/%s", sprint_tm(h->max_reply));
+            }
+
+            fprintf(stderr, "\n");
+        }
+    }
+}
+
+/************************************************************
+
+  Function: print_per_system_stats_json
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_per_system_stats_json(void)
+{
+    int i, j, avg, outage_ms;
+    HOST_ENTRY *h;
+    int64_t resp;
+
+    for (i = 0; i < num_hosts; i++) {
+        h = table[i];
+
+        if (opt_report_all_rtts_on)
+            fprintf(stdout, "{\"vSum\": {");
+        else
+            fprintf(stdout, "{\"summary\": {");
+
+        fprintf(stdout, "\"host\": \"%s\", ", h->host);
+
+        if (opt_report_all_rtts_on) {
+            fprintf(stdout, "\"values\": [");
+            for (j = 0; j < h->num_sent; j++) {
+                if (j > 0)
+                  fprintf(stdout, ", ");
+                
+                if ((resp = h->resp_times[j]) >= 0)
+                    fprintf(stdout, "%s", sprint_tm(resp));
+                else
+                    fprintf(stdout, "null");
+            }
+
+            fprintf(stdout, "]}");
+        }
+        else {
+            if (h->num_recv <= h->num_sent) {
+                fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
+                fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
+                fprintf(stdout, "\"loss\": %d", h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
+
+                if (opt_outage_on) {
+                    /* Time outage total */
+                    outage_ms = (h->num_sent - h->num_recv) * opt_perhost_interval / 1e6;
+                    fprintf(stdout, ", \"outage(ms)\": %d", outage_ms);
+                }
+            }
+            else {
+                fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
+                fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
+                fprintf(stdout, "\"return\": %d", h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
+            }
+
+            if (h->num_recv) {
+                avg = h->total_time / h->num_recv;
+                fprintf(stdout, ", \"rttMin\": %s", sprint_tm(h->min_reply));
+                fprintf(stdout, ", \"rttAvg\": %s", sprint_tm(avg));
+                fprintf(stdout, ", \"rttMax\": %s", sprint_tm(h->max_reply));
+            }
+
+            fprintf(stdout, "}");
+        }
+        fprintf(stdout, "}\n");
+    }
+}
+
+/************************************************************
+
+  Function: print_global_stats
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_global_stats(void)
+{
+    fprintf(stderr, "\n");
+    fprintf(stderr, " %7d targets\n", num_hosts);
+    fprintf(stderr, " %7d alive\n", num_alive);
+    fprintf(stderr, " %7d unreachable\n", num_unreachable);
+    fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
+    fprintf(stderr, "\n");
+    fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
+    fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
+    fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
+    fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
+    fprintf(stderr, "\n");
+
+    if (total_replies == 0) {
+        min_reply = 0;
+        max_reply = 0;
+        total_replies = 1;
+        sum_replies = 0;
+    }
+
+    fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
+    fprintf(stderr, " %s ms (avg round trip time)\n",
+        sprint_tm(sum_replies / total_replies));
+    fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
+    fprintf(stderr, " %12.3f sec (elapsed real time)\n",
+        (end_time - start_time) / 1e9);
+    fprintf(stderr, "\n");
+}
+
+/************************************************************
+
+  Function: print_global_stats_json
+
+*************************************************************
+
+  Inputs:  void (none)
+
+  Description:
+
+
+************************************************************/
+
+void print_global_stats_json(void)
+{
+    fprintf(stdout, "{\"stats\": {");
+    fprintf(stdout, "\"targets\": %d, ", num_hosts);
+    fprintf(stdout, "\"alive\": %d, ", num_alive);
+    fprintf(stdout, "\"unreachable\": %d, ", num_unreachable);
+    fprintf(stdout, "\"unknownAddresses\": %d, ", num_noaddress);
+    fprintf(stdout, "\"timeouts\": %d, ", num_timeout);
+    fprintf(stdout, "\"icmpEchosSent\": %d, ", num_pingsent);
+    fprintf(stdout, "\"icmpEchoRepliesReceived\": %d, ", num_pingreceived);
+    fprintf(stdout, "\"otherIcmpReceived\": %d, ", num_othericmprcvd);
+
+    if (total_replies == 0) {
+        min_reply = 0;
+        max_reply = 0;
+        total_replies = 1;
+        sum_replies = 0;
+    }
+
+    fprintf(stdout, "\"rttMin\": %s, ", sprint_tm(min_reply));
+    fprintf(stdout, "\"rttAvg\": %s, ", sprint_tm(sum_replies / total_replies));
+    fprintf(stdout, "\"rttMax\": %s, ", sprint_tm(max_reply));
+    fprintf(stdout, "\"elapsed\": %.3f", (end_time - start_time) / 1e9);
+    fprintf(stdout, "}}\n");
+}
diff --git a/src/stats.h b/src/stats.h
new file mode 100644 (file)
index 0000000..de59940
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _STATS_H
+#define _STATS_H
+
+#include "fping.h"
+
+void print_per_system_stats(void);
+void print_per_system_stats_json(void);
+void print_global_stats(void);
+void print_global_stats_json(void);
+#endif