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)
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
#include <time.h>
#include "seqmap.h"
+#include "output.h"
+#include "stats.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
};
#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 ***/
char *filename = NULL; /* file containing hosts to ping */
-/*** forward declarations ***/
-static uint32_t ms_since_midnight_utc(int64_t time_val);
-
/************************************************************
Function: p_setsockopt
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 *)¤t_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
}
}
-/************************************************************
- 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);
-}
/************************************************************
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(¤t_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));
-}
/************************************************************
#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)
#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);
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();
--- /dev/null
+#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(¤t_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 *)¤t_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);
+ }
+ }
+}
--- /dev/null
+#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
--- /dev/null
+#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");
+}
--- /dev/null
+#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