$OpenBSD: patch-fping_c,v 1.7 2007/07/13 08:13:22 djm Exp $
--- fping.c.orig	Thu Jul 12 12:36:46 2007
+++ fping.c	Thu Jul 12 12:36:50 2007
@@ -42,7 +42,6 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
-#define IPV6 1						/* This should be a compiler option, or even better be done from the Makefile... ;) */
 
 #ifndef _NO_PROTO
 #if !__STDC__ && !defined( __cplusplus ) && !defined( FUNCPROTO ) \
@@ -67,7 +66,7 @@ extern "C"
 
 /*** autoconf includes ***/
 
-
+#include <sys/types.h>
 #include <stdio.h>
 #include <errno.h>
 #include <time.h>
@@ -88,7 +87,6 @@ extern "C"
 #include <string.h>
 #include <stddef.h>
 
-#include <sys/types.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 
@@ -112,6 +110,10 @@ extern "C"
 #include <arpa/inet.h>
 #include <netdb.h>
 
+#if (defined(__unix__) || defined(unix)) && !defined(USG)
+#include <sys/param.h>
+#endif
+
 /* RS6000 has sys/select.h */
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
@@ -123,10 +125,16 @@ extern "C"
 
 /*** externals ***/
 
+#ifndef __OpenBSD__
 extern char *optarg;
 extern int optind,opterr;
 extern int h_errno;
+#endif
 
+#ifdef HAVE_PROGNAME
+extern char *__progname;
+#endif
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
@@ -246,13 +254,13 @@ typedef struct host_entry
      struct timeval       last_send_time;     /* time of last packet sent */
      int                  num_sent;           /* number of ping packets sent */
      int                  num_recv;           /* number of pings received */
-     int                  max_reply;          /* longest response time */
-     int                  min_reply;          /* shortest response time */
+     long                 max_reply;          /* longest response time */
+     long                 min_reply;          /* shortest response time */
      int                  total_time;         /* sum of response times */
      int                  num_sent_i;         /* number of ping packets sent */
      int                  num_recv_i;         /* number of pings received */
-     int                  max_reply_i;        /* longest response time */
-     int                  min_reply_i;        /* shortest response time */
+     long                 max_reply_i;        /* longest response time */
+     long                 min_reply_i;        /* shortest response time */
      int                  total_time_i;       /* sum of response times */
      int                  *resp_times;        /* individual response times */
 #if defined( DEBUG ) || defined( _DEBUG )
@@ -283,6 +291,12 @@ u_int ping_pkt_size;
 u_int count = 1;
 u_int trials;
 u_int report_interval = 0;
+int src_addr_present = 0;
+#ifndef IPV6
+struct in_addr src_addr;
+#else
+struct in6_addr src_addr;
+#endif
 
 /* global stats */
 long max_reply = 0;
@@ -408,6 +422,11 @@ int main( int argc, char **argv )
 	struct protoent *proto;
 	char *buf;
 	uid_t uid;
+#ifndef IPV6
+	struct sockaddr_in sa;
+#else
+	struct sockaddr_in6 sa;
+#endif
 	/* check if we are root */
 
 	if( geteuid() )
@@ -482,7 +501,11 @@ int main( int argc, char **argv )
 
 	}/* IF */
 
-	prog = argv[0];
+#ifdef HAVE_PROGNAME
+	prog = __progname;
+#else
+	prog = (prog = strrchr(argv[0], '/')) ? prog + 1 : argv[0];
+#endif
 	ident = getpid() & 0xFFFF;
 
 	verbose_flag = 1;
@@ -491,7 +514,7 @@ int main( int argc, char **argv )
 
 	/* get command line options */
 
-	while( ( c = getopt( argc, argv, "gedhlmnqusaAvz:t:i:p:f:r:c:b:C:Q:B:" ) ) != EOF )
+	while( ( c = getopt( argc, argv, "gedhlmnqusaAvz:t:i:p:f:r:c:b:C:Q:B:S:" ) ) != EOF )
 	{
 		switch( c )
 		{
@@ -502,9 +525,9 @@ int main( int argc, char **argv )
 			break;
 		
 		case 'r':
-			if( !( retry = ( u_int )atoi( optarg ) ) )
-				usage();
+			retry = ( u_int )atoi( optarg );
 
+
 			break;
 		
 		case 'i':
@@ -639,6 +662,16 @@ int main( int argc, char **argv )
 			generate_flag = 1;
 			break;
 
+		case 'S':
+#ifndef IPV6
+			if( ! inet_pton( AF_INET, optarg, &src_addr ) )
+#else
+			if( ! inet_pton( AF_INET6, optarg, &src_addr ) )
+#endif
+				usage();
+			src_addr_present = 1;
+			break;
+
 		default:
 			usage();
 			break;
@@ -808,8 +841,13 @@ int main( int argc, char **argv )
 	else if( filename )
 	{
 		FILE *ping_file;
+#ifdef MAXHOSTNAMELEN
+		char line[MAXHOSTNAMELEN];
+		char host[MAXHOSTNAMELEN];
+#else
 		char line[132];
 		char host[132];
+#endif
 		char *p;
 		
 		if( strcmp( filename, "-" ) == 0 )
@@ -823,6 +861,7 @@ int main( int argc, char **argv )
 
 		while( fgets( line, 132, ping_file ) )
 		{
+			line[132-1] = '\0';
 			if( sscanf( line, "%s", host ) != 1 )
 				continue;
 			
@@ -962,6 +1001,22 @@ int main( int argc, char **argv )
 	if( !num_hosts )
 		exit( 2 );
 
+	/* set the source address */
+
+	if( src_addr_present )
+	{
+		memset( &sa, 0, sizeof( sa ) );
+#ifndef IPV6
+		sa.sin_family = AF_INET;
+		sa.sin_addr = src_addr;
+#else
+		sa.sin6_family = AF_INET6;
+		sa.sin6_addr = src_addr;
+#endif
+		if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
+			errno_crash_and_burn( "cannot bind source address" );
+	}
+
 	/* allocate array to hold outstanding ping requests */
 
 	table = ( HOST_ENTRY** )malloc( sizeof( HOST_ENTRY* ) * num_hosts );
@@ -1503,7 +1558,6 @@ void send_ping( int s, HOST_ENTRY *h )
 	memset( buffer, 0, ping_pkt_size * sizeof( char ) );
 	icp = ( FPING_ICMPHDR* )buffer;
 
-	gettimeofday( &h->last_send_time, &tz );
 #ifndef IPV6
 	icp->icmp_type = ICMP_ECHO;
 	icp->icmp_code = 0;
@@ -1512,6 +1566,8 @@ void send_ping( int s, HOST_ENTRY *h )
 	icp->icmp_id = ident;
 
 	pdp = ( PING_DATA* )( buffer + SIZE_ICMP_HDR );
+	/* set the time at the very last possible point */
+	gettimeofday(&h->last_send_time,&tz);
 	pdp->ping_ts = h->last_send_time;
 	pdp->ping_count = h->num_sent;
 
@@ -1523,6 +1579,8 @@ void send_ping( int s, HOST_ENTRY *h )
 	icp->icmp6_id = ident;
 
 	pdp = ( PING_DATA* )( buffer + SIZE_ICMP_HDR );
+	/* set the time at the very last possible point */
+	gettimeofday(&h->last_send_time,&tz);
 	pdp->ping_ts = h->last_send_time;
 	pdp->ping_count = h->num_sent;
 
@@ -1611,6 +1669,9 @@ int wait_for_reply( void )
 
 	result = recvfrom_wto( s, buffer, sizeof(buffer), &response_addr, select_time );
 
+	/* get time of receipt as close to the real time as possible */
+	gettimeofday(&current_time,&tz);
+
 	if( result < 0 )
 		return 0;	/* timeout */
   
@@ -1625,7 +1686,7 @@ int wait_for_reply( void )
 
 	ip = ( struct ip* )buffer;
 #ifndef IPV6
-#if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ )
+#if defined( __alpha__ ) && defined(__osf1__) && __STDC__ && !defined( __GLIBC__ )
 	/* 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.
@@ -1633,7 +1694,7 @@ int wait_for_reply( void )
 	hlen = ( ip->ip_vhl & 0x0F ) << 2;
 #else
 	hlen = ip->ip_hl << 2;
-#endif /* defined(__alpha__) && __STDC__ */
+#endif /* defined(__alpha__) && defined(__osf1__) && __STDC__ */
 	if( result < hlen + ICMP_MINLEN )
 #else
 	if( result < sizeof(FPING_ICMPHDR) )
@@ -1690,7 +1751,6 @@ int wait_for_reply( void )
 	h = table[n];
 
 	/* received ping is cool, so process it */
-	gettimeofday( &current_time, &tz );
 	h->waiting = 0;
 	h->timeout = timeout;
 	h->num_recv++;
@@ -2570,7 +2630,7 @@ char * sprint_tm( int t )
 	/* <= 0.99 ms */
 	if( t < 100 )
 	{
-		sprintf( buf, "0.%02d", t );
+		snprintf( buf, sizeof(buf), "0.%02d", t );
 		return( buf );
 
 	}/* IF */
@@ -2578,7 +2638,7 @@ char * sprint_tm( int t )
 	/* 1.00 - 9.99 ms */
 	if( t < 1000 )
 	{
-		sprintf( buf, "%d.%02d", t / 100, t % 100 );
+		snprintf( buf, sizeof(buf), "%d.%02d", t / 100, t % 100 );
 		return( buf );
 
 	}/* IF */
@@ -2586,13 +2646,13 @@ char * sprint_tm( int t )
 	/* 10.0 - 99.9 ms */
 	if( t < 10000 )
 	{
-		sprintf( buf, "%d.%d", t / 100, ( t % 100 ) / 10 );
+		snprintf( buf, sizeof(buf), "%d.%d", t / 100, ( t % 100 ) / 10 );
 		return( buf );
 	
 	}/* IF */
   
 	/* >= 100 ms */
-	sprintf( buf, "%d", t / 100 );
+	snprintf( buf, sizeof(buf), "%d", t / 100 );
 	return( buf );
 
 } /* sprint_tm() */
@@ -2732,6 +2792,7 @@ void usage( void )
 	fprintf( stderr, "   -Q n       same as -q, but show summary every n seconds\n" );
 	fprintf( stderr, "   -r n       number of retries (default %d)\n", retry );
 	fprintf( stderr, "   -s         print final stats\n" );
+	fprintf( stderr, "   -S addr    set source address\n" );
 	fprintf( stderr, "   -t n       individual target initial timeout (in millisec) (default %d)\n", timeout / 100 );
 	fprintf( stderr, "   -u         show targets that are unreachable\n" );
 	fprintf( stderr, "   -v         show version\n" );
