@ -34,17 +34,17 @@
extern " C " {
# endif /* __cplusplus */
# include "config.h"
# include "fping.h"
# include "config.h"
# include "options.h"
# include "optparse.h"
# include <inttypes.h>
# include <errno.h>
# include <inttypes.h>
# include <signal.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdint.h>
# include <stdio.h>
# include <time.h>
# include "seqmap.h"
@ -60,8 +60,6 @@ extern "C" {
# include <stddef.h>
# include <string.h>
# include <time.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/types.h>
@ -118,15 +116,16 @@ extern int h_errno;
/*** Constants ***/
# if HAVE_SO_TIMESTAMPNS
# define CLOCKID CLOCK_REALTIME
# endif
/* CLOCK_MONTONIC starts under macOS, OpenBSD and FreeBSD with undefined positive point and can not be use
* see github PR # 217
* The configure script detect the predefined operating systems an set CLOCK_REALTIME using over ONLY_CLOCK_REALTIME variable
*/
# if HAVE_SO_TIMESTAMPNS || ONLY_CLOCK_REALTIME
# define CLOCKID CLOCK_REALTIME
# endif
# if !defined(CLOCKID)
# if defined(CLOCK_MONOTONIC) && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
# if defined(CLOCK_MONOTONIC)
# define CLOCKID CLOCK_MONOTONIC
# else
# define CLOCKID CLOCK_REALTIME
@ -140,7 +139,7 @@ extern int h_errno;
# define SIZE_ICMP_HDR 8 /* from ip_icmp.h */
# define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR)
# define MAX_GENERATE 1 0000 0 /* maximum number of hosts that -g can generate */
# define MAX_GENERATE 1 3107 0 /* maximum number of hosts that -g can generate */
/* sized so as to be like traditional ping */
# define DEFAULT_PING_DATA_SIZE 56
@ -355,15 +354,19 @@ int generate_flag = 0; /* flag for IP list generation */
int verbose_flag , quiet_flag , stats_flag , unreachable_flag , alive_flag ;
int elapsed_flag , version_flag , count_flag , loop_flag , netdata_flag ;
int per_recv_flag , report_all_rtts_flag , name_flag , addr_flag , backoff_flag , rdns_flag ;
int multif_flag , timeout_flag ;
int multif_flag , timeout_flag , fast_reachable ;
int outage_flag = 0 ;
int timestamp_flag = 0 ;
int random_data_flag = 0 ;
int timestamp_format_flag = 0 ;
int nonzero_payload_flag = 0 ;
int cumulative_stats_flag = 0 ;
# if defined(DEBUG) || defined(_DEBUG)
int randomly_lose_flag , trace_flag , print_per_system_flag ;
int lose_factor ;
# endif /* DEBUG || _DEBUG */
unsigned int fwmark = 0 ;
char * filename = NULL ; /* file containing hosts to ping */
/*** forward declarations ***/
@ -379,6 +382,7 @@ void usage(int);
int wait_for_reply ( int64_t ) ;
void print_per_system_stats ( void ) ;
void print_per_system_splits ( void ) ;
void stats_reset_interval ( HOST_ENTRY * h ) ;
void print_netdata ( void ) ;
void print_global_stats ( void ) ;
void main_loop ( ) ;
@ -390,6 +394,7 @@ struct event *ev_dequeue(struct event_queue *queue);
void ev_remove ( struct event_queue * queue , struct event * event ) ;
void add_cidr ( char * ) ;
void add_range ( char * , char * ) ;
void add_addr_range_ipv4 ( unsigned long , unsigned long ) ;
void print_warning ( char * fmt , . . . ) ;
int addr_cmp ( struct sockaddr * a , struct sockaddr * b ) ;
void host_add_ping_event ( HOST_ENTRY * h , int index , int64_t ev_time ) ;
@ -397,6 +402,7 @@ void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time);
struct event * host_get_timeout_event ( HOST_ENTRY * h , int index ) ;
void stats_add ( HOST_ENTRY * h , int index , int success , int64_t latency ) ;
void update_current_time ( ) ;
void print_timestamp_format ( int64_t current_time_ns , int timestamp_format ) ;
/************************************************************
@ -450,6 +456,13 @@ int p_setsockopt(uid_t p_uid, int sockfd, int level, int optname,
int main ( int argc , char * * argv )
{
/* Debug: CPU Performance */
# if defined(DEBUG) || defined(_DEBUG)
clock_t perf_cpu_start , perf_cpu_end ;
double perf_cpu_time_used ;
perf_cpu_start = clock ( ) ;
# endif /* DEBUG || _DEBUG */
int c ;
const uid_t suid = geteuid ( ) ;
int tos = 0 ;
@ -512,6 +525,7 @@ int main(int argc, char** argv)
{ " vcount " , ' C ' , OPTPARSE_REQUIRED } ,
{ " rdns " , ' d ' , OPTPARSE_NONE } ,
{ " timestamp " , ' D ' , OPTPARSE_NONE } ,
{ " timestamp-format " , ' 0 ' , OPTPARSE_REQUIRED } ,
{ " elapsed " , ' e ' , OPTPARSE_NONE } ,
{ " file " , ' f ' , OPTPARSE_REQUIRED } ,
{ " generate " , ' g ' , OPTPARSE_NONE } ,
@ -519,6 +533,9 @@ int main(int argc, char** argv)
{ " ttl " , ' H ' , OPTPARSE_REQUIRED } ,
{ " interval " , ' i ' , OPTPARSE_REQUIRED } ,
{ " iface " , ' I ' , OPTPARSE_REQUIRED } ,
# ifdef SO_MARK
{ " fwmark " , ' k ' , OPTPARSE_REQUIRED } ,
# endif
{ " loop " , ' l ' , OPTPARSE_NONE } ,
{ " all " , ' m ' , OPTPARSE_NONE } ,
{ " dontfrag " , ' M ' , OPTPARSE_NONE } ,
@ -530,7 +547,7 @@ int main(int argc, char** argv)
{ " quiet " , ' q ' , OPTPARSE_NONE } ,
{ " squiet " , ' Q ' , OPTPARSE_REQUIRED } ,
{ " retry " , ' r ' , OPTPARSE_REQUIRED } ,
{ " rand om " , ' R ' , OPTPARSE_NONE } ,
{ " nonze ro" , ' Z ' , OPTPARSE_NONE } ,
{ " stats " , ' s ' , OPTPARSE_NONE } ,
{ " src " , ' S ' , OPTPARSE_REQUIRED } ,
{ " timeout " , ' t ' , OPTPARSE_REQUIRED } ,
@ -538,6 +555,7 @@ int main(int argc, char** argv)
{ " unreach " , ' u ' , OPTPARSE_NONE } ,
{ " version " , ' v ' , OPTPARSE_NONE } ,
{ " reachable " , ' x ' , OPTPARSE_REQUIRED } ,
{ " fast-reachable " , ' X ' , OPTPARSE_REQUIRED } ,
# if defined(DEBUG) || defined(_DEBUG)
{ NULL , ' z ' , OPTPARSE_REQUIRED } ,
# endif
@ -547,6 +565,19 @@ int main(int argc, char** argv)
float opt_value_float ;
while ( ( c = optparse_long ( & optparse_state , longopts , NULL ) ) ! = EOF ) {
switch ( c ) {
case ' 0 ' :
if ( strstr ( optparse_state . optlongname , " timestamp-format " ) ! = NULL ) {
if ( strcmp ( optparse_state . optarg , " ctime " ) = = 0 ) {
timestamp_format_flag = 1 ;
} else if ( strcmp ( optparse_state . optarg , " iso " ) = = 0 ) {
timestamp_format_flag = 2 ;
} else if ( strcmp ( optparse_state . optarg , " rfc3339 " ) = = 0 ) {
timestamp_format_flag = 3 ;
} else {
usage ( 1 ) ;
}
}
break ;
case ' 4 ' :
# ifdef IPV6
if ( hints_ai_family ! = AF_UNSPEC & & hints_ai_family ! = AF_INET ) {
@ -591,7 +622,7 @@ int main(int argc, char** argv)
break ;
case ' t ' :
if ( ! sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) )
if ( sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) ! = 1 )
usage ( 1 ) ;
if ( opt_value_float < 0 ) {
usage ( 1 ) ;
@ -601,12 +632,12 @@ int main(int argc, char** argv)
break ;
case ' r ' :
if ( ! sscanf ( optparse_state . optarg , " %u " , & retry ) )
if ( sscanf ( optparse_state . optarg , " %u " , & retry ) ! = 1 )
usage ( 1 ) ;
break ;
case ' i ' :
if ( ! sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) )
if ( sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) ! = 1 )
usage ( 1 ) ;
if ( opt_value_float < 0 ) {
usage ( 1 ) ;
@ -615,7 +646,7 @@ int main(int argc, char** argv)
break ;
case ' p ' :
if ( ! sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) )
if ( sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) ! = 1 )
usage ( 1 ) ;
if ( opt_value_float < 0 ) {
usage ( 1 ) ;
@ -640,7 +671,7 @@ int main(int argc, char** argv)
break ;
case ' b ' :
if ( ! sscanf ( optparse_state . optarg , " %u " , & ping_data_size ) )
if ( sscanf ( optparse_state . optarg , " %u " , & ping_data_size ) ! = 1 )
usage ( 1 ) ;
break ;
@ -657,13 +688,21 @@ int main(int argc, char** argv)
case ' Q ' :
verbose_flag = 0 ;
quiet_flag = 1 ;
if ( ! sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) )
if ( sscanf ( optparse_state . optarg , " %f " , & opt_value_float ) ! = 1 )
usage ( 1 ) ;
if ( opt_value_float < 0 ) {
usage ( 1 ) ;
}
report_interval = opt_value_float * 1e9 ;
/* recognize keyword(s) after number, ignore everything else */
{
char * comma = strchr ( optparse_state . optarg , ' , ' ) ;
if ( ( comma ! = NULL ) & & ( strcmp ( + + comma , " cumulative " ) = = 0 ) ) {
cumulative_stats_flag = 1 ;
}
}
break ;
case ' e ' :
@ -712,8 +751,8 @@ int main(int argc, char** argv)
timestamp_flag = 1 ;
break ;
case ' R ' :
random_data _flag = 1 ;
case ' Z ' :
nonzero_payload _flag = 1 ;
break ;
case ' l ' :
@ -752,9 +791,32 @@ int main(int argc, char** argv)
usage ( 1 ) ;
break ;
case ' X ' :
if ( ! ( min_reachable = ( unsigned int ) atoi ( optparse_state . optarg ) ) )
usage ( 1 ) ;
fast_reachable = 1 ;
break ;
case ' f ' :
filename = optparse_state . optarg ;
break ;
# ifdef SO_MARK
case ' k ' :
if ( ! ( fwmark = ( unsigned int ) atol ( optparse_state . optarg ) ) )
usage ( 1 ) ;
if ( socket4 > = 0 )
if ( - 1 = = setsockopt ( socket4 , SOL_SOCKET , SO_MARK , & fwmark , sizeof fwmark ) )
perror ( " fwmark ipv4 " ) ;
# ifdef IPV6
if ( socket6 > = 0 )
if ( - 1 = = setsockopt ( socket6 , SOL_SOCKET , SO_MARK , & fwmark , sizeof fwmark ) )
perror ( " fwmark ipv6 " ) ;
# endif
break ;
# endif
case ' g ' :
/* use IP list generation */
@ -804,7 +866,7 @@ int main(int argc, char** argv)
break ;
case ' O ' :
if ( sscanf ( optparse_state . optarg , " %i " , & tos ) ) {
if ( sscanf ( optparse_state . optarg , " %i " , & tos ) = = 1 ) {
if ( socket4 > = 0 ) {
if ( setsockopt ( socket4 , IPPROTO_IP , IP_TOS , & tos , sizeof ( tos ) ) ) {
perror ( " setting type of service octet IP_TOS " ) ;
@ -846,11 +908,13 @@ int main(int argc, char** argv)
# ifndef IPV6
if ( socket4 < 0 ) {
crash_and_burn ( " can't create socket (must run as root?) " ) ;
}
# else
if ( ( socket4 < 0 & & socket6 < 0 ) | | ( hints_ai_family = = AF_INET6 & & socket6 < 0 ) ) {
# endif
crash_and_burn ( " can't create socket (must run as root?) " ) ;
}
# endif
if ( ttl > 255 ) {
fprintf ( stderr , " %s: ttl %u out of range \n " , prog , ttl ) ;
@ -889,9 +953,6 @@ int main(int argc, char** argv)
exit ( 1 ) ;
}
if ( alive_flag | | unreachable_flag | | min_reachable )
verbose_flag = 0 ;
if ( count_flag ) {
if ( verbose_flag )
per_recv_flag = 1 ;
@ -906,6 +967,9 @@ int main(int argc, char** argv)
alive_flag = unreachable_flag = verbose_flag = 0 ;
}
if ( alive_flag | | unreachable_flag | | min_reachable )
verbose_flag = 0 ;
trials = ( count > retry + 1 ) ? count : retry + 1 ;
/* auto-tune default timeout for count/loop modes
@ -1007,13 +1071,17 @@ int main(int argc, char** argv)
int opt = 1 ;
if ( socket4 > = 0 ) {
if ( setsockopt ( socket4 , SOL_SOCKET , SO_TIMESTAMPNS , & opt , sizeof ( opt ) ) ) {
perror ( " setting SO_TIMESTAMPNS option " ) ;
if ( setsockopt ( socket4 , SOL_SOCKET , SO_TIMESTAMP , & opt , sizeof ( opt ) ) ) {
perror ( " setting SO_TIMESTAMPNS and SO_TIMESTAMP option " ) ;
}
}
}
# ifdef IPV6
if ( socket6 > = 0 ) {
if ( setsockopt ( socket6 , SOL_SOCKET , SO_TIMESTAMPNS , & opt , sizeof ( opt ) ) ) {
perror ( " setting SO_TIMESTAMPNS option (IPv6) " ) ;
if ( setsockopt ( socket6 , SOL_SOCKET , SO_TIMESTAMP , & opt , sizeof ( opt ) ) ) {
perror ( " setting SO_TIMESTAMPNS and SO_TIMESTAMP option (IPv6) " ) ;
}
}
}
# endif
@ -1106,11 +1174,11 @@ int main(int argc, char** argv)
exit ( num_noaddress ? 2 : 1 ) ;
}
if ( s rc_addr_set & & socket4 > = 0 ) {
if ( s ocket4 > = 0 & & ( src_addr_set | | socktype4 = = SOCK_DGRAM ) ) {
socket_set_src_addr_ipv4 ( socket4 , & src_addr , ( socktype4 = = SOCK_DGRAM ) ? & ident4 : NULL ) ;
}
# ifdef IPV6
if ( s rc_addr6_set & & socket6 > = 0 ) {
if ( s ocket6 > = 0 & & ( src_addr6_set | | socktype6 = = SOCK_DGRAM ) ) {
socket_set_src_addr_ipv6 ( socket6 , & src_addr6 , ( socktype6 = = SOCK_DGRAM ) ? & ident6 : NULL ) ;
}
# endif
@ -1163,6 +1231,13 @@ int main(int argc, char** argv)
/* main loop */
main_loop ( ) ;
/* Debug: CPU Performance */
# if defined(DEBUG) || defined(_DEBUG)
perf_cpu_end = clock ( ) ;
perf_cpu_time_used = ( ( double ) ( perf_cpu_end - perf_cpu_start ) ) / CLOCKS_PER_SEC ;
printf ( " [DEBUG] CPU time used: %f sec " , perf_cpu_time_used ) ;
# endif /* DEBUG || _DEBUG */
finish ( ) ;
return 0 ;
@ -1208,6 +1283,7 @@ void add_cidr(char* addr)
exit ( 1 ) ;
}
net_addr = ntohl ( ( ( struct sockaddr_in * ) addr_res - > ai_addr ) - > sin_addr . s_addr ) ;
freeaddrinfo ( addr_res ) ;
/* check mask */
if ( mask < 1 | | mask > 32 ) {
@ -1229,15 +1305,7 @@ void add_cidr(char* addr)
}
/* add all hosts in that network (net_addr and net_last inclusive) */
for ( ; net_addr < = net_last ; net_addr + + ) {
struct in_addr in_addr_tmp ;
char buffer [ 20 ] ;
in_addr_tmp . s_addr = htonl ( net_addr ) ;
inet_ntop ( AF_INET , & in_addr_tmp , buffer , sizeof ( buffer ) ) ;
add_name ( buffer ) ;
}
freeaddrinfo ( addr_res ) ;
add_addr_range_ipv4 ( net_addr , net_last ) ;
}
void add_range ( char * start , char * end )
@ -1281,7 +1349,14 @@ void add_range(char* start, char* end)
end_long = ntohl ( ( ( struct sockaddr_in * ) addr_res - > ai_addr ) - > sin_addr . s_addr ) ;
freeaddrinfo ( addr_res ) ;
if ( end_long > start_long + MAX_GENERATE ) {
/* add IPv4 addresses from closed interval [start_long,end_long] */
add_addr_range_ipv4 ( start_long , end_long ) ;
}
void add_addr_range_ipv4 ( unsigned long start_long , unsigned long end_long )
{
/* check if generator limit is exceeded */
if ( end_long > = start_long + MAX_GENERATE ) {
fprintf ( stderr , " %s: -g parameter generates too many addresses \n " , prog ) ;
exit ( 1 ) ;
}
@ -1307,9 +1382,7 @@ void main_loop()
dbg_printf ( " %s " , " # main_loop \n " ) ;
/* timeout event ? */
if ( event_queue_timeout . first & &
event_queue_timeout . first - > ev_time - current_time_ns < = 0 )
{
if ( event_queue_timeout . first & & event_queue_timeout . first - > ev_time - current_time_ns < = 0 ) {
event = ev_dequeue ( & event_queue_timeout ) ;
h = event - > host ;
@ -1319,7 +1392,7 @@ void main_loop()
if ( per_recv_flag ) {
if ( timestamp_flag ) {
print f( " [%.5f] " , ( double ) current_time_ns / 1e9 ) ;
print _timestamp_format( current_time_ns , timestamp_format_flag ) ;
}
printf ( " %-*s : [%d], timed out " ,
max_hostname_len , h - > host , event - > ping_index ) ;
@ -1358,9 +1431,7 @@ void main_loop()
}
/* ping event ? */
if ( event_queue_ping . first & &
event_queue_ping . first - > ev_time - current_time_ns < = 0 )
{
if ( event_queue_ping . first & & event_queue_ping . first - > ev_time - current_time_ns < = 0 ) {
/* Make sure that we don't ping more than once every "interval" */
lt = current_time_ns - last_send_time ;
if ( lt < interval )
@ -1506,7 +1577,6 @@ void update_current_time()
current_time_ns = timespec_ns ( & current_time ) ;
}
/************************************************************
Function : finish
@ -1561,7 +1631,8 @@ void finish()
if ( ( num_hosts - num_unreachable ) > = min_reachable ) {
printf ( " Enough hosts reachable (required: %d, reachable: %d) \n " , min_reachable , num_hosts - num_unreachable ) ;
exit ( 0 ) ;
} else {
}
else {
printf ( " Not enough hosts reachable (required: %d, reachable: %d) \n " , min_reachable , num_hosts - num_unreachable ) ;
exit ( 1 ) ;
}
@ -1625,7 +1696,7 @@ void print_per_system_stats(void)
else {
fprintf ( stderr , " xmt/rcv/%%return = %d/%d/%d%% " ,
h - > num_sent , h - > num_recv ,
( ( h - > num_recv * 100 ) / h - > num_sent ) ) ;
h - > num_sent > 0 ? ( ( h - > num_recv * 100 ) / h - > num_sent ) : 0 ) ;
}
if ( h - > num_recv ) {
@ -1665,7 +1736,7 @@ void print_netdata(void)
h = table [ i ] ;
if ( ! sent_charts ) {
printf ( " CHART fping.%s_packets '' 'FPing Packets for host %s ' packets '%s' fping.packets line 110020 %.0f\n " , h - > name , h - > host , h - > host , report_interval / 1e9 ) ;
printf ( " CHART fping.%s_packets '' 'FPing Packets ' packets '%s' fping.packets line 110020 %.0f\n " , h - > name , h - > host , report_interval / 1e9 ) ;
printf ( " DIMENSION xmt sent absolute 1 1 \n " ) ;
printf ( " DIMENSION rcv received absolute 1 1 \n " ) ;
}
@ -1676,7 +1747,7 @@ void print_netdata(void)
printf ( " END \n " ) ;
if ( ! sent_charts ) {
printf ( " CHART fping.%s_quality '' 'FPing Quality for host %s ' percentage '%s' fping.quality area 110010 %.0f\n " , h - > name , h - > host , h - > host , report_interval / 1e9 ) ;
printf ( " CHART fping.%s_quality '' 'FPing Quality ' percentage '%s' fping.quality area 110010 %.0f\n " , h - > name , h - > host , report_interval / 1e9 ) ;
printf ( " DIMENSION returned '' absolute 1 1 \n " ) ;
/* printf("DIMENSION lost '' absolute 1 1\n"); */
}
@ -1693,7 +1764,7 @@ void print_netdata(void)
printf ( " END \n " ) ;
if ( ! sent_charts ) {
printf ( " CHART fping.%s_latency '' 'FPing Latency for host %s ' ms '%s' fping.latency area 110000 %.0f\n " , h - > name , h - > host , h - > host , report_interval / 1e9 ) ;
printf ( " CHART fping.%s_latency '' 'FPing Latency ' ms '%s' fping.latency area 110000 %.0f\n " , h - > name , h - > host , report_interval / 1e9 ) ;
printf ( " DIMENSION min minimum absolute 1 1000000 \n " ) ;
printf ( " DIMENSION max maximum absolute 1 1000000 \n " ) ;
printf ( " DIMENSION avg average absolute 1 1000000 \n " ) ;
@ -1708,7 +1779,7 @@ void print_netdata(void)
}
printf ( " END \n " ) ;
h - > num_sent_i = h - > num_recv_i = h - > max_reply_i = h - > min_reply_i = h - > total_time_i = 0 ;
stats_reset_interval ( h ) ;
}
sent_charts = 1 ;
@ -1768,7 +1839,9 @@ void print_per_system_splits(void)
}
fprintf ( stderr , " \n " ) ;
h - > num_sent_i = h - > num_recv_i = h - > max_reply_i = h - > min_reply_i = h - > total_time_i = 0 ;
if ( ! cumulative_stats_flag ) {
stats_reset_interval ( h ) ;
}
}
}
@ -1908,9 +1981,11 @@ int socket_can_read(struct timeval* timeout)
select_again :
FD_ZERO ( & readset ) ;
if ( socket4 > = 0 ) FD_SET ( socket4 , & readset ) ;
if ( socket4 > = 0 )
FD_SET ( socket4 , & readset ) ;
# ifdef IPV6
if ( socket6 > = 0 ) FD_SET ( socket6 , & readset ) ;
if ( socket6 > = 0 )
FD_SET ( socket6 , & readset ) ;
# endif
nfound = select ( socketmax + 1 , & readset , NULL , NULL , timeout ) ;
@ -1953,15 +2028,13 @@ int receive_packet(int64_t wait_time,
reply_buf ,
reply_buf_len
} ;
struct msghdr recv_msghdr = {
reply_src_addr ,
reply_src_addr_len ,
& msg_iov ,
1 ,
& msg_control ,
sizeof ( msg_control ) ,
0
} ;
struct msghdr recv_msghdr = { 0 } ;
recv_msghdr . msg_name = reply_src_addr ;
recv_msghdr . msg_namelen = reply_src_addr_len ;
recv_msghdr . msg_iov = & msg_iov ;
recv_msghdr . msg_iovlen = 1 ;
recv_msghdr . msg_control = & msg_control ;
recv_msghdr . msg_controllen = sizeof ( msg_control ) ;
# if HAVE_SO_TIMESTAMPNS
struct cmsghdr * cmsg ;
# endif
@ -1991,8 +2064,7 @@ int receive_packet(int64_t wait_time,
struct timespec reply_timestamp_ts ;
for ( cmsg = CMSG_FIRSTHDR ( & recv_msghdr ) ;
cmsg ! = NULL ;
cmsg = CMSG_NXTHDR ( & recv_msghdr , cmsg ) )
{
cmsg = CMSG_NXTHDR ( & recv_msghdr , cmsg ) ) {
if ( cmsg - > cmsg_level = = SOL_SOCKET & & cmsg - > cmsg_type = = SCM_TIMESTAMPNS ) {
memcpy ( & reply_timestamp_ts , CMSG_DATA ( cmsg ) , sizeof ( reply_timestamp_ts ) ) ;
* reply_timestamp = timespec_ns ( & reply_timestamp_ts ) ;
@ -2089,7 +2161,7 @@ int decode_icmp_ipv4(
if ( ! using_sock_dgram4 ) {
struct ip * ip = ( struct ip * ) reply_buf ;
# if defined(__alpha__) && __STDC__ && !defined(__GLIBC__)
# if defined(__alpha__) && __STDC__ && !defined(__GLIBC__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
/* The alpha headers are decidedly broken.
* Using an ANSI compiler , it provides ip_vhl instead of ip_hl and
* ip_v . So , to get ip_hl , we mask off the bottom four bits .
@ -2100,12 +2172,11 @@ int decode_icmp_ipv4(
# endif
}
if ( reply_buf_len < hlen + ICMP_MINLEN ) {
/* too short */
if ( verbose_flag ) {
char buf [ INET6_ADDRSTRLEN ] ;
getnameinfo ( response_addr , sizeof ( struct sockaddr_in ) , buf , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
getnameinfo ( response_addr , response_addr_len , buf , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
printf ( " received packet too short for ICMP (%d bytes from %s) \n " , ( int ) reply_buf_len , buf ) ;
}
return - 1 ;
@ -2138,7 +2209,7 @@ int decode_icmp_ipv4(
return - 1 ;
}
getnameinfo ( response_addr , sizeof ( struct sockaddr_in ) , addr_ascii , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
getnameinfo ( response_addr , response_addr_len , addr_ascii , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
switch ( icp - > icmp_type ) {
case ICMP_UNREACH :
@ -2197,7 +2268,7 @@ int decode_icmp_ipv6(
if ( reply_buf_len < sizeof ( struct icmp6_hdr ) ) {
if ( verbose_flag ) {
char buf [ INET6_ADDRSTRLEN ] ;
getnameinfo ( ( struct sockaddr * ) & response_addr , sizeof ( response_addr ) , buf , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
getnameinfo ( response_addr , response_addr_len , buf , INET6_ADDRSTRLEN , NULL , 0 , NI_NUMERICHOST ) ;
printf ( " received packet too short for ICMP (%d bytes from %s) \n " , ( int ) reply_buf_len , buf ) ;
}
return 0 ; /* too short */
@ -2304,7 +2375,8 @@ int wait_for_reply(int64_t wait_time)
}
update_current_time ( ) ;
if ( recv_time = = 0 ) recv_time = current_time_ns ;
if ( recv_time = = 0 )
recv_time = current_time_ns ;
/* Process ICMP packet and retrieve id/seq */
if ( response_addr . ss_family = = AF_INET ) {
@ -2408,6 +2480,9 @@ int wait_for_reply(int64_t wait_time)
/* print "is alive" */
if ( h - > num_recv = = 1 ) {
num_alive + + ;
if ( fast_reachable & & num_alive > = min_reachable )
finish_requested = 1 ;
if ( verbose_flag | | alive_flag ) {
printf ( " %s " , h - > host ) ;
@ -2430,7 +2505,7 @@ int wait_for_reply(int64_t wait_time)
/* print received ping (unless --quiet) */
if ( per_recv_flag ) {
if ( timestamp_flag ) {
print f( " [%.5f] " , ( double ) recv_time / 1e9 ) ;
print _timestamp_format( recv_time , timestamp_format_flag ) ;
}
avg = h - > total_time / h - > num_recv ;
printf ( " %-*s : [%d], %d bytes, %s ms " ,
@ -2647,9 +2722,7 @@ void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_
void crash_and_burn ( char * message )
{
if ( verbose_flag )
fprintf ( stderr , " %s: %s \n " , prog , message ) ;
exit ( 4 ) ;
}
@ -2785,7 +2858,6 @@ struct event *host_get_timeout_event(HOST_ENTRY *h, int index)
return & h - > event_storage_timeout [ index % event_storage_count ] ;
}
/************************************************************
Function : ev_enqueue
@ -2884,6 +2956,40 @@ void ev_remove(struct event_queue *queue, struct event *event)
event - > ev_next = NULL ;
}
/************************************************************
Function : print_human_readable_time from current_time_ns
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void print_timestamp_format ( int64_t current_time_ns , int timestamp_format )
{
char time_buffer [ 100 ] ;
time_t current_time_s ;
struct tm * local_time ;
current_time_s = current_time_ns / 1000000000 ;
local_time = localtime ( & current_time_s ) ;
switch ( timestamp_format ) {
case 1 :
// timestamp-format ctime
strftime ( time_buffer , sizeof ( time_buffer ) , " %c " , local_time ) ;
printf ( " [%s] " , time_buffer ) ;
break ;
case 2 :
// timestamp-format iso
strftime ( time_buffer , sizeof ( time_buffer ) , " %Y-%m-%dT%T%z " , local_time ) ;
printf ( " [%s] " , time_buffer ) ;
break ;
case 3 :
// timestamp-format rfc3339
strftime ( time_buffer , sizeof ( time_buffer ) , " %Y-%m-%d %H:%M:%S " , local_time ) ;
printf ( " [%s] " , time_buffer ) ;
break ;
default :
printf ( " [%.5f] " , ( double ) current_time_ns / 1e9 ) ;
}
}
/************************************************************
Function : usage
@ -2906,14 +3012,19 @@ void usage(int is_error)
fprintf ( out , " -6, --ipv6 only ping IPv6 addresses \n " ) ;
fprintf ( out , " -b, --size=BYTES amount of ping data to send, in bytes (default: %d) \n " , DEFAULT_PING_DATA_SIZE ) ;
fprintf ( out , " -B, --backoff=N set exponential backoff factor to N (default: 1.5) \n " ) ;
fprintf ( out , " -c, --count=N count mode: send N pings to each target \n " ) ;
fprintf ( out , " -c, --count=N count mode: send N pings to each target and report stats \n " ) ;
fprintf ( out , " -f, --file=FILE read list of targets from a file ( - means stdin) \n " ) ;
fprintf ( out , " -g, --generate generate target list (only if no -f specified) \n " ) ;
fprintf ( out , " -g, --generate generate target list (only if no -f specified), \n " ) ;
fprintf ( out , " limited to at most %d targets \n " , MAX_GENERATE ) ;
fprintf ( out , " (give start and end IP in the target list, or a CIDR address) \n " ) ;
fprintf ( out , " (ex. %s -g 192.168.1.0 192.168.1.255 or %s -g 192.168.1.0/24) \n " , prog , prog ) ;
fprintf ( out , " -H, --ttl=N set the IP TTL value (Time To Live hops) \n " ) ;
fprintf ( out , " -i, --interval=MSEC interval between sending ping packets (default: %.0f ms) \n " , interval / 1e6 ) ;
# ifdef SO_BINDTODEVICE
fprintf ( out , " -I, --iface=IFACE bind to a particular interface \n " ) ;
# endif
# ifdef SO_MARK
fprintf ( out , " -k, --fwmark=FWMARK set the routing mark \n " ) ;
# endif
fprintf ( out , " -l, --loop loop mode: send pings forever \n " ) ;
fprintf ( out , " -m, --all use all IPs of provided hostnames (e.g. IPv4 and IPv6), use with -A \n " ) ;
@ -2922,7 +3033,7 @@ void usage(int is_error)
fprintf ( out , " -p, --period=MSEC interval between ping packets to one target (in ms) \n " ) ;
fprintf ( out , " (in loop and count modes, default: %.0f ms) \n " , perhost_interval / 1e6 ) ;
fprintf ( out , " -r, --retry=N number of retries (default: %d) \n " , DEFAULT_RETRY ) ;
fprintf ( out , " - R, --random random packet data (to foil link data compression )\n " ) ;
fprintf ( out , " - Z, --nonzero non-zero packet data (same payload as ping 0xA ... )\n " ) ;
fprintf ( out , " -S, --src=IP set source address \n " ) ;
fprintf ( out , " -t, --timeout=MSEC individual target initial timeout (default: %.0f ms, \n " , timeout / 1e6 ) ;
fprintf ( out , " except with -l/-c/-C, where it's the -p period up to 2000 ms) \n " ) ;
@ -2930,19 +3041,21 @@ void usage(int is_error)
fprintf ( out , " Output options: \n " ) ;
fprintf ( out , " -a, --alive show targets that are alive \n " ) ;
fprintf ( out , " -A, --addr show targets by address \n " ) ;
fprintf ( out , " -C, --vcount=N same as -c, report results in verbose format\n " ) ;
fprintf ( out , " -C, --vcount=N same as -c, report results (not stats) in verbose format\n " ) ;
fprintf ( out , " -d, --rdns show targets by name (force reverse-DNS lookup) \n " ) ;
fprintf ( out , " -D, --timestamp print timestamp before each output line \n " ) ;
fprintf ( out , " --timestamp-format=FORMAT show timestamp in the given format (-D required): ctime|iso|rfc3339 \n " ) ;
fprintf ( out , " -e, --elapsed show elapsed time on return packets \n " ) ;
fprintf ( out , " -i, --interval=MSEC interval between sending ping packets (default: %.0f ms) \n " , interval / 1e6 ) ;
fprintf ( out , " -n, --name show targets by name (reverse-DNS lookup for target IPs) \n " ) ;
fprintf ( out , " -N, --netdata output compatible for netdata (-l -Q are required) \n " ) ;
fprintf ( out , " -o, --outage show the accumulated outage time (lost packets * packet interval) \n " ) ;
fprintf ( out , " -q, --quiet quiet (don't show per-target/per-ping results) \n " ) ;
fprintf ( out , " -Q, --squiet=SECS same as -q, but add interval summary every SECS seconds \n " ) ;
fprintf ( out , " -Q, --squiet=SECS[,cumulative] same as -q, but add interval summary every SECS seconds, \n " ) ;
fprintf ( out , " with 'cumulative', print stats since beginning \n " ) ;
fprintf ( out , " -s, --stats print final stats \n " ) ;
fprintf ( out , " -u, --unreach show targets that are unreachable \n " ) ;
fprintf ( out , " -v, --version show version \n " ) ;
fprintf ( out , " -x, --reachable=N shows if >=N hosts are reachable or not \n " ) ;
fprintf ( out , " -X, --fast-reachable=N exits true immediately when N hosts are found \n " ) ;
exit ( is_error ) ;
}