"Fossies" - the Fresh Open Source Software Archive

Member "fping-5.1/src/fping.c" (6 Feb 2022, 88372 Bytes) of package /linux/misc/fping-5.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * fping: fast-ping, file-ping, favorite-ping, funky-ping
    3  *
    4  *   Ping a list of target hosts in a round robin fashion.
    5  *   A better ping overall.
    6  *
    7  * fping website:  http://www.fping.org
    8  *
    9  * Current maintainer of fping: David Schweikert
   10  * Please send suggestions and patches to: david@schweikert.ch
   11  *
   12  *
   13  * Original author:  Roland Schemers  <schemers@stanford.edu>
   14  * IPv6 Support:     Jeroen Massar    <jeroen@unfix.org / jeroen@ipng.nl>
   15  * Improved main loop: David Schweikert <david@schweikert.ch>
   16  * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
   17  * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
   18  *
   19  *
   20  * Redistribution and use in source and binary forms are permitted
   21  * provided that the above copyright notice and this paragraph are
   22  * duplicated in all such forms and that any documentation,
   23  * advertising materials, and other materials related to such
   24  * distribution and use acknowledge that the software was developed
   25  * by Stanford University.  The name of the University may not be used
   26  * to endorse or promote products derived from this software without
   27  * specific prior written permission.
   28  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   30  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   31  */
   32 
   33 #ifdef __cplusplus
   34 extern "C" {
   35 #endif /* __cplusplus */
   36 
   37 #include "config.h"
   38 #include "fping.h"
   39 #include "options.h"
   40 #include "optparse.h"
   41 
   42 #include <inttypes.h>
   43 #include <errno.h>
   44 #include <signal.h>
   45 #include <stdarg.h>
   46 #include <stdio.h>
   47 #include <stdint.h>
   48 #include <time.h>
   49 
   50 #include "seqmap.h"
   51 
   52 #ifdef HAVE_UNISTD_H
   53 #include <unistd.h>
   54 #endif /* HAVE_UNISTD_H */
   55 
   56 #ifdef HAVE_STDLIB_H
   57 #include <stdlib.h>
   58 #endif /* HAVE_STDLIB_H */
   59 
   60 #include <stddef.h>
   61 #include <string.h>
   62 
   63 #include <sys/socket.h>
   64 #include <sys/time.h>
   65 #include <sys/types.h>
   66 
   67 #if HAVE_SYS_FILE_H
   68 #include <sys/file.h>
   69 #endif /* HAVE_SYS_FILE_H */
   70 
   71 #ifdef IPV6
   72 #include <netinet/icmp6.h>
   73 #endif
   74 #include <netinet/in_systm.h>
   75 
   76 #include <netinet/ip.h>
   77 #include <netinet/ip_icmp.h>
   78 
   79 #include <arpa/inet.h>
   80 #include <ctype.h>
   81 #include <netdb.h>
   82 
   83 #include <sys/select.h>
   84 
   85 /*** compatibility ***/
   86 
   87 /* Mac OS X's getaddrinfo() does not fail if we use an invalid combination,
   88  * e.g. AF_INET6 with "127.0.0.1". If we pass AI_UNUSABLE to flags, it behaves
   89  * like other platforms. But AI_UNUSABLE isn't available on other platforms,
   90  * and we can safely use 0 for flags instead.
   91  */
   92 #ifndef AI_UNUSABLE
   93 #define AI_UNUSABLE 0
   94 #endif
   95 
   96 /* MSG_TRUNC available on Linux kernel 2.2+, makes recvmsg return the full
   97  * length of the raw packet received, even if the buffer is smaller */
   98 #ifndef MSG_TRUNC
   99 #define MSG_TRUNC 0
  100 #define RECV_BUFSIZE 4096
  101 #else
  102 #define RECV_BUFSIZE 128
  103 #endif
  104 
  105 /*** externals ***/
  106 
  107 extern char* optarg;
  108 extern int optind, opterr;
  109 #ifndef h_errno
  110 extern int h_errno;
  111 #endif
  112 
  113 #ifdef __cplusplus
  114 }
  115 #endif /* __cplusplus */
  116 
  117 /*** Constants ***/
  118 
  119 #if HAVE_SO_TIMESTAMPNS
  120 #define CLOCKID CLOCK_REALTIME
  121 #endif
  122 
  123 /* CLOCK_MONTONIC starts under macOS, OpenBSD and FreeBSD with undefined positive point and can not be use
  124  * see github PR #217
  125  */
  126 #if !defined(CLOCKID)
  127 #if defined(CLOCK_MONOTONIC) && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
  128 #define CLOCKID CLOCK_MONOTONIC
  129 #else
  130 #define CLOCKID CLOCK_REALTIME
  131 #endif
  132 #endif
  133 
  134 /*** Ping packet defines ***/
  135 
  136 #define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */
  137 #define SIZE_IP_HDR 40
  138 #define SIZE_ICMP_HDR 8 /* from ip_icmp.h */
  139 #define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR)
  140 
  141 #define MAX_GENERATE 100000 /* maximum number of hosts that -g can generate */
  142 
  143 /* sized so as to be like traditional ping */
  144 #define DEFAULT_PING_DATA_SIZE 56
  145 
  146 /* maxima and minima */
  147 #ifdef FPING_SAFE_LIMITS
  148 #define MIN_INTERVAL 1 /* in millisec */
  149 #define MIN_PERHOST_INTERVAL 10 /* in millisec */
  150 #else
  151 #define MIN_INTERVAL 0
  152 #define MIN_PERHOST_INTERVAL 0
  153 #endif
  154 
  155 /* response time array flags */
  156 #define RESP_WAITING -1
  157 #define RESP_UNUSED -2
  158 #define RESP_ERROR -3
  159 #define RESP_TIMEOUT -4
  160 
  161 /* debugging flags */
  162 #if defined(DEBUG) || defined(_DEBUG)
  163 #define DBG_TRACE 1
  164 #define DBG_SENT_TIMES 2
  165 #define DBG_RANDOM_LOSE_FEW 4
  166 #define DBG_RANDOM_LOSE_MANY 8
  167 #define DBG_PRINT_PER_SYSTEM 16
  168 #define DBG_REPORT_ALL_RTTS 32
  169 #endif /* DEBUG || _DEBUG */
  170 
  171 /* Long names for ICMP packet types */
  172 #define ICMP_TYPE_STR_MAX 18
  173 char* icmp_type_str[19] = {
  174     "ICMP Echo Reply", /* 0 */
  175     "",
  176     "",
  177     "ICMP Unreachable", /* 3 */
  178     "ICMP Source Quench", /* 4 */
  179     "ICMP Redirect", /* 5 */
  180     "",
  181     "",
  182     "ICMP Echo", /* 8 */
  183     "",
  184     "",
  185     "ICMP Time Exceeded", /* 11 */
  186     "ICMP Parameter Problem", /* 12 */
  187     "ICMP Timestamp Request", /* 13 */
  188     "ICMP Timestamp Reply", /* 14 */
  189     "ICMP Information Request", /* 15 */
  190     "ICMP Information Reply", /* 16 */
  191     "ICMP Mask Request", /* 17 */
  192     "ICMP Mask Reply" /* 18 */
  193 };
  194 
  195 char* icmp_unreach_str[16] = {
  196     "ICMP Network Unreachable", /* 0 */
  197     "ICMP Host Unreachable", /* 1 */
  198     "ICMP Protocol Unreachable", /* 2 */
  199     "ICMP Port Unreachable", /* 3 */
  200     "ICMP Unreachable (Fragmentation Needed)", /* 4 */
  201     "ICMP Unreachable (Source Route Failed)", /* 5 */
  202     "ICMP Unreachable (Destination Network Unknown)", /* 6 */
  203     "ICMP Unreachable (Destination Host Unknown)", /* 7 */
  204     "ICMP Unreachable (Source Host Isolated)", /* 8 */
  205     "ICMP Unreachable (Communication with Network Prohibited)", /* 9 */
  206     "ICMP Unreachable (Communication with Host Prohibited)", /* 10 */
  207     "ICMP Unreachable (Network Unreachable For Type Of Service)", /* 11 */
  208     "ICMP Unreachable (Host Unreachable For Type Of Service)", /* 12 */
  209     "ICMP Unreachable (Communication Administratively Prohibited)", /* 13 */
  210     "ICMP Unreachable (Host Precedence Violation)", /* 14 */
  211     "ICMP Unreachable (Precedence cutoff in effect)" /* 15 */
  212 };
  213 
  214 #define ICMP_UNREACH_MAXTYPE 15
  215 
  216 struct event;
  217 typedef struct host_entry {
  218     int i; /* index into array */
  219     char* name; /* name as given by user */
  220     char* host; /* text description of host */
  221     struct sockaddr_storage saddr; /* internet address */
  222     socklen_t saddr_len;
  223     int64_t timeout; /* time to wait for response */
  224     int64_t last_send_time; /* time of last packet sent */
  225     int num_sent; /* number of ping packets sent (for statistics) */
  226     int num_recv; /* number of pings received (duplicates ignored) */
  227     int num_recv_total; /* number of pings received, including duplicates */
  228     int64_t max_reply; /* longest response time */
  229     int64_t min_reply; /* shortest response time */
  230     int64_t total_time; /* sum of response times */
  231     /* _i -> splits (reset on every report interval) */
  232     int num_sent_i; /* number of ping packets sent */
  233     int num_recv_i; /* number of pings received */
  234     int64_t max_reply_i; /* longest response time */
  235     int64_t min_reply_i; /* shortest response time */
  236     int64_t total_time_i; /* sum of response times */
  237     int64_t* resp_times; /* individual response times */
  238 
  239     /* to avoid allocating two struct events each time that we send a ping, we
  240      * preallocate here two struct events for each ping that we might send for
  241      * this host. */
  242     struct event *event_storage_ping;
  243     struct event *event_storage_timeout;
  244 } HOST_ENTRY;
  245 
  246 int event_storage_count; /* how many events can be stored in host_entry->event_storage_xxx */
  247 
  248 /* basic algorithm to ensure that we have correct data at all times:
  249  *
  250  * 1. when a ping is sent:
  251  *    - two events get added into event_queue:
  252  *      - t+PERIOD: ping event
  253  *      - t+TIMEOUT: timeout event
  254  *
  255  * 2. when a ping is received:
  256  *    - record statistics (increase num_sent and num_received)
  257  *    - remove timeout event (we store the event in seqmap, so that we can retrieve it when the response is received)
  258  *
  259  * 3. when a timeout happens:
  260  *    - record statistics (increase num_sent only)
  261  */
  262 
  263 #define EV_TYPE_PING 1
  264 #define EV_TYPE_TIMEOUT 2
  265 
  266 struct event {
  267     struct event *ev_prev;
  268     struct event *ev_next;
  269     int64_t ev_time;
  270     struct host_entry *host;
  271     int ping_index;
  272 };
  273 
  274 struct event_queue {
  275     struct event *first;
  276     struct event *last;
  277 };
  278 
  279 /*** globals ***/
  280 
  281 HOST_ENTRY** table = NULL; /* array of pointers to items in the list */
  282 
  283 /* we keep two separate queues: a ping queue, for when the next ping should be
  284  * sent, and a timeout queue. the reason for having two separate queues is that
  285  * the ping period and the timeout value are different, so if we put them in
  286  * the same event queue, we would need to scan many more entries when inserting
  287  * into the sorted list.
  288  */
  289 struct event_queue event_queue_ping;
  290 struct event_queue event_queue_timeout;
  291 
  292 char* prog;
  293 int ident4 = 0; /* our icmp identity field */
  294 int ident6 = 0;
  295 int socket4 = -1;
  296 int socktype4 = -1;
  297 int using_sock_dgram4 = 0;
  298 #ifndef IPV6
  299 int hints_ai_family = AF_INET;
  300 #else
  301 int socket6 = -1;
  302 int socktype6 = -1;
  303 int hints_ai_family = AF_UNSPEC;
  304 #endif
  305 
  306 volatile sig_atomic_t status_snapshot = 0;
  307 volatile sig_atomic_t finish_requested = 0;
  308 
  309 unsigned int debugging = 0;
  310 
  311 /* all time-related values are int64_t nanoseconds */
  312 unsigned int retry = DEFAULT_RETRY;
  313 int64_t timeout = (int64_t) DEFAULT_TIMEOUT * 1000000;
  314 int64_t interval = (int64_t) DEFAULT_INTERVAL * 1000000;
  315 int64_t perhost_interval = (int64_t) DEFAULT_PERHOST_INTERVAL * 1000000;
  316 float backoff = DEFAULT_BACKOFF_FACTOR;
  317 unsigned int ping_data_size = DEFAULT_PING_DATA_SIZE;
  318 unsigned int count = 1, min_reachable = 0;
  319 unsigned int trials;
  320 int64_t report_interval = 0;
  321 unsigned int ttl = 0;
  322 int src_addr_set = 0;
  323 struct in_addr src_addr;
  324 #ifdef IPV6
  325 int src_addr6_set = 0;
  326 struct in6_addr src_addr6;
  327 #endif
  328 
  329 /* global stats */
  330 int64_t max_reply = 0;
  331 int64_t min_reply = 0;
  332 int64_t total_replies = 0;
  333 int64_t sum_replies = 0;
  334 int max_hostname_len = 0;
  335 int num_hosts = 0; /* total number of hosts */
  336 int num_alive = 0, /* total number alive */
  337     num_unreachable = 0, /* total number unreachable */
  338     num_noaddress = 0; /* total number of addresses not found */
  339 int num_timeout = 0, /* number of times select timed out */
  340     num_pingsent = 0, /* total pings sent */
  341     num_pingreceived = 0, /* total pings received */
  342     num_othericmprcvd = 0; /* total non-echo-reply ICMP received */
  343 
  344 struct timespec current_time; /* current time (pseudo) */
  345 int64_t current_time_ns;
  346 int64_t start_time;
  347 int64_t end_time;
  348 int64_t last_send_time; /* time last ping was sent */
  349 int64_t next_report_time; /* time next -Q report is expected */
  350 
  351 /* switches */
  352 int generate_flag = 0; /* flag for IP list generation */
  353 int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
  354 int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag;
  355 int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag, rdns_flag;
  356 int multif_flag, timeout_flag;
  357 int outage_flag = 0;
  358 int timestamp_flag = 0;
  359 int random_data_flag = 0;
  360 #if defined(DEBUG) || defined(_DEBUG)
  361 int randomly_lose_flag, trace_flag, print_per_system_flag;
  362 int lose_factor;
  363 #endif /* DEBUG || _DEBUG */
  364 
  365 char* filename = NULL; /* file containing hosts to ping */
  366 
  367 /*** forward declarations ***/
  368 
  369 void add_name(char* name);
  370 void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len);
  371 char* na_cat(char* name, struct in_addr ipaddr);
  372 void crash_and_burn(char* message);
  373 void errno_crash_and_burn(char* message);
  374 char* get_host_by_address(struct in_addr in);
  375 int send_ping(HOST_ENTRY* h, int index);
  376 void usage(int);
  377 int wait_for_reply(int64_t);
  378 void print_per_system_stats(void);
  379 void print_per_system_splits(void);
  380 void print_netdata(void);
  381 void print_global_stats(void);
  382 void main_loop();
  383 void signal_handler(int);
  384 void finish();
  385 const char* sprint_tm(int64_t t);
  386 void ev_enqueue(struct event_queue *queue, struct event *event);
  387 struct event *ev_dequeue(struct event_queue *queue);
  388 void ev_remove(struct event_queue *queue, struct event *event);
  389 void add_cidr(char*);
  390 void add_range(char*, char*);
  391 void print_warning(char* fmt, ...);
  392 int addr_cmp(struct sockaddr* a, struct sockaddr* b);
  393 void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time);
  394 void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time);
  395 struct event *host_get_timeout_event(HOST_ENTRY *h, int index);
  396 void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency);
  397 void update_current_time();
  398 
  399 /************************************************************
  400 
  401   Function: p_setsockopt
  402 
  403 *************************************************************
  404 
  405   Inputs:  p_uid: privileged uid. Others as per setsockopt(2)
  406 
  407   Description:
  408 
  409   Elevates privileges to p_uid when required, calls
  410   setsockopt, and drops privileges back.
  411 
  412 ************************************************************/
  413 
  414 int p_setsockopt(uid_t p_uid, int sockfd, int level, int optname,
  415     const void *optval, socklen_t optlen)
  416 {
  417     const uid_t saved_uid = geteuid();
  418     int res;
  419 
  420     if (p_uid != saved_uid && seteuid(p_uid)) {
  421     perror("cannot elevate privileges for setsockopt");
  422     }
  423 
  424     res = setsockopt(sockfd, level, optname, optval, optlen);
  425 
  426     if (p_uid != saved_uid && seteuid(saved_uid)) {
  427     perror("fatal error: could not drop privileges after setsockopt");
  428     /* continuing would be a security hole */
  429     exit(4);
  430     }
  431 
  432     return res;
  433 }
  434 
  435 /************************************************************
  436 
  437   Function: main
  438 
  439 *************************************************************
  440 
  441   Inputs:  int argc, char** argv
  442 
  443   Description:
  444 
  445   Main program entry point
  446 
  447 ************************************************************/
  448 
  449 int main(int argc, char** argv)
  450 {
  451     int c;
  452     const uid_t suid = geteuid();
  453     int tos = 0;
  454     struct optparse optparse_state;
  455 #ifdef USE_SIGACTION
  456     struct sigaction act;
  457 #endif
  458 
  459     /* pre-parse -h/--help, so that we also can output help information
  460      * without trying to open the socket, which might fail */
  461     prog = argv[0];
  462     if(argc == 2 && ( strcmp(argv[1],"-h")==0 || strcmp(argv[1],"--help")==0 )) {
  463         usage(0);
  464     }
  465 
  466     socket4 = open_ping_socket_ipv4(&socktype4);
  467 #ifdef __linux__
  468     /* We only treat SOCK_DGRAM differently on Linux, where the IPv4 header
  469      * structure is missing in the message.
  470      */
  471     using_sock_dgram4 = (socktype4 == SOCK_DGRAM);
  472 #endif
  473 
  474 #ifdef IPV6
  475     socket6 = open_ping_socket_ipv6(&socktype6);
  476     /* if called (sym-linked) via 'fping6', imply '-6'
  477      * for backward compatibility */
  478     if (strstr(prog, "fping6")) {
  479         hints_ai_family = AF_INET6;
  480     }
  481 #endif
  482 
  483     memset(&src_addr, 0, sizeof(src_addr));
  484 #ifdef IPV6
  485     memset(&src_addr6, 0, sizeof(src_addr6));
  486 #endif
  487 
  488     if (!suid && suid != getuid()) {
  489         /* *temporarily* drop privileges */
  490         if (seteuid(getuid()) == -1)
  491             perror("cannot setuid");
  492     }
  493 
  494     optparse_init(&optparse_state, argv);
  495     ident4 = ident6 = htons(getpid() & 0xFFFF);
  496     verbose_flag = 1;
  497     backoff_flag = 1;
  498     opterr = 1;
  499 
  500     /* get command line options */
  501 
  502     struct optparse_long longopts[] = {
  503         { "ipv4", '4', OPTPARSE_NONE },
  504         { "ipv6", '6', OPTPARSE_NONE },
  505         { "alive", 'a', OPTPARSE_NONE },
  506         { "addr", 'A', OPTPARSE_NONE },
  507         { "size", 'b', OPTPARSE_REQUIRED },
  508         { "backoff", 'B', OPTPARSE_REQUIRED },
  509         { "count", 'c', OPTPARSE_REQUIRED },
  510         { "vcount", 'C', OPTPARSE_REQUIRED },
  511         { "rdns", 'd', OPTPARSE_NONE },
  512         { "timestamp", 'D', OPTPARSE_NONE },
  513         { "elapsed", 'e', OPTPARSE_NONE },
  514         { "file", 'f', OPTPARSE_REQUIRED },
  515         { "generate", 'g', OPTPARSE_NONE },
  516         { "help", 'h', OPTPARSE_NONE },
  517         { "ttl", 'H', OPTPARSE_REQUIRED },
  518         { "interval", 'i', OPTPARSE_REQUIRED },
  519         { "iface", 'I', OPTPARSE_REQUIRED },
  520         { "loop", 'l', OPTPARSE_NONE },
  521         { "all", 'm', OPTPARSE_NONE },
  522         { "dontfrag", 'M', OPTPARSE_NONE },
  523         { "name", 'n', OPTPARSE_NONE },
  524         { "netdata", 'N', OPTPARSE_NONE },
  525         { "outage", 'o', OPTPARSE_NONE },
  526         { "tos", 'O', OPTPARSE_REQUIRED },
  527         { "period", 'p', OPTPARSE_REQUIRED },
  528         { "quiet", 'q', OPTPARSE_NONE },
  529         { "squiet", 'Q', OPTPARSE_REQUIRED },
  530         { "retry", 'r', OPTPARSE_REQUIRED },
  531         { "random", 'R', OPTPARSE_NONE },
  532         { "stats", 's', OPTPARSE_NONE },
  533         { "src", 'S', OPTPARSE_REQUIRED },
  534         { "timeout", 't', OPTPARSE_REQUIRED },
  535         { NULL, 'T', OPTPARSE_REQUIRED },
  536         { "unreach", 'u', OPTPARSE_NONE },
  537         { "version", 'v', OPTPARSE_NONE },
  538         { "reachable", 'x', OPTPARSE_REQUIRED },
  539 #if defined(DEBUG) || defined(_DEBUG)
  540         { NULL, 'z', OPTPARSE_REQUIRED },
  541 #endif
  542         { 0, 0, 0 }
  543     };
  544 
  545     float opt_value_float;
  546     while ((c = optparse_long(&optparse_state, longopts, NULL)) != EOF) {
  547         switch (c) {
  548         case '4':
  549 #ifdef IPV6
  550             if (hints_ai_family != AF_UNSPEC && hints_ai_family != AF_INET) {
  551                 fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
  552                 exit(1);
  553             }
  554             hints_ai_family = AF_INET;
  555 #endif
  556             break;
  557         case '6':
  558 #ifdef IPV6
  559             if (hints_ai_family != AF_UNSPEC && hints_ai_family != AF_INET6) {
  560                 fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
  561                 exit(1);
  562             }
  563             hints_ai_family = AF_INET6;
  564 #else
  565             fprintf(stderr, "%s: IPv6 not supported by this binary\n", prog);
  566             exit(1);
  567 #endif
  568             break;
  569         case 'M':
  570 #ifdef IP_MTU_DISCOVER
  571             if (socket4 >= 0) {
  572                 int val = IP_PMTUDISC_DO;
  573                 if (setsockopt(socket4, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))) {
  574                     perror("setsockopt IP_MTU_DISCOVER");
  575                 }
  576             }
  577 #ifdef IPV6
  578             if (socket6 >= 0) {
  579                 int val = IPV6_PMTUDISC_DO;
  580                 if (setsockopt(socket6, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, sizeof(val))) {
  581                     perror("setsockopt IPV6_MTU_DISCOVER");
  582                 }
  583             }
  584 #endif
  585 #else
  586             fprintf(stderr, "%s, -M option not supported on this platform\n", prog);
  587             exit(1);
  588 #endif
  589             break;
  590 
  591         case 't':
  592             if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
  593                 usage(1);
  594             if (opt_value_float < 0) {
  595                 usage(1);
  596             }
  597             timeout = opt_value_float * 1000000;
  598             timeout_flag = 1;
  599             break;
  600 
  601         case 'r':
  602             if (!sscanf(optparse_state.optarg, "%u", &retry))
  603                 usage(1);
  604             break;
  605 
  606         case 'i':
  607             if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
  608                 usage(1);
  609             if (opt_value_float < 0) {
  610                 usage(1);
  611             }
  612             interval = opt_value_float * 1000000;
  613             break;
  614 
  615         case 'p':
  616             if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
  617                 usage(1);
  618             if (opt_value_float < 0) {
  619                 usage(1);
  620             }
  621             perhost_interval = opt_value_float * 1000000;
  622 
  623             break;
  624 
  625         case 'c':
  626             if (!(count = (unsigned int)atoi(optparse_state.optarg)))
  627                 usage(1);
  628 
  629             count_flag = 1;
  630             break;
  631 
  632         case 'C':
  633             if (!(count = (unsigned int)atoi(optparse_state.optarg)))
  634                 usage(1);
  635 
  636             count_flag = 1;
  637             report_all_rtts_flag = 1;
  638             break;
  639 
  640         case 'b':
  641             if (!sscanf(optparse_state.optarg, "%u", &ping_data_size))
  642                 usage(1);
  643 
  644             break;
  645 
  646         case 'h':
  647             usage(0);
  648             break;
  649 
  650         case 'q':
  651             verbose_flag = 0;
  652             quiet_flag = 1;
  653             break;
  654 
  655         case 'Q':
  656             verbose_flag = 0;
  657             quiet_flag = 1;
  658             if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
  659                 usage(1);
  660             if (opt_value_float < 0) {
  661                 usage(1);
  662             }
  663             report_interval = opt_value_float * 1e9;
  664 
  665             break;
  666 
  667         case 'e':
  668             elapsed_flag = 1;
  669             break;
  670 
  671         case 'm':
  672             multif_flag = 1;
  673             break;
  674 
  675         case 'N':
  676             netdata_flag = 1;
  677             break;
  678 
  679         case 'n':
  680             name_flag = 1;
  681             if (rdns_flag) {
  682                 fprintf(stderr, "%s: use either one of -d or -n\n", prog);
  683                 exit(1);
  684             }
  685             break;
  686 
  687         case 'd':
  688             rdns_flag = 1;
  689             if (name_flag) {
  690                 fprintf(stderr, "%s: use either one of -d or -n\n", prog);
  691                 exit(1);
  692             }
  693             break;
  694 
  695         case 'A':
  696             addr_flag = 1;
  697             break;
  698 
  699         case 'B':
  700             if (!(backoff = atof(optparse_state.optarg)))
  701                 usage(1);
  702 
  703             break;
  704 
  705         case 's':
  706             stats_flag = 1;
  707             break;
  708 
  709         case 'D':
  710             timestamp_flag = 1;
  711             break;
  712 
  713         case 'R':
  714             random_data_flag = 1;
  715             break;
  716 
  717         case 'l':
  718             loop_flag = 1;
  719             backoff_flag = 0;
  720             break;
  721 
  722         case 'u':
  723             unreachable_flag = 1;
  724             break;
  725 
  726         case 'a':
  727             alive_flag = 1;
  728             break;
  729 
  730         case 'H':
  731             if (!(ttl = (unsigned int)atoi(optparse_state.optarg)))
  732                 usage(1);
  733             break;
  734 
  735 #if defined(DEBUG) || defined(_DEBUG)
  736         case 'z':
  737             if (sscanf(optparse_state.optarg, "0x%x", &debugging) != 1)
  738                 if (sscanf(optparse_state.optarg, "%u", &debugging) != 1)
  739                     usage(1);
  740 
  741             break;
  742 #endif /* DEBUG || _DEBUG */
  743 
  744         case 'v':
  745             printf("%s: Version %s\n", prog, VERSION);
  746             exit(0);
  747 
  748         case 'x':
  749             if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
  750                 usage(1);
  751             break;
  752 
  753         case 'f':
  754             filename = optparse_state.optarg;
  755             break;
  756 
  757         case 'g':
  758             /* use IP list generation */
  759             /* mutually exclusive with using file input or command line targets */
  760             generate_flag = 1;
  761             break;
  762 
  763         case 'S':
  764             if (inet_pton(AF_INET, optparse_state.optarg, &src_addr)) {
  765                 src_addr_set = 1;
  766                 break;
  767             }
  768 #ifdef IPV6
  769             if (inet_pton(AF_INET6, optparse_state.optarg, &src_addr6)) {
  770                 src_addr6_set = 1;
  771                 break;
  772             }
  773 #endif
  774             fprintf(stderr, "%s: can't parse source address: %s\n", prog, optparse_state.optarg);
  775             exit(1);
  776 
  777         case 'I':
  778 #ifdef SO_BINDTODEVICE
  779             if (socket4 >= 0) {
  780                 if (p_setsockopt(suid, socket4, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
  781                     perror("binding to specific interface (SO_BINTODEVICE)");
  782                     exit(1);
  783                 }
  784             }
  785 #ifdef IPV6
  786             if (socket6 >= 0) {
  787                 if (p_setsockopt(suid, socket6, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
  788                     perror("binding to specific interface (SO_BINTODEVICE), IPV6");
  789                     exit(1);
  790                 }
  791             }
  792 #endif
  793 #else
  794             printf("%s: cant bind to a particular net interface since SO_BINDTODEVICE is not supported on your os.\n", prog);
  795             exit(3);
  796             ;
  797 #endif
  798             break;
  799 
  800         case 'T':
  801             /* This option is ignored for compatibility reasons ("select timeout" is not meaningful anymore) */
  802             break;
  803 
  804         case 'O':
  805             if (sscanf(optparse_state.optarg, "%i", &tos)) {
  806                 if (socket4 >= 0) {
  807                     if (setsockopt(socket4, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
  808                         perror("setting type of service octet IP_TOS");
  809                     }
  810                 }
  811 #if defined(IPV6) && defined(IPV6_TCLASS)
  812                 if (socket6 >= 0) {
  813                     if (setsockopt(socket6, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos))) {
  814                         perror("setting type of service octet IPV6_TCLASS");
  815                     }
  816                 }
  817 #endif
  818             }
  819             else {
  820                 usage(1);
  821             }
  822             break;
  823 
  824         case 'o':
  825             outage_flag = 1;
  826             break;
  827 
  828         case '?':
  829             fprintf(stderr, "%s: %s\n", argv[0], optparse_state.errmsg);
  830             fprintf(stderr, "see 'fping -h' for usage information\n");
  831             exit(1);
  832             break;
  833         }
  834     }
  835 
  836     /* permanently drop privileges */
  837     if (suid != getuid() && setuid(getuid())) {
  838     perror("fatal: failed to permanently drop privileges");
  839     /* continuing would be a security hole */
  840     exit(4);
  841     }
  842 
  843     /* validate various option settings */
  844 
  845 #ifndef IPV6
  846     if (socket4 < 0) {
  847 #else
  848     if ((socket4 < 0 && socket6 < 0) || (hints_ai_family == AF_INET6 && socket6 < 0)) {
  849 #endif
  850         crash_and_burn("can't create socket (must run as root?)");
  851     }
  852 
  853     if (ttl > 255) {
  854         fprintf(stderr, "%s: ttl %u out of range\n", prog, ttl);
  855         exit(1);
  856     }
  857 
  858     if (unreachable_flag && alive_flag) {
  859         fprintf(stderr, "%s: specify only one of a, u\n", prog);
  860         exit(1);
  861     }
  862 
  863     if (count_flag && loop_flag) {
  864         fprintf(stderr, "%s: specify only one of c, l\n", prog);
  865         exit(1);
  866     }
  867 
  868 #ifdef FPING_SAFE_LIMITS
  869     if ((interval < (int64_t) MIN_INTERVAL * 1000000 || perhost_interval < (int64_t) MIN_PERHOST_INTERVAL * 1000000)
  870         && getuid()) {
  871         fprintf(stderr, "%s: these options are too risky for mere mortals.\n", prog);
  872         fprintf(stderr, "%s: You need -i >= %u and -p >= %u\n",
  873             prog, MIN_INTERVAL, MIN_PERHOST_INTERVAL);
  874         exit(1);
  875     }
  876 #endif
  877 
  878     if (ping_data_size > MAX_PING_DATA) {
  879         fprintf(stderr, "%s: data size %u not valid, must be lower than %u\n",
  880             prog, ping_data_size, (unsigned int)MAX_PING_DATA);
  881         exit(1);
  882     }
  883 
  884     if ((backoff > MAX_BACKOFF_FACTOR) || (backoff < MIN_BACKOFF_FACTOR)) {
  885         fprintf(stderr, "%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n",
  886             prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR);
  887         exit(1);
  888     }
  889 
  890     if (alive_flag || unreachable_flag || min_reachable)
  891         verbose_flag = 0;
  892 
  893     if (count_flag) {
  894         if (verbose_flag)
  895             per_recv_flag = 1;
  896 
  897         alive_flag = unreachable_flag = verbose_flag = 0;
  898     }
  899 
  900     if (loop_flag) {
  901         if (!report_interval)
  902             per_recv_flag = 1;
  903 
  904         alive_flag = unreachable_flag = verbose_flag = 0;
  905     }
  906 
  907     trials = (count > retry + 1) ? count : retry + 1;
  908 
  909     /* auto-tune default timeout for count/loop modes
  910      * see also github #32 */
  911     if (loop_flag || count_flag) {
  912         if (!timeout_flag) {
  913             timeout = perhost_interval;
  914             if (timeout > (int64_t) AUTOTUNE_TIMEOUT_MAX * 1000000) {
  915                 timeout = (int64_t) AUTOTUNE_TIMEOUT_MAX * 1000000;
  916             }
  917         }
  918     }
  919 
  920 #if defined(DEBUG) || defined(_DEBUG)
  921     if (debugging & DBG_TRACE)
  922         trace_flag = 1;
  923 
  924     if (debugging & DBG_RANDOM_LOSE_FEW) {
  925         randomly_lose_flag = 1;
  926         lose_factor = 1; /* ie, 1/4 */
  927     }
  928 
  929     if (debugging & DBG_RANDOM_LOSE_MANY) {
  930         randomly_lose_flag = 1;
  931         lose_factor = 5; /* ie, 3/4 */
  932     }
  933 
  934     if (debugging & DBG_PRINT_PER_SYSTEM)
  935         print_per_system_flag = 1;
  936 
  937     if ((debugging & DBG_REPORT_ALL_RTTS) && !loop_flag)
  938         report_all_rtts_flag = 1;
  939 
  940     if (trace_flag) {
  941         fprintf(stderr, "%s:\n  count: %u, retry: %u, interval: %.0f ms\n",
  942             prog, count, retry, interval / 1e6);
  943         fprintf(stderr, "  perhost_interval: %.0f ms, timeout: %.0f\n",
  944             perhost_interval / 1e6, timeout / 1e6);
  945         fprintf(stderr, "  ping_data_size = %u, trials = %u\n",
  946             ping_data_size, trials);
  947 
  948         if (verbose_flag)
  949             fprintf(stderr, "  verbose_flag set\n");
  950         if (multif_flag)
  951             fprintf(stderr, "  multif_flag set\n");
  952         if (name_flag)
  953             fprintf(stderr, "  name_flag set\n");
  954         if (addr_flag)
  955             fprintf(stderr, "  addr_flag set\n");
  956         if (stats_flag)
  957             fprintf(stderr, "  stats_flag set\n");
  958         if (unreachable_flag)
  959             fprintf(stderr, "  unreachable_flag set\n");
  960         if (alive_flag)
  961             fprintf(stderr, "  alive_flag set\n");
  962         if (elapsed_flag)
  963             fprintf(stderr, "  elapsed_flag set\n");
  964         if (version_flag)
  965             fprintf(stderr, "  version_flag set\n");
  966         if (count_flag)
  967             fprintf(stderr, "  count_flag set\n");
  968         if (loop_flag)
  969             fprintf(stderr, "  loop_flag set\n");
  970         if (backoff_flag)
  971             fprintf(stderr, "  backoff_flag set\n");
  972         if (per_recv_flag)
  973             fprintf(stderr, "  per_recv_flag set\n");
  974         if (report_all_rtts_flag)
  975             fprintf(stderr, "  report_all_rtts_flag set\n");
  976         if (randomly_lose_flag)
  977             fprintf(stderr, "  randomly_lose_flag set\n");
  978         if (print_per_system_flag)
  979             fprintf(stderr, "  print_per_system_flag set\n");
  980         if (outage_flag)
  981             fprintf(stderr, "  outage_flag set\n");
  982         if (netdata_flag)
  983             fprintf(stderr, "  netdata_flag set\n");
  984     }
  985 #endif /* DEBUG || _DEBUG */
  986 
  987     /* set the TTL, if the -H option was set (otherwise ttl will be = 0) */
  988     if (ttl > 0) {
  989         if (socket4 >= 0) {
  990             if (setsockopt(socket4, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) {
  991                 perror("setting time to live");
  992             }
  993         }
  994 #ifdef IPV6
  995         if (socket6 >= 0) {
  996             if (setsockopt(socket6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl))) {
  997                 perror("setting time to live");
  998             }
  999         }
 1000 #endif
 1001     }
 1002 
 1003 #if HAVE_SO_TIMESTAMPNS
 1004     {
 1005         int opt = 1;
 1006         if (socket4 >= 0) {
 1007             if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
 1008                 perror("setting SO_TIMESTAMPNS option");
 1009             }
 1010         }
 1011 #ifdef IPV6
 1012         if (socket6 >= 0) {
 1013             if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
 1014                 perror("setting SO_TIMESTAMPNS option (IPv6)");
 1015             }
 1016         }
 1017 #endif
 1018     }
 1019 #endif
 1020 
 1021     update_current_time();
 1022     start_time = current_time_ns;
 1023 
 1024     /* handle host names supplied on command line or in a file */
 1025     /* if the generate_flag is on, then generate the IP list */
 1026 
 1027     argv = &argv[optparse_state.optind];
 1028     argc -= optparse_state.optind;
 1029 
 1030     /* calculate how many ping can be in-flight per host */
 1031     if(count_flag) {
 1032         event_storage_count = count;
 1033     }
 1034     else if(loop_flag) {
 1035         if(perhost_interval > timeout) {
 1036             event_storage_count = 1;
 1037         }
 1038         else {
 1039             event_storage_count = 1 + timeout / perhost_interval;
 1040         }
 1041     }
 1042     else {
 1043         event_storage_count = 1;
 1044     }
 1045 
 1046     /* file and generate are mutually exclusive */
 1047     /* file and command line are mutually exclusive */
 1048     /* generate requires command line parameters beyond the switches */
 1049     if ((*argv && filename) || (filename && generate_flag) || (generate_flag && !*argv))
 1050         usage(1);
 1051 
 1052     /* if no conditions are specified, then assume input from stdin */
 1053     if (!*argv && !filename && !generate_flag)
 1054         filename = "-";
 1055 
 1056     if (*argv && !generate_flag) {
 1057         while (*argv) {
 1058             add_name(*argv);
 1059             ++argv;
 1060         }
 1061     }
 1062     else if (filename) {
 1063         FILE* ping_file;
 1064         char line[132];
 1065         char host[132];
 1066 
 1067         if (strcmp(filename, "-") == 0)
 1068             ping_file = fdopen(0, "r");
 1069         else
 1070             ping_file = fopen(filename, "r");
 1071 
 1072         if (!ping_file)
 1073             errno_crash_and_burn("fopen");
 1074 
 1075         while (fgets(line, sizeof(line), ping_file)) {
 1076             if (sscanf(line, "%s", host) != 1)
 1077                 continue;
 1078 
 1079             if ((!*host) || (host[0] == '#')) /* magic to avoid comments */
 1080                 continue;
 1081 
 1082             add_name(host);
 1083         }
 1084 
 1085         fclose(ping_file);
 1086     }
 1087     else if (*argv && generate_flag) {
 1088         if (argc == 1) {
 1089             /* one target: we expect a cidr range (n.n.n.n/m) */
 1090             add_cidr(argv[0]);
 1091         }
 1092         else if (argc == 2) {
 1093             add_range(argv[0], argv[1]);
 1094         }
 1095         else {
 1096             usage(1);
 1097         }
 1098     }
 1099     else {
 1100         usage(1);
 1101     }
 1102 
 1103     if (!num_hosts) {
 1104         exit(num_noaddress ? 2 : 1);
 1105     }
 1106 
 1107     if (src_addr_set && socket4 >= 0) {
 1108         socket_set_src_addr_ipv4(socket4, &src_addr, (socktype4 == SOCK_DGRAM) ? &ident4 : NULL);
 1109     }
 1110 #ifdef IPV6
 1111     if (src_addr6_set && socket6 >= 0) {
 1112         socket_set_src_addr_ipv6(socket6, &src_addr6, (socktype6 == SOCK_DGRAM) ? &ident6 : NULL);
 1113     }
 1114 #endif
 1115 
 1116     /* allocate and initialize array to map host nr to host_entry */
 1117     {
 1118         struct event *cursor = event_queue_ping.first;
 1119         int i= 0;
 1120         table = (HOST_ENTRY**)calloc(num_hosts, sizeof(HOST_ENTRY *));
 1121         if (!table)
 1122             crash_and_burn("Can't malloc array of hosts");
 1123         /* initialize table of hosts. we know that we have ping events scheduled
 1124          * for each of them */
 1125         for (cursor = event_queue_ping.first; cursor; cursor = cursor->ev_next) {
 1126             table[i] = cursor->host;
 1127             cursor->host->i = i;
 1128             i++;
 1129         }
 1130     }
 1131 
 1132     init_ping_buffer_ipv4(ping_data_size);
 1133 #ifdef IPV6
 1134     init_ping_buffer_ipv6(ping_data_size);
 1135 #endif
 1136 
 1137 #ifdef USE_SIGACTION
 1138     memset(&act, 0, sizeof(act));
 1139     act.sa_handler = signal_handler;
 1140     sigemptyset(&act.sa_mask);
 1141     sigaddset(&act.sa_mask, SIGINT);
 1142     sigaddset(&act.sa_mask, SIGQUIT);
 1143     act.sa_flags = SA_RESTART;
 1144     if (sigaction(SIGQUIT, &act, NULL) || sigaction(SIGINT, &act, NULL)) {
 1145         crash_and_burn("failure to set signal handler");
 1146     }
 1147 #else
 1148     signal(SIGINT, signal_handler);
 1149     signal(SIGQUIT, signal_handler);
 1150 #endif
 1151     setlinebuf(stdout);
 1152 
 1153     if (report_interval) {
 1154         next_report_time = current_time_ns + report_interval;
 1155     }
 1156 
 1157     last_send_time = 0;
 1158 
 1159     seqmap_init();
 1160 
 1161     /* main loop */
 1162     main_loop();
 1163 
 1164     finish();
 1165 
 1166     return 0;
 1167 }
 1168 
 1169 static inline int64_t timespec_ns(struct timespec* a)
 1170 {
 1171     return ((int64_t) a->tv_sec * 1000000000) + a->tv_nsec;
 1172 }
 1173 
 1174 void add_cidr(char* addr)
 1175 {
 1176     char* addr_end;
 1177     char* mask_str;
 1178     unsigned long mask;
 1179     unsigned long bitmask;
 1180     int ret;
 1181     struct addrinfo addr_hints;
 1182     struct addrinfo* addr_res;
 1183     unsigned long net_addr;
 1184     unsigned long net_last;
 1185 
 1186     /* Split address from mask */
 1187     addr_end = strchr(addr, '/');
 1188     if (addr_end == NULL) {
 1189         usage(1);
 1190     }
 1191     *addr_end = '\0';
 1192     mask_str = addr_end + 1;
 1193     mask = atoi(mask_str);
 1194 
 1195     /* parse address (IPv4 only) */
 1196     memset(&addr_hints, 0, sizeof(struct addrinfo));
 1197     addr_hints.ai_family = AF_UNSPEC;
 1198     addr_hints.ai_flags = AI_NUMERICHOST;
 1199     ret = getaddrinfo(addr, NULL, &addr_hints, &addr_res);
 1200     if (ret) {
 1201         fprintf(stderr, "%s, can't parse address %s: %s\n", prog, addr, gai_strerror(ret));
 1202         exit(1);
 1203     }
 1204     if (addr_res->ai_family != AF_INET) {
 1205         fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
 1206         exit(1);
 1207     }
 1208     net_addr = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
 1209 
 1210     /* check mask */
 1211     if (mask < 1 || mask > 32) {
 1212         fprintf(stderr, "%s: netmask must be between 1 and 32 (is: %s)\n", prog, mask_str);
 1213         exit(1);
 1214     }
 1215 
 1216     /* convert mask integer from 1 to 32 to a bitmask */
 1217     bitmask = ((unsigned long)0xFFFFFFFF) << (32 - mask);
 1218 
 1219     /* calculate network range */
 1220     net_addr &= bitmask;
 1221     net_last = net_addr + ((unsigned long)0x1 << (32 - mask)) - 1;
 1222 
 1223     /* exclude network and broadcast address for regular prefixes */
 1224     if (mask < 31) {
 1225         net_last--;
 1226         net_addr++;
 1227     }
 1228 
 1229     /* add all hosts in that network (net_addr and net_last inclusive) */
 1230     for (; net_addr <= net_last; net_addr++) {
 1231         struct in_addr in_addr_tmp;
 1232         char buffer[20];
 1233         in_addr_tmp.s_addr = htonl(net_addr);
 1234         inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
 1235         add_name(buffer);
 1236     }
 1237 
 1238     freeaddrinfo(addr_res);
 1239 }
 1240 
 1241 void add_range(char* start, char* end)
 1242 {
 1243     struct addrinfo addr_hints;
 1244     struct addrinfo* addr_res;
 1245     unsigned long start_long;
 1246     unsigned long end_long;
 1247     int ret;
 1248 
 1249     /* parse start address (IPv4 only) */
 1250     memset(&addr_hints, 0, sizeof(struct addrinfo));
 1251     addr_hints.ai_family = AF_UNSPEC;
 1252     addr_hints.ai_flags = AI_NUMERICHOST;
 1253     ret = getaddrinfo(start, NULL, &addr_hints, &addr_res);
 1254     if (ret) {
 1255         fprintf(stderr, "%s: can't parse address %s: %s\n", prog, start, gai_strerror(ret));
 1256         exit(1);
 1257     }
 1258     if (addr_res->ai_family != AF_INET) {
 1259         freeaddrinfo(addr_res);
 1260         fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
 1261         exit(1);
 1262     }
 1263     start_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
 1264 
 1265     /* parse end address (IPv4 only) */
 1266     memset(&addr_hints, 0, sizeof(struct addrinfo));
 1267     addr_hints.ai_family = AF_UNSPEC;
 1268     addr_hints.ai_flags = AI_NUMERICHOST;
 1269     ret = getaddrinfo(end, NULL, &addr_hints, &addr_res);
 1270     if (ret) {
 1271         fprintf(stderr, "%s: can't parse address %s: %s\n", prog, end, gai_strerror(ret));
 1272         exit(1);
 1273     }
 1274     if (addr_res->ai_family != AF_INET) {
 1275         freeaddrinfo(addr_res);
 1276         fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
 1277         exit(1);
 1278     }
 1279     end_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
 1280     freeaddrinfo(addr_res);
 1281 
 1282     if (end_long > start_long + MAX_GENERATE) {
 1283         fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
 1284         exit(1);
 1285     }
 1286 
 1287     /* generate */
 1288     for (; start_long <= end_long; start_long++) {
 1289         struct in_addr in_addr_tmp;
 1290         char buffer[20];
 1291         in_addr_tmp.s_addr = htonl(start_long);
 1292         inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
 1293         add_name(buffer);
 1294     }
 1295 }
 1296 
 1297 void main_loop()
 1298 {
 1299     int64_t lt;
 1300     int64_t wait_time_ns;
 1301     struct event *event;
 1302     struct host_entry *h;
 1303 
 1304     while (event_queue_ping.first || event_queue_timeout.first) {
 1305         dbg_printf("%s", "# main_loop\n");
 1306 
 1307         /* timeout event ? */
 1308         if (event_queue_timeout.first &&
 1309             event_queue_timeout.first->ev_time - current_time_ns <= 0)
 1310         {
 1311             event = ev_dequeue(&event_queue_timeout);
 1312             h = event->host;
 1313 
 1314             dbg_printf("%s [%d]: timeout event\n", h->host, event->ping_index);
 1315 
 1316             stats_add(h, event->ping_index, 0, -1);
 1317 
 1318             if (per_recv_flag) {
 1319                 if (timestamp_flag) {
 1320                     printf("[%.5f] ", (double)current_time_ns / 1e9);
 1321                 }
 1322                 printf("%-*s : [%d], timed out",
 1323                     max_hostname_len, h->host, event->ping_index);
 1324                 if(h->num_recv > 0) {
 1325                     printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
 1326                 }
 1327                 else {
 1328                     printf(" (NaN avg, ");
 1329                 }
 1330                 if (h->num_recv <= h->num_sent) {
 1331                     printf("%d%% loss)",
 1332                         ((h->num_sent - h->num_recv) * 100) / h->num_sent);
 1333                 }
 1334                 else {
 1335                     printf("%d%% return)",
 1336                         (h->num_recv_total * 100) / h->num_sent);
 1337                 }
 1338                 printf("\n");
 1339             }
 1340 
 1341             /* do we need to send a retry? */
 1342             if (!loop_flag && !count_flag) {
 1343                 if (h->num_sent < retry + 1) {
 1344                     if (backoff_flag) {
 1345                         h->timeout *= backoff;
 1346                     }
 1347                     send_ping(h, event->ping_index);
 1348                 }
 1349             }
 1350 
 1351             /* note: we process first timeout events, because we might need to
 1352              * wait to process ping events, while we for sure never need to
 1353              * wait for timeout events.
 1354              */
 1355             continue;
 1356         }
 1357 
 1358         /* ping event ? */
 1359         if (event_queue_ping.first &&
 1360             event_queue_ping.first->ev_time - current_time_ns <= 0)
 1361         {
 1362             /* Make sure that we don't ping more than once every "interval" */
 1363             lt = current_time_ns - last_send_time;
 1364             if (lt < interval)
 1365                 goto wait_for_reply;
 1366 
 1367             /* Dequeue the event */
 1368             event = ev_dequeue(&event_queue_ping);
 1369             h = event->host;
 1370 
 1371             dbg_printf("%s [%d]: ping event\n", h->host, event->ping_index);
 1372 
 1373             /* Send the ping */
 1374             send_ping(h, event->ping_index);
 1375 
 1376             /* Loop and count mode: schedule next ping */
 1377             if (loop_flag || (count_flag && event->ping_index+1 < count)) {
 1378                 host_add_ping_event(h, event->ping_index+1, event->ev_time + perhost_interval);
 1379             }
 1380         }
 1381         
 1382         wait_for_reply:
 1383 
 1384         /* When is the next ping next event? */
 1385         wait_time_ns = -1;
 1386         if (event_queue_ping.first) {
 1387             wait_time_ns = event_queue_ping.first->ev_time - current_time_ns;
 1388             if (wait_time_ns < 0)
 1389                 wait_time_ns = 0;
 1390             /* make sure that we wait enough, so that the inter-ping delay is
 1391              * bigger than 'interval' */
 1392             if (wait_time_ns < interval) {
 1393                 lt = current_time_ns - last_send_time;
 1394                 if (lt < interval) {
 1395                     wait_time_ns = interval - lt;
 1396                 }
 1397             }
 1398 
 1399             dbg_printf("next ping event in %.0f ms (%s)\n", wait_time_ns / 1e6, event_queue_ping.first->host->host);
 1400         }
 1401 
 1402         /* When is the next timeout event? */
 1403         if (event_queue_timeout.first) {
 1404             int64_t wait_time_timeout = event_queue_timeout.first->ev_time - current_time_ns;
 1405             if(wait_time_ns < 0 || wait_time_timeout < wait_time_ns) {
 1406                 wait_time_ns = wait_time_timeout;
 1407                 if (wait_time_ns < 0) {
 1408                     wait_time_ns = 0;
 1409                 }
 1410             }
 1411             
 1412             dbg_printf("next timeout event in %.0f ms (%s)\n", wait_time_timeout / 1e6, event_queue_timeout.first->host->host);
 1413         }
 1414 
 1415         /* When is the next report due? */
 1416         if (report_interval && (loop_flag || count_flag)) {
 1417             int64_t wait_time_next_report = next_report_time - current_time_ns;
 1418             if (wait_time_next_report < wait_time_ns) {
 1419                 wait_time_ns = wait_time_next_report;
 1420                 if (wait_time_ns < 0) {
 1421                     wait_time_ns = 0;
 1422                 }
 1423             }
 1424 
 1425             dbg_printf("next report  event in %0.f ms\n", wait_time_next_report / 1e6);
 1426         }
 1427 
 1428         /* if wait_time is still -1, it means that we are waiting for nothing... */
 1429         if(wait_time_ns == -1) {
 1430             break;
 1431         }
 1432 
 1433         /* end of loop was requested by interrupt signal handler */
 1434         if (finish_requested) {
 1435             break;
 1436         }
 1437 
 1438         /* Receive replies */
 1439         /* (this is what sleeps during each loop iteration) */
 1440         dbg_printf("waiting up to %.0f ms\n", wait_time_ns / 1e6);
 1441         if (wait_for_reply(wait_time_ns)) {
 1442             while (wait_for_reply(0))
 1443                 ; /* process other replies in the queue */
 1444         }
 1445 
 1446         update_current_time();
 1447 
 1448         if (status_snapshot) {
 1449             status_snapshot = 0;
 1450             print_per_system_splits();
 1451         }
 1452 
 1453         /* Print report */
 1454         if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) {
 1455             if (netdata_flag)
 1456                 print_netdata();
 1457             else
 1458                 print_per_system_splits();
 1459 
 1460             while (current_time_ns >= next_report_time) {
 1461                 next_report_time += report_interval;
 1462             }
 1463         }
 1464     }
 1465 }
 1466 
 1467 /************************************************************
 1468 
 1469   Function: signal_handler
 1470 
 1471 *************************************************************
 1472 
 1473   Inputs:  int signum
 1474 
 1475   Description:
 1476 
 1477   SIGQUIT signal handler - set flag and return
 1478   SIGINT signal handler - set flag and return
 1479 
 1480 ************************************************************/
 1481 
 1482 void signal_handler(int signum)
 1483 {
 1484     switch (signum) {
 1485     case SIGINT:
 1486         finish_requested = 1;
 1487         break;
 1488 
 1489     case SIGQUIT:
 1490         status_snapshot = 1;
 1491         break;
 1492     }
 1493 }
 1494 
 1495 /************************************************************
 1496 
 1497   Function: update_current_time
 1498 
 1499 *************************************************************/
 1500 
 1501 void update_current_time()
 1502 {
 1503     clock_gettime(CLOCKID, &current_time);
 1504     current_time_ns = timespec_ns(&current_time);
 1505 }
 1506 
 1507 
 1508 /************************************************************
 1509 
 1510   Function: finish
 1511 
 1512 *************************************************************
 1513 
 1514   Inputs:  void (none)
 1515 
 1516   Description:
 1517 
 1518   Main program clean up and exit point
 1519 
 1520 ************************************************************/
 1521 
 1522 void finish()
 1523 {
 1524     int i;
 1525     HOST_ENTRY* h;
 1526 
 1527     update_current_time();
 1528     end_time = current_time_ns;
 1529 
 1530     /* tot up unreachables */
 1531     for (i = 0; i < num_hosts; i++) {
 1532         h = table[i];
 1533 
 1534         if (!h->num_recv) {
 1535             num_unreachable++;
 1536 
 1537             if (verbose_flag || unreachable_flag) {
 1538                 printf("%s", h->host);
 1539 
 1540                 if (verbose_flag)
 1541                     printf(" is unreachable");
 1542 
 1543                 printf("\n");
 1544             }
 1545         }
 1546     }
 1547 
 1548     if (count_flag || loop_flag)
 1549         print_per_system_stats();
 1550 #if defined(DEBUG) || defined(_DEBUG)
 1551     else if (print_per_system_flag)
 1552         print_per_system_stats();
 1553 #endif /* DEBUG || _DEBUG */
 1554 
 1555     if (stats_flag)
 1556         print_global_stats();
 1557 
 1558     if (min_reachable) {
 1559         if ((num_hosts-num_unreachable) >= min_reachable) {
 1560             printf("Enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts-num_unreachable);
 1561             exit(0);
 1562         } else {
 1563             printf("Not enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts-num_unreachable);
 1564             exit(1);
 1565         }
 1566     }
 1567 
 1568     if (num_noaddress)
 1569         exit(2);
 1570     else if (num_alive != num_hosts)
 1571         exit(1);
 1572 
 1573     exit(0);
 1574 }
 1575 
 1576 /************************************************************
 1577 
 1578   Function: print_per_system_stats
 1579 
 1580 *************************************************************
 1581 
 1582   Inputs:  void (none)
 1583 
 1584   Description:
 1585 
 1586 
 1587 ************************************************************/
 1588 
 1589 void print_per_system_stats(void)
 1590 {
 1591     int i, j, avg, outage_ms;
 1592     HOST_ENTRY* h;
 1593     int64_t resp;
 1594 
 1595     if (verbose_flag || per_recv_flag)
 1596         fprintf(stderr, "\n");
 1597 
 1598     for (i = 0; i < num_hosts; i++) {
 1599         h = table[i];
 1600         fprintf(stderr, "%-*s :", max_hostname_len, h->host);
 1601 
 1602         if (report_all_rtts_flag) {
 1603             for (j = 0; j < h->num_sent; j++) {
 1604                 if ((resp = h->resp_times[j]) >= 0)
 1605                     fprintf(stderr, " %s", sprint_tm(resp));
 1606                 else
 1607                     fprintf(stderr, " -");
 1608             }
 1609 
 1610             fprintf(stderr, "\n");
 1611         }
 1612         else {
 1613             if (h->num_recv <= h->num_sent) {
 1614                 fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
 1615                     h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
 1616 
 1617                 if (outage_flag) {
 1618                     /* Time outage total */
 1619                     outage_ms = (h->num_sent - h->num_recv) * perhost_interval / 1e6;
 1620                     fprintf(stderr, ", outage(ms) = %d", outage_ms);
 1621                 }
 1622             }
 1623             else {
 1624                 fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
 1625                     h->num_sent, h->num_recv,
 1626                     ((h->num_recv * 100) / h->num_sent));
 1627             }
 1628 
 1629             if (h->num_recv) {
 1630                 avg = h->total_time / h->num_recv;
 1631                 fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
 1632                 fprintf(stderr, "/%s", sprint_tm(avg));
 1633                 fprintf(stderr, "/%s", sprint_tm(h->max_reply));
 1634             }
 1635 
 1636             fprintf(stderr, "\n");
 1637         }
 1638     }
 1639 }
 1640 
 1641 /************************************************************
 1642 
 1643   Function: print_netdata
 1644 
 1645 *************************************************************
 1646 
 1647   Inputs:  void (none)
 1648 
 1649   Description:
 1650 
 1651 
 1652 ************************************************************/
 1653 
 1654 void print_netdata(void)
 1655 {
 1656     static int sent_charts = 0;
 1657 
 1658     int i;
 1659     int64_t avg;
 1660     HOST_ENTRY* h;
 1661 
 1662     for (i = 0; i < num_hosts; i++) {
 1663         h = table[i];
 1664 
 1665         if (!sent_charts) {
 1666             printf("CHART fping.%s_packets '' 'FPing Packets for host %s' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, h->host, report_interval / 1e9);
 1667             printf("DIMENSION xmt sent absolute 1 1\n");
 1668             printf("DIMENSION rcv received absolute 1 1\n");
 1669         }
 1670 
 1671         printf("BEGIN fping.%s_packets\n", h->name);
 1672         printf("SET xmt = %d\n", h->num_sent_i);
 1673         printf("SET rcv = %d\n", h->num_recv_i);
 1674         printf("END\n");
 1675 
 1676         if (!sent_charts) {
 1677             printf("CHART fping.%s_quality '' 'FPing Quality for host %s' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, h->host, report_interval / 1e9);
 1678             printf("DIMENSION returned '' absolute 1 1\n");
 1679             /* printf("DIMENSION lost '' absolute 1 1\n"); */
 1680         }
 1681 
 1682         printf("BEGIN fping.%s_quality\n", h->name);
 1683         /*
 1684         if( h->num_recv_i <= h->num_sent_i )
 1685             printf("SET lost = %d\n", h->num_sent_i > 0 ? ( ( h->num_sent_i - h->num_recv_i ) * 100 ) / h->num_sent_i : 0 );
 1686         else
 1687             printf("SET lost = 0\n");
 1688 */
 1689 
 1690         printf("SET returned = %d\n", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
 1691         printf("END\n");
 1692 
 1693         if (!sent_charts) {
 1694             printf("CHART fping.%s_latency '' 'FPing Latency for host %s' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, h->host, report_interval / 1e9);
 1695             printf("DIMENSION min minimum absolute 1 1000000\n");
 1696             printf("DIMENSION max maximum absolute 1 1000000\n");
 1697             printf("DIMENSION avg average absolute 1 1000000\n");
 1698         }
 1699 
 1700         printf("BEGIN fping.%s_latency\n", h->name);
 1701         if (h->num_recv_i) {
 1702             avg = h->total_time_i / h->num_recv_i;
 1703             printf("SET min = %" PRId64 "\n", h->min_reply_i);
 1704             printf("SET avg = %" PRId64 "\n", avg);
 1705             printf("SET max = %" PRId64 "\n", h->max_reply_i);
 1706         }
 1707         printf("END\n");
 1708 
 1709         h->num_sent_i = h->num_recv_i = h->max_reply_i = h->min_reply_i = h->total_time_i = 0;
 1710     }
 1711 
 1712     sent_charts = 1;
 1713 }
 1714 
 1715 /************************************************************
 1716 
 1717   Function: print_per_system_splits
 1718 
 1719 *************************************************************
 1720 
 1721   Inputs:  void (none)
 1722 
 1723   Description:
 1724 
 1725 
 1726 ************************************************************/
 1727 
 1728 void print_per_system_splits(void)
 1729 {
 1730     int i, avg, outage_ms_i;
 1731     HOST_ENTRY* h;
 1732     struct tm* curr_tm;
 1733 
 1734     if (verbose_flag || per_recv_flag)
 1735         fprintf(stderr, "\n");
 1736 
 1737     update_current_time();
 1738     curr_tm = localtime((time_t*)&current_time.tv_sec);
 1739     fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
 1740         curr_tm->tm_min, curr_tm->tm_sec);
 1741 
 1742     for (i = 0; i < num_hosts; i++) {
 1743         h = table[i];
 1744         fprintf(stderr, "%-*s :", max_hostname_len, h->host);
 1745 
 1746         if (h->num_recv_i <= h->num_sent_i) {
 1747             fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
 1748                 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);
 1749 
 1750             if (outage_flag) {
 1751                 /* Time outage  */
 1752                 outage_ms_i = (h->num_sent_i - h->num_recv_i) * perhost_interval / 1e6;
 1753                 fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
 1754             }
 1755         }
 1756         else {
 1757             fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
 1758                 h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
 1759         }
 1760 
 1761         if (h->num_recv_i) {
 1762             avg = h->total_time_i / h->num_recv_i;
 1763             fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
 1764             fprintf(stderr, "/%s", sprint_tm(avg));
 1765             fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
 1766         }
 1767 
 1768         fprintf(stderr, "\n");
 1769         h->num_sent_i = h->num_recv_i = h->max_reply_i = h->min_reply_i = h->total_time_i = 0;
 1770     }
 1771 }
 1772 
 1773 /************************************************************
 1774 
 1775   Function: print_global_stats
 1776 
 1777 *************************************************************
 1778 
 1779   Inputs:  void (none)
 1780 
 1781   Description:
 1782 
 1783 
 1784 ************************************************************/
 1785 
 1786 void print_global_stats(void)
 1787 {
 1788     fprintf(stderr, "\n");
 1789     fprintf(stderr, " %7d targets\n", num_hosts);
 1790     fprintf(stderr, " %7d alive\n", num_alive);
 1791     fprintf(stderr, " %7d unreachable\n", num_unreachable);
 1792     fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
 1793     fprintf(stderr, "\n");
 1794     fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
 1795     fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
 1796     fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
 1797     fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
 1798     fprintf(stderr, "\n");
 1799 
 1800     if (total_replies == 0) {
 1801         min_reply = 0;
 1802         max_reply = 0;
 1803         total_replies = 1;
 1804         sum_replies = 0;
 1805     }
 1806 
 1807     fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
 1808     fprintf(stderr, " %s ms (avg round trip time)\n",
 1809         sprint_tm(sum_replies / total_replies));
 1810     fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
 1811     fprintf(stderr, " %12.3f sec (elapsed real time)\n",
 1812         (end_time - start_time) / 1e9);
 1813     fprintf(stderr, "\n");
 1814 }
 1815 
 1816 /************************************************************
 1817 
 1818   Function: send_ping
 1819 
 1820 *************************************************************
 1821 
 1822   Inputs:  int s, HOST_ENTRY *h
 1823 
 1824   Description:
 1825 
 1826   Compose and transmit an ICMP_ECHO REQUEST packet.  The IP packet
 1827   will be added on by the kernel.  The ID field is our UNIX process ID,
 1828   and the sequence number is an index into an array of outstanding
 1829   ping requests. The sequence number will later be used to quickly
 1830   figure out who the ping reply came from.
 1831 
 1832 ************************************************************/
 1833 
 1834 int send_ping(HOST_ENTRY* h, int index)
 1835 {
 1836     int n;
 1837     int myseq;
 1838     int ret = 1;
 1839 
 1840     update_current_time();
 1841     h->last_send_time = current_time_ns;
 1842     myseq = seqmap_add(h->i, index, current_time_ns);
 1843 
 1844     dbg_printf("%s [%d]: send ping\n", h->host, index);
 1845 
 1846     if (h->saddr.ss_family == AF_INET && socket4 >= 0) {
 1847         n = socket_sendto_ping_ipv4(socket4, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident4);
 1848     }
 1849 #ifdef IPV6
 1850     else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) {
 1851         n = socket_sendto_ping_ipv6(socket6, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident6);
 1852     }
 1853 #endif
 1854     else {
 1855         return 0;
 1856     }
 1857 
 1858     /* error sending? */
 1859     if (
 1860         (n < 0)
 1861 #if defined(EHOSTDOWN)
 1862         && errno != EHOSTDOWN
 1863 #endif
 1864         ) {
 1865         if (verbose_flag) {
 1866             print_warning("%s: error while sending ping: %s\n", h->host, strerror(errno));
 1867         }
 1868         else {
 1869             dbg_printf("%s: error while sending ping: %s\n", h->host, strerror(errno));
 1870         }
 1871 
 1872         h->num_sent++;
 1873         h->num_sent_i++;
 1874         if (!loop_flag)
 1875             h->resp_times[index] = RESP_ERROR;
 1876 
 1877         ret = 0;
 1878     }
 1879     else {
 1880         /* schedule timeout */
 1881         host_add_timeout_event(h, index, current_time_ns + h->timeout);
 1882 
 1883         /* mark this trial as outstanding */
 1884         if (!loop_flag) {
 1885             h->resp_times[index] = RESP_WAITING;
 1886         }
 1887     }
 1888 
 1889     num_pingsent++;
 1890     last_send_time = h->last_send_time;
 1891 
 1892     return (ret);
 1893 }
 1894 
 1895 int socket_can_read(struct timeval* timeout)
 1896 {
 1897     int nfound;
 1898     fd_set readset;
 1899     int socketmax;
 1900 
 1901 #ifndef IPV6
 1902     socketmax = socket4;
 1903 #else
 1904     socketmax = socket4 > socket6 ? socket4 : socket6;
 1905 #endif
 1906 
 1907 select_again:
 1908     FD_ZERO(&readset);
 1909     if(socket4 >= 0) FD_SET(socket4, &readset);
 1910 #ifdef IPV6
 1911     if(socket6 >= 0) FD_SET(socket6, &readset);
 1912 #endif
 1913 
 1914     nfound = select(socketmax + 1, &readset, NULL, NULL, timeout);
 1915     if (nfound < 0) {
 1916         if (errno == EINTR) {
 1917             /* interrupted system call: redo the select */
 1918             goto select_again;
 1919         }
 1920         else {
 1921             perror("select");
 1922         }
 1923     }
 1924 
 1925     if (nfound > 0) {
 1926         if (socket4 >= 0 && FD_ISSET(socket4, &readset)) {
 1927             return socket4;
 1928         }
 1929 #ifdef IPV6
 1930         if (socket6 >= 0 && FD_ISSET(socket6, &readset)) {
 1931             return socket6;
 1932         }
 1933 #endif
 1934     }
 1935 
 1936     return -1;
 1937 }
 1938 
 1939 int receive_packet(int64_t wait_time,
 1940     int64_t* reply_timestamp,
 1941     struct sockaddr* reply_src_addr,
 1942     size_t reply_src_addr_len,
 1943     char* reply_buf,
 1944     size_t reply_buf_len)
 1945 {
 1946     struct timeval to;
 1947     int s = 0;
 1948     int recv_len;
 1949     static unsigned char msg_control[40];
 1950     struct iovec msg_iov = {
 1951         reply_buf,
 1952         reply_buf_len
 1953     };
 1954     struct msghdr recv_msghdr = {
 1955         reply_src_addr,
 1956         reply_src_addr_len,
 1957         &msg_iov,
 1958         1,
 1959         &msg_control,
 1960         sizeof(msg_control),
 1961         0
 1962     };
 1963 #if HAVE_SO_TIMESTAMPNS
 1964     struct cmsghdr* cmsg;
 1965 #endif
 1966 
 1967     /* Wait for a socket to become ready */
 1968     if (wait_time) {
 1969         to.tv_sec = wait_time / UINT64_C(1000000000);
 1970         to.tv_usec = (wait_time % UINT64_C(1000000000)) / 1000 + 1;
 1971     }
 1972     else {
 1973         to.tv_sec = 0;
 1974         to.tv_usec = 0;
 1975     }
 1976     s = socket_can_read(&to);
 1977     if (s == -1) {
 1978         return 0; /* timeout */
 1979     }
 1980 
 1981     recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC);
 1982     if (recv_len <= 0) {
 1983         return 0;
 1984     }
 1985 
 1986 #if HAVE_SO_TIMESTAMPNS
 1987     /* ancilliary data */
 1988     {
 1989         struct timespec reply_timestamp_ts;
 1990         for (cmsg = CMSG_FIRSTHDR(&recv_msghdr);
 1991              cmsg != NULL;
 1992              cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg))
 1993         {
 1994             if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
 1995                 memcpy(&reply_timestamp_ts, CMSG_DATA(cmsg), sizeof(reply_timestamp_ts));
 1996                 *reply_timestamp = timespec_ns(&reply_timestamp_ts);
 1997             }
 1998         }
 1999     }
 2000 #endif
 2001 
 2002 #if defined(DEBUG) || defined(_DEBUG)
 2003     if (randomly_lose_flag) {
 2004         if ((random() & 0x07) <= lose_factor)
 2005             return 0;
 2006     }
 2007 #endif
 2008 
 2009     return recv_len;
 2010 }
 2011 
 2012 /* stats_add: update host statistics for a single packet that was received (or timed out)
 2013  * h: host entry to update
 2014  * index: if in count mode: index number for this ping packet (-1 otherwise)
 2015  * success: 1 if response received, 0 otherwise
 2016  * latency: response time, in ns
 2017  */
 2018 void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency)
 2019 {
 2020     /* sent count - we update only on receive/timeout, so that we don't get
 2021      * weird loss percentage, just because a packet was note recived yet.
 2022      */
 2023     h->num_sent++;
 2024     h->num_sent_i++;
 2025 
 2026     if(!success) {
 2027         if(!loop_flag && index>=0) {
 2028             h->resp_times[index] = RESP_TIMEOUT;
 2029         }
 2030         num_timeout++;
 2031         return;
 2032     }
 2033 
 2034     /* received count */
 2035     h->num_recv++;
 2036     h->num_recv_i++;
 2037 
 2038     /* maximum */
 2039     if (!h->max_reply || latency > h->max_reply) {
 2040         h->max_reply = latency;
 2041     }
 2042     if (!h->max_reply_i || latency > h->max_reply_i) {
 2043         h->max_reply_i = latency;
 2044     }
 2045 
 2046     /* minimum */
 2047     if (!h->min_reply || latency < h->min_reply) {
 2048         h->min_reply = latency;
 2049     }
 2050     if (!h->min_reply_i || latency < h->min_reply_i) {
 2051         h->min_reply_i = latency;
 2052     }
 2053 
 2054     /* total time (for average) */
 2055     h->total_time += latency;
 2056     h->total_time_i += latency;
 2057 
 2058     /* response time per-packet (count mode) */
 2059     if(!loop_flag && index>=0) {
 2060         h->resp_times[index] = latency;
 2061     }
 2062 }
 2063 
 2064 /* stats_reset_interval: reset interval statistics
 2065  * h: host entry to update
 2066  */
 2067 void stats_reset_interval(HOST_ENTRY *h)
 2068 {
 2069     h->num_sent_i = 0;
 2070     h->num_recv_i = 0;
 2071     h->max_reply_i = 0;
 2072     h->min_reply_i = 0;
 2073     h->total_time_i = 0;
 2074 }
 2075 
 2076 int decode_icmp_ipv4(
 2077     struct sockaddr* response_addr,
 2078     size_t response_addr_len,
 2079     char* reply_buf,
 2080     size_t reply_buf_len,
 2081     unsigned short* id,
 2082     unsigned short* seq)
 2083 {
 2084     struct icmp* icp;
 2085     int hlen = 0;
 2086 
 2087     if (!using_sock_dgram4) {
 2088         struct ip* ip = (struct ip*)reply_buf;
 2089 
 2090 #if defined(__alpha__) && __STDC__ && !defined(__GLIBC__)
 2091         /* The alpha headers are decidedly broken.
 2092          * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
 2093          * ip_v.  So, to get ip_hl, we mask off the bottom four bits.
 2094          */
 2095         hlen = (ip->ip_vhl & 0x0F) << 2;
 2096 #else
 2097         hlen = ip->ip_hl << 2;
 2098 #endif
 2099     }
 2100 
 2101 
 2102     if (reply_buf_len < hlen + ICMP_MINLEN) {
 2103         /* too short */
 2104         if (verbose_flag) {
 2105             char buf[INET6_ADDRSTRLEN];
 2106             getnameinfo( response_addr, sizeof( struct sockaddr_in ), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2107             printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
 2108         }
 2109         return -1;
 2110     }
 2111 
 2112     icp = (struct icmp*)(reply_buf + hlen);
 2113 
 2114     if (icp->icmp_type != ICMP_ECHOREPLY) {
 2115         /* Handle other ICMP packets */
 2116         struct icmp* sent_icmp;
 2117         SEQMAP_VALUE* seqmap_value;
 2118         char addr_ascii[INET6_ADDRSTRLEN];
 2119         HOST_ENTRY* h;
 2120 
 2121         /* reply icmp packet (hlen + ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
 2122         if (reply_buf_len < hlen + ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
 2123             /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
 2124             return -1;
 2125         }
 2126 
 2127         sent_icmp = (struct icmp*)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip));
 2128 
 2129         if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) {
 2130             /* not caused by us */
 2131             return -1;
 2132         }
 2133 
 2134         seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), current_time_ns);
 2135         if (seqmap_value == NULL) {
 2136             return -1;
 2137         }
 2138 
 2139         getnameinfo(response_addr, sizeof( struct sockaddr_in ), addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2140 
 2141         switch (icp->icmp_type) {
 2142         case ICMP_UNREACH:
 2143             h = table[seqmap_value->host_nr];
 2144             if (icp->icmp_code > ICMP_UNREACH_MAXTYPE) {
 2145                 print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
 2146                     addr_ascii, h->host);
 2147             }
 2148             else {
 2149                 print_warning("%s from %s for ICMP Echo sent to %s",
 2150                     icmp_unreach_str[icp->icmp_code], addr_ascii, h->host);
 2151             }
 2152 
 2153             print_warning("\n");
 2154             num_othericmprcvd++;
 2155             break;
 2156 
 2157         case ICMP_SOURCEQUENCH:
 2158         case ICMP_REDIRECT:
 2159         case ICMP_TIMXCEED:
 2160         case ICMP_PARAMPROB:
 2161             h = table[seqmap_value->host_nr];
 2162             if (icp->icmp_type <= ICMP_TYPE_STR_MAX) {
 2163                 print_warning("%s from %s for ICMP Echo sent to %s",
 2164                     icmp_type_str[icp->icmp_type], addr_ascii, h->host);
 2165             }
 2166             else {
 2167                 print_warning("ICMP %d from %s for ICMP Echo sent to %s",
 2168                     icp->icmp_type, addr_ascii, h->host);
 2169             }
 2170             print_warning("\n");
 2171             num_othericmprcvd++;
 2172             break;
 2173         }
 2174 
 2175         return -1;
 2176     }
 2177 
 2178     *id = icp->icmp_id;
 2179     *seq = ntohs(icp->icmp_seq);
 2180 
 2181     return hlen;
 2182 }
 2183 
 2184 #ifdef IPV6
 2185 int decode_icmp_ipv6(
 2186     struct sockaddr* response_addr,
 2187     size_t response_addr_len,
 2188     char* reply_buf,
 2189     size_t reply_buf_len,
 2190     unsigned short* id,
 2191     unsigned short* seq)
 2192 {
 2193     struct icmp6_hdr* icp;
 2194 
 2195     if (reply_buf_len < sizeof(struct icmp6_hdr)) {
 2196         if (verbose_flag) {
 2197             char buf[INET6_ADDRSTRLEN];
 2198             getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2199             printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
 2200         }
 2201         return 0; /* too short */
 2202     }
 2203 
 2204     icp = (struct icmp6_hdr*)reply_buf;
 2205 
 2206     if (icp->icmp6_type != ICMP6_ECHO_REPLY) {
 2207         /* Handle other ICMP packets */
 2208         struct icmp6_hdr* sent_icmp;
 2209         SEQMAP_VALUE* seqmap_value;
 2210         char addr_ascii[INET6_ADDRSTRLEN];
 2211         HOST_ENTRY* h;
 2212 
 2213         /* reply icmp packet (ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
 2214         if (reply_buf_len < ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
 2215             /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
 2216             return 0;
 2217         }
 2218 
 2219         sent_icmp = (struct icmp6_hdr*)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip));
 2220 
 2221         if (sent_icmp->icmp6_type != ICMP_ECHO || sent_icmp->icmp6_id != ident6) {
 2222             /* not caused by us */
 2223             return 0;
 2224         }
 2225 
 2226         seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), current_time_ns);
 2227         if (seqmap_value == NULL) {
 2228             return 0;
 2229         }
 2230 
 2231         getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2232 
 2233         switch (icp->icmp6_type) {
 2234         case ICMP_UNREACH:
 2235             h = table[seqmap_value->host_nr];
 2236             if (icp->icmp6_code > ICMP_UNREACH_MAXTYPE) {
 2237                 print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
 2238                     addr_ascii, h->host);
 2239             }
 2240             else {
 2241                 print_warning("%s from %s for ICMP Echo sent to %s",
 2242                     icmp_unreach_str[icp->icmp6_code], addr_ascii, h->host);
 2243             }
 2244 
 2245             print_warning("\n");
 2246             num_othericmprcvd++;
 2247             break;
 2248 
 2249         case ICMP_SOURCEQUENCH:
 2250         case ICMP_REDIRECT:
 2251         case ICMP_TIMXCEED:
 2252         case ICMP_PARAMPROB:
 2253             h = table[seqmap_value->host_nr];
 2254             if (icp->icmp6_type <= ICMP_TYPE_STR_MAX) {
 2255                 print_warning("%s from %s for ICMP Echo sent to %s",
 2256                     icmp_type_str[icp->icmp6_type], addr_ascii, h->host);
 2257             }
 2258             else {
 2259                 print_warning("ICMP %d from %s for ICMP Echo sent to %s",
 2260                     icp->icmp6_type, addr_ascii, h->host);
 2261             }
 2262             print_warning("\n");
 2263             num_othericmprcvd++;
 2264             break;
 2265         }
 2266 
 2267         return 0;
 2268     }
 2269 
 2270     *id = icp->icmp6_id;
 2271     *seq = ntohs(icp->icmp6_seq);
 2272 
 2273     return 1;
 2274 }
 2275 #endif
 2276 
 2277 int wait_for_reply(int64_t wait_time)
 2278 {
 2279     int result;
 2280     static char buffer[RECV_BUFSIZE];
 2281     struct sockaddr_storage response_addr;
 2282     int n, avg;
 2283     HOST_ENTRY* h;
 2284     int64_t this_reply;
 2285     int this_count;
 2286     int64_t recv_time=0;
 2287     SEQMAP_VALUE* seqmap_value;
 2288     unsigned short id;
 2289     unsigned short seq;
 2290 
 2291     /* Receive packet */
 2292     result = receive_packet(wait_time, /* max. wait time, in ns */
 2293         &recv_time, /* reply_timestamp */
 2294         (struct sockaddr*)&response_addr, /* reply_src_addr */
 2295         sizeof(response_addr), /* reply_src_addr_len */
 2296         buffer, /* reply_buf */
 2297         sizeof(buffer) /* reply_buf_len */
 2298         );
 2299 
 2300     if (result <= 0) {
 2301         return 0;
 2302     }
 2303 
 2304     update_current_time();
 2305     if(recv_time==0) recv_time = current_time_ns;
 2306 
 2307     /* Process ICMP packet and retrieve id/seq */
 2308     if (response_addr.ss_family == AF_INET) {
 2309         int ip_hlen = decode_icmp_ipv4(
 2310                 (struct sockaddr*)&response_addr,
 2311                 sizeof(response_addr),
 2312                 buffer,
 2313                 sizeof(buffer),
 2314                 &id,
 2315                 &seq);
 2316         if (ip_hlen < 0) {
 2317             return 1;
 2318         }
 2319         if (id != ident4) {
 2320             return 1; /* packet received, but not the one we are looking for! */
 2321         }
 2322         if (!using_sock_dgram4) {
 2323             /* do not include IP header in returned size, to be consistent with ping(8) and also
 2324              * with fping with IPv6 hosts */
 2325             result -= ip_hlen;
 2326         }
 2327     }
 2328 #ifdef IPV6
 2329     else if (response_addr.ss_family == AF_INET6) {
 2330         if (!decode_icmp_ipv6(
 2331                 (struct sockaddr*)&response_addr,
 2332                 sizeof(response_addr),
 2333                 buffer,
 2334                 sizeof(buffer),
 2335                 &id,
 2336                 &seq)) {
 2337             return 1;
 2338         }
 2339         if (id != ident6) {
 2340             return 1; /* packet received, but not the one we are looking for! */
 2341         }
 2342     }
 2343 #endif
 2344     else {
 2345         return 1;
 2346     }
 2347 
 2348     seqmap_value = seqmap_fetch(seq, current_time_ns);
 2349     if (seqmap_value == NULL) {
 2350         return 1;
 2351     }
 2352 
 2353     /* find corresponding host_entry */
 2354     n = seqmap_value->host_nr;
 2355     h = table[n];
 2356     this_count = seqmap_value->ping_count;
 2357     this_reply = recv_time - seqmap_value->ping_ts;
 2358 
 2359     /* update stats that include invalid replies */
 2360     h->num_recv_total++;
 2361     num_pingreceived++;
 2362 
 2363     dbg_printf("received [%d] from %s\n", this_count, h->host);
 2364 
 2365     /* discard duplicates */
 2366     if (!loop_flag && h->resp_times[this_count] >= 0) {
 2367         if (!per_recv_flag) {
 2368             fprintf(stderr, "%s : duplicate for [%d], %d bytes, %s ms",
 2369                 h->host, this_count, result, sprint_tm(this_reply));
 2370 
 2371             if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
 2372                 char buf[INET6_ADDRSTRLEN];
 2373                 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2374                 fprintf(stderr, " [<- %s]", buf);
 2375             }
 2376             fprintf(stderr, "\n");
 2377         }
 2378         return 1;
 2379     }
 2380 
 2381     /* discard reply if delay is larger than timeout
 2382      * (see also: github #32) */
 2383     if (this_reply > h->timeout) {
 2384         return 1;
 2385     }
 2386 
 2387     /* update stats */
 2388     stats_add(h, this_count, 1, this_reply);
 2389     // TODO: move to stats_add?
 2390     if (!max_reply || this_reply > max_reply)
 2391         max_reply = this_reply;
 2392     if (!min_reply || this_reply < min_reply)
 2393         min_reply = this_reply;
 2394     sum_replies += this_reply;
 2395     total_replies++;
 2396     
 2397     /* initialize timeout to initial timeout (without backoff) */
 2398     h->timeout = timeout;
 2399 
 2400     /* remove timeout event */
 2401     struct event *timeout_event = host_get_timeout_event(h, this_count);
 2402     if(timeout_event) {
 2403         ev_remove(&event_queue_timeout, timeout_event);
 2404     }
 2405     
 2406     /* print "is alive" */
 2407     if (h->num_recv == 1) {
 2408         num_alive++;
 2409         if (verbose_flag || alive_flag) {
 2410             printf("%s", h->host);
 2411 
 2412             if (verbose_flag)
 2413                 printf(" is alive");
 2414 
 2415             if (elapsed_flag)
 2416                 printf(" (%s ms)", sprint_tm(this_reply));
 2417 
 2418             if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
 2419                 char buf[INET6_ADDRSTRLEN];
 2420                 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2421                 fprintf(stderr, " [<- %s]", buf);
 2422             }
 2423 
 2424             printf("\n");
 2425         }
 2426     }
 2427 
 2428     /* print received ping (unless --quiet) */
 2429     if (per_recv_flag) {
 2430         if (timestamp_flag) {
 2431             printf("[%.5f] ", (double)recv_time / 1e9);
 2432         }
 2433         avg = h->total_time / h->num_recv;
 2434         printf("%-*s : [%d], %d bytes, %s ms",
 2435             max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
 2436         printf(" (%s avg, ", sprint_tm(avg));
 2437 
 2438         if (h->num_recv <= h->num_sent) {
 2439             printf("%d%% loss)",
 2440                 ((h->num_sent - h->num_recv) * 100) / h->num_sent);
 2441         }
 2442         else {
 2443             printf("%d%% return)",
 2444                 (h->num_recv_total * 100) / h->num_sent);
 2445         }
 2446 
 2447         if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
 2448             char buf[INET6_ADDRSTRLEN];
 2449             getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
 2450             fprintf(stderr, " [<- %s]", buf);
 2451         }
 2452 
 2453         printf("\n");
 2454     }
 2455 
 2456     return 1;
 2457 }
 2458 
 2459 /************************************************************
 2460 
 2461   Function: add_name
 2462 
 2463 *************************************************************
 2464 
 2465   Inputs:  char* name
 2466 
 2467   Description:
 2468 
 2469   process input name for addition to target list
 2470   name can turn into multiple targets via multiple interfaces (-m)
 2471   or via NIS groups
 2472 
 2473 ************************************************************/
 2474 
 2475 void add_name(char* name)
 2476 {
 2477     struct addrinfo *res0, *res, hints;
 2478     int ret_ga;
 2479     char* printname;
 2480     char namebuf[256];
 2481     char addrbuf[256];
 2482 
 2483     /* getaddrinfo */
 2484     memset(&hints, 0, sizeof(struct addrinfo));
 2485     hints.ai_flags = AI_UNUSABLE;
 2486     hints.ai_socktype = SOCK_RAW;
 2487     hints.ai_family = hints_ai_family;
 2488     if (hints_ai_family == AF_INET) {
 2489         hints.ai_protocol = IPPROTO_ICMP;
 2490     }
 2491 #ifdef IPV6
 2492     else if (hints_ai_family == AF_INET6) {
 2493         hints.ai_protocol = IPPROTO_ICMPV6;
 2494     }
 2495 #endif
 2496     else {
 2497         hints.ai_socktype = SOCK_STREAM;
 2498         hints.ai_protocol = 0;
 2499     }
 2500     ret_ga = getaddrinfo(name, NULL, &hints, &res0);
 2501     if (ret_ga) {
 2502         if (!quiet_flag)
 2503             print_warning("%s: %s\n", name, gai_strerror(ret_ga));
 2504         num_noaddress++;
 2505         return;
 2506     }
 2507 
 2508     /* NOTE: we could/should loop with res on all addresses like this:
 2509      * for (res = res0; res; res = res->ai_next) {
 2510      * We don't do it yet, however, because is is an incompatible change
 2511      * (need to implement a separate option for this)
 2512      */
 2513     for (res = res0; res; res = res->ai_next) {
 2514         /* name_flag: addr -> name lookup requested) */
 2515         if (name_flag || rdns_flag) {
 2516             int do_rdns = rdns_flag ? 1 : 0;
 2517             if (name_flag) {
 2518                 /* Was it a numerical address? Only then do a rdns-query */
 2519                 struct addrinfo* nres;
 2520                 hints.ai_flags = AI_NUMERICHOST;
 2521                 if (getaddrinfo(name, NULL, &hints, &nres) == 0) {
 2522                     do_rdns = 1;
 2523                     freeaddrinfo(nres);
 2524                 }
 2525             }
 2526 
 2527             if (do_rdns && getnameinfo(res->ai_addr, res->ai_addrlen, namebuf, sizeof(namebuf) / sizeof(char), NULL, 0, 0) == 0) {
 2528                 printname = namebuf;
 2529             }
 2530             else {
 2531                 printname = name;
 2532             }
 2533         }
 2534         else {
 2535             printname = name;
 2536         }
 2537 
 2538         /* addr_flag: name -> addr lookup requested */
 2539         if (addr_flag) {
 2540             int ret;
 2541             ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
 2542                 sizeof(addrbuf) / sizeof(char), NULL, 0, NI_NUMERICHOST);
 2543             if (ret) {
 2544                 if (!quiet_flag) {
 2545                     print_warning("%s: can't forward-lookup address (%s)\n", name, gai_strerror(ret));
 2546                 }
 2547                 continue;
 2548             }
 2549 
 2550             if (name_flag || rdns_flag) {
 2551                 char nameaddrbuf[512+3];
 2552                 snprintf(nameaddrbuf, sizeof(nameaddrbuf) / sizeof(char), "%s (%s)", printname, addrbuf);
 2553                 add_addr(name, nameaddrbuf, res->ai_addr, res->ai_addrlen);
 2554             }
 2555             else {
 2556                 add_addr(name, addrbuf, res->ai_addr, res->ai_addrlen);
 2557             }
 2558         }
 2559         else {
 2560             add_addr(name, printname, res->ai_addr, res->ai_addrlen);
 2561         }
 2562 
 2563         if (!multif_flag) {
 2564             break;
 2565         }
 2566     }
 2567 
 2568     freeaddrinfo(res0);
 2569 }
 2570 
 2571 /************************************************************
 2572 
 2573   Function: add_addr
 2574 
 2575 *************************************************************
 2576 
 2577   Description:
 2578 
 2579   add single address to list of hosts to be pinged
 2580 
 2581 ************************************************************/
 2582 
 2583 void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len)
 2584 {
 2585     HOST_ENTRY* p;
 2586     int n;
 2587     int64_t *i;
 2588 
 2589     p = (HOST_ENTRY*)calloc(1, sizeof(HOST_ENTRY));
 2590     if (!p)
 2591         crash_and_burn("can't allocate HOST_ENTRY");
 2592 
 2593     p->name = strdup(name);
 2594     p->host = strdup(host);
 2595     memcpy(&p->saddr, ipaddr, ipaddr_len);
 2596     p->saddr_len = ipaddr_len;
 2597     p->timeout = timeout;
 2598     p->min_reply = 0;
 2599 
 2600     if (netdata_flag) {
 2601         char* s = p->name;
 2602         while (*s) {
 2603             if (!isalnum(*s))
 2604                 *s = '_';
 2605             s++;
 2606         }
 2607     }
 2608 
 2609     if (strlen(p->host) > max_hostname_len)
 2610         max_hostname_len = strlen(p->host);
 2611 
 2612     /* array for response time results */
 2613     if (!loop_flag) {
 2614         i = (int64_t*)malloc(trials * sizeof(int64_t));
 2615         if (!i)
 2616             crash_and_burn("can't allocate resp_times array");
 2617 
 2618         for (n = 1; n < trials; n++)
 2619             i[n] = RESP_UNUSED;
 2620 
 2621         p->resp_times = i;
 2622     }
 2623 
 2624     /* allocate event storage */
 2625     p->event_storage_ping = (struct event *) calloc(event_storage_count, sizeof(struct event));
 2626     p->event_storage_timeout = (struct event *) calloc(event_storage_count, sizeof(struct event));
 2627 
 2628     /* schedule first ping */
 2629     host_add_ping_event(p, 0, current_time_ns);
 2630 
 2631     num_hosts++;
 2632 }
 2633 
 2634 /************************************************************
 2635 
 2636   Function: crash_and_burn
 2637 
 2638 *************************************************************
 2639 
 2640   Inputs:  char* message
 2641 
 2642   Description:
 2643 
 2644 ************************************************************/
 2645 
 2646 void crash_and_burn(char* message)
 2647 {
 2648     if (verbose_flag)
 2649         fprintf(stderr, "%s: %s\n", prog, message);
 2650 
 2651     exit(4);
 2652 }
 2653 
 2654 /************************************************************
 2655 
 2656   Function: errno_crash_and_burn
 2657 
 2658 *************************************************************
 2659 
 2660   Inputs:  char* message
 2661 
 2662   Description:
 2663 
 2664 ************************************************************/
 2665 
 2666 void errno_crash_and_burn(char* message)
 2667 {
 2668     fprintf(stderr, "%s: %s : %s\n", prog, message, strerror(errno));
 2669     exit(4);
 2670 }
 2671 
 2672 /************************************************************
 2673 
 2674   Function: print_warning
 2675 
 2676   Description: fprintf(stderr, ...), unless running with -q
 2677 
 2678 *************************************************************/
 2679 
 2680 void print_warning(char* format, ...)
 2681 {
 2682     va_list args;
 2683     if (!quiet_flag) {
 2684         va_start(args, format);
 2685         vfprintf(stderr, format, args);
 2686         va_end(args);
 2687     }
 2688 }
 2689 
 2690 /************************************************************
 2691 
 2692   Function: sprint_tm
 2693 
 2694 *************************************************************
 2695 
 2696   render nanosecond int64_t value into milliseconds string with three digits of
 2697   precision.
 2698 
 2699 ************************************************************/
 2700 
 2701 const char* sprint_tm(int64_t ns)
 2702 {
 2703     static char buf[10];
 2704     double t = (double)ns / 1e6;
 2705 
 2706     if (t < 0.0) {
 2707         /* negative (unexpected) */
 2708         sprintf(buf, "%.2g", t);
 2709     }
 2710     else if (t < 1.0) {
 2711         /* <= 0.99 ms */
 2712         sprintf(buf, "%.3f", t);
 2713     }
 2714     else if (t < 10.0) {
 2715         /* 1.00 - 9.99 ms */
 2716         sprintf(buf, "%.2f", t);
 2717     }
 2718     else if (t < 100.0) {
 2719         /* 10.0 - 99.9 ms */
 2720         sprintf(buf, "%.1f", t);
 2721     }
 2722     else if (t < 1000000.0) {
 2723         /* 100 - 1'000'000 ms */
 2724         sprintf(buf, "%.0f", t);
 2725     }
 2726     else {
 2727         sprintf(buf, "%.3e", t);
 2728     }
 2729 
 2730     return (buf);
 2731 }
 2732 
 2733 /************************************************************
 2734 
 2735   Function: addr_cmp
 2736 
 2737 *************************************************************/
 2738 int addr_cmp(struct sockaddr* a, struct sockaddr* b)
 2739 {
 2740     if (a->sa_family != b->sa_family) {
 2741         return a->sa_family - b->sa_family;
 2742     }
 2743     else {
 2744         if (a->sa_family == AF_INET) {
 2745             return ((struct sockaddr_in*)a)->sin_addr.s_addr - ((struct sockaddr_in*)b)->sin_addr.s_addr;
 2746         }
 2747         else if (a->sa_family == AF_INET6) {
 2748             return memcmp(&((struct sockaddr_in6*)a)->sin6_addr,
 2749                 &((struct sockaddr_in6*)b)->sin6_addr,
 2750                 sizeof(((struct sockaddr_in6*)a)->sin6_addr));
 2751         }
 2752     }
 2753 
 2754     return 0;
 2755 }
 2756 
 2757 void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time)
 2758 {
 2759     struct event *event = &h->event_storage_ping[index % event_storage_count];
 2760     event->host = h;
 2761     event->ping_index = index;
 2762     event->ev_time = ev_time;
 2763     ev_enqueue(&event_queue_ping, event);
 2764 
 2765     dbg_printf("%s [%d]: add ping event in %.0f ms\n",
 2766         event->host->host, index, (ev_time - current_time_ns) / 1e6);
 2767 }
 2768 
 2769 void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time)
 2770 {
 2771     struct event *event = &h->event_storage_timeout[index % event_storage_count];
 2772     event->host = h;
 2773     event->ping_index = index;
 2774     event->ev_time = ev_time;
 2775     ev_enqueue(&event_queue_timeout, event);
 2776 
 2777     dbg_printf("%s [%d]: add timeout event in %.0f ms\n",
 2778         event->host->host, index, (ev_time - current_time_ns) / 1e6);
 2779 }
 2780 
 2781 struct event *host_get_timeout_event(HOST_ENTRY *h, int index)
 2782 {
 2783     return &h->event_storage_timeout[index % event_storage_count];
 2784 }
 2785 
 2786 
 2787 /************************************************************
 2788 
 2789   Function: ev_enqueue
 2790 
 2791   Enqueue an event
 2792 
 2793   The queue is sorted by event->ev_time, so that queue->first always points to
 2794   the earliest event.
 2795 
 2796   We start scanning the queue from the tail, because we assume
 2797   that new events mostly get inserted with a event time higher
 2798   than the others.
 2799 
 2800 *************************************************************/
 2801 void ev_enqueue(struct event_queue *queue, struct event* event)
 2802 {
 2803     struct event* i;
 2804     struct event* i_prev;
 2805 
 2806     /* Empty list */
 2807     if (queue->last == NULL) {
 2808         event->ev_next = NULL;
 2809         event->ev_prev = NULL;
 2810         queue->first = event;
 2811         queue->last = event;
 2812         return;
 2813     }
 2814 
 2815     /* Insert on tail? */
 2816     if (event->ev_time - queue->last->ev_time >= 0) {
 2817         event->ev_next = NULL;
 2818         event->ev_prev = queue->last;
 2819         queue->last->ev_next = event;
 2820         queue->last = event;
 2821         return;
 2822     }
 2823 
 2824     /* Find insertion point */
 2825     i = queue->last;
 2826     while (1) {
 2827         i_prev = i->ev_prev;
 2828         if (i_prev == NULL || event->ev_time - i_prev->ev_time >= 0) {
 2829             event->ev_prev = i_prev;
 2830             event->ev_next = i;
 2831             i->ev_prev = event;
 2832             if (i_prev != NULL) {
 2833                 i_prev->ev_next = event;
 2834             }
 2835             else {
 2836                 queue->first = event;
 2837             }
 2838             return;
 2839         }
 2840         i = i_prev;
 2841     }
 2842 }
 2843 
 2844 /************************************************************
 2845 
 2846   Function: ev_dequeue
 2847 
 2848 *************************************************************/
 2849 struct event *ev_dequeue(struct event_queue *queue)
 2850 {
 2851     struct event *dequeued;
 2852 
 2853     if (queue->first == NULL) {
 2854         return NULL;
 2855     }
 2856     dequeued = queue->first;
 2857     ev_remove(queue, dequeued);
 2858 
 2859     return dequeued;
 2860 }
 2861 
 2862 /************************************************************
 2863 
 2864   Function: ev_remove
 2865 
 2866 *************************************************************/
 2867 void ev_remove(struct event_queue *queue, struct event *event)
 2868 {
 2869     if (queue->first == event) {
 2870         queue->first = event->ev_next;
 2871     }
 2872     if (queue->last == event) {
 2873         queue->last = event->ev_prev;
 2874     }
 2875     if (event->ev_prev) {
 2876         event->ev_prev->ev_next = event->ev_next;
 2877     }
 2878     if (event->ev_next) {
 2879         event->ev_next->ev_prev = event->ev_prev;
 2880     }
 2881     event->ev_prev = NULL;
 2882     event->ev_next = NULL;
 2883 }
 2884 
 2885 /************************************************************
 2886 
 2887   Function: usage
 2888 
 2889 *************************************************************
 2890 
 2891   Inputs:  int: 0 if output on request, 1 if output because of wrong argument
 2892 
 2893   Description:
 2894 
 2895 ************************************************************/
 2896 
 2897 void usage(int is_error)
 2898 {
 2899     FILE* out = is_error ? stderr : stdout;
 2900     fprintf(out, "Usage: %s [options] [targets...]\n", prog);
 2901     fprintf(out, "\n");
 2902     fprintf(out, "Probing options:\n");
 2903     fprintf(out, "   -4, --ipv4         only ping IPv4 addresses\n");
 2904     fprintf(out, "   -6, --ipv6         only ping IPv6 addresses\n");
 2905     fprintf(out, "   -b, --size=BYTES   amount of ping data to send, in bytes (default: %d)\n", DEFAULT_PING_DATA_SIZE);
 2906     fprintf(out, "   -B, --backoff=N    set exponential backoff factor to N (default: 1.5)\n");
 2907     fprintf(out, "   -c, --count=N      count mode: send N pings to each target\n");
 2908     fprintf(out, "   -f, --file=FILE    read list of targets from a file ( - means stdin)\n");
 2909     fprintf(out, "   -g, --generate     generate target list (only if no -f specified)\n");
 2910     fprintf(out, "                      (give start and end IP in the target list, or a CIDR address)\n");
 2911     fprintf(out, "                      (ex. %s -g 192.168.1.0 192.168.1.255 or %s -g 192.168.1.0/24)\n", prog, prog);
 2912     fprintf(out, "   -H, --ttl=N        set the IP TTL value (Time To Live hops)\n");
 2913 #ifdef SO_BINDTODEVICE
 2914     fprintf(out, "   -I, --iface=IFACE  bind to a particular interface\n");
 2915 #endif
 2916     fprintf(out, "   -l, --loop         loop mode: send pings forever\n");
 2917     fprintf(out, "   -m, --all          use all IPs of provided hostnames (e.g. IPv4 and IPv6), use with -A\n");
 2918     fprintf(out, "   -M, --dontfrag     set the Don't Fragment flag\n");
 2919     fprintf(out, "   -O, --tos=N        set the type of service (tos) flag on the ICMP packets\n");
 2920     fprintf(out, "   -p, --period=MSEC  interval between ping packets to one target (in ms)\n");
 2921     fprintf(out, "                      (in loop and count modes, default: %.0f ms)\n", perhost_interval / 1e6);
 2922     fprintf(out, "   -r, --retry=N      number of retries (default: %d)\n", DEFAULT_RETRY);
 2923     fprintf(out, "   -R, --random       random packet data (to foil link data compression)\n");
 2924     fprintf(out, "   -S, --src=IP       set source address\n");
 2925     fprintf(out, "   -t, --timeout=MSEC individual target initial timeout (default: %.0f ms,\n", timeout / 1e6);
 2926     fprintf(out, "                      except with -l/-c/-C, where it's the -p period up to 2000 ms)\n");
 2927     fprintf(out, "\n");
 2928     fprintf(out, "Output options:\n");
 2929     fprintf(out, "   -a, --alive        show targets that are alive\n");
 2930     fprintf(out, "   -A, --addr         show targets by address\n");
 2931     fprintf(out, "   -C, --vcount=N     same as -c, report results in verbose format\n");
 2932     fprintf(out, "   -d, --rdns         show targets by name (force reverse-DNS lookup)\n");
 2933     fprintf(out, "   -D, --timestamp    print timestamp before each output line\n");
 2934     fprintf(out, "   -e, --elapsed      show elapsed time on return packets\n");
 2935     fprintf(out, "   -i, --interval=MSEC  interval between sending ping packets (default: %.0f ms)\n", interval / 1e6);
 2936     fprintf(out, "   -n, --name         show targets by name (reverse-DNS lookup for target IPs)\n");
 2937     fprintf(out, "   -N, --netdata      output compatible for netdata (-l -Q are required)\n");
 2938     fprintf(out, "   -o, --outage       show the accumulated outage time (lost packets * packet interval)\n");
 2939     fprintf(out, "   -q, --quiet        quiet (don't show per-target/per-ping results)\n");
 2940     fprintf(out, "   -Q, --squiet=SECS  same as -q, but add interval summary every SECS seconds\n");
 2941     fprintf(out, "   -s, --stats        print final stats\n");
 2942     fprintf(out, "   -u, --unreach      show targets that are unreachable\n");
 2943     fprintf(out, "   -v, --version      show version\n");
 2944     fprintf(out, "   -x, --reachable=N  shows if >=N hosts are reachable or not\n");
 2945     exit(is_error);
 2946 }