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