From 961c9c558dc1d4881b79b41582ee3bb72b437ce4 Mon Sep 17 00:00:00 2001 From: octo Date: Sat, 29 Apr 2006 11:13:32 +0000 Subject: [PATCH] Implemented various options for the `oping' binary. --- configure.ac | 1 + src/Makefile.am | 4 + src/oping.c | 257 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 213 insertions(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index 69418878..6f74c816 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,7 @@ AC_CONFIG_SUBDIRS(libltdl src) # AC_HEADER_STDC AC_CHECK_HEADERS(unistd.h) +AC_CHECK_HEADERS(math.h) AC_CHECK_HEADERS(fcntl.h) AC_CHECK_HEADERS(sys/types.h) AC_CHECK_HEADERS(sys/stat.h) diff --git a/src/Makefile.am b/src/Makefile.am index 72f00cf8..08e84455 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,3 +18,7 @@ bin_PROGRAMS = oping oping_SOURCES = oping.c oping_LDADD = liboping.la +oping_LDFLAGS = -lm +if BUILD_WITH_LIBRT +oping_LDFLAGS += -lrt +endif diff --git a/src/oping.c b/src/oping.c index e70988f3..b18accf5 100644 --- a/src/oping.c +++ b/src/oping.c @@ -31,24 +31,183 @@ # error "You don't have the standard C99 header files installed" #endif /* STDC_HEADERS */ +#if HAVE_MATH_H +# include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + #if HAVE_NETDB_H # include /* NI_MAXHOST */ #endif #include +static double opt_interval = 1.0; +static int opt_addrfamily = PING_DEF_AF; +static int opt_count = -1; + +void usage_exit (const char *name) +{ + fprintf (stderr, "Usage: %s [-46] [-c count] [-i interval] host [host [host ...]]\n", + name); + exit (1); +} + +int read_options (int argc, char **argv) +{ + int optchar; + + while (1) + { + optchar = getopt (argc, argv, "46c:i:"); + + if (optchar == -1) + break; + + switch (optchar) + { + case '4': + case '6': + opt_addrfamily = (optchar == '4') ? AF_INET : AF_INET6; + break; + + case 'c': + { + int new_count; + new_count = atoi (optarg); + if (new_count > 0) + opt_count = new_count; + } + break; + + case 'i': + { + double new_interval; + new_interval = atof (optarg); + if (new_interval >= 0.2) + opt_interval = new_interval; + } + break; + + default: + usage_exit (argv[0]); + } + } + + return (optind); +} + +void print_host (pingobj_iter_t *iter) +{ + char host[NI_MAXHOST]; + char addr[NI_MAXHOST]; + double latency; + uint16_t sequence; + size_t buffer_len; + + buffer_len = sizeof (host); + if (ping_iterator_get_info (iter, PING_INFO_HOSTNAME, + host, &buffer_len) != 0) + { + fprintf (stderr, "ping_iterator_get_info failed.\n"); + return; + } + + buffer_len = sizeof (addr); + if (ping_iterator_get_info (iter, PING_INFO_ADDRESS, + addr, &buffer_len) != 0) + { + fprintf (stderr, "ping_iterator_get_info failed.\n"); + return; + } + + buffer_len = sizeof (latency); + ping_iterator_get_info (iter, PING_INFO_LATENCY, + &latency, &buffer_len); + + buffer_len = sizeof (sequence); + ping_iterator_get_info (iter, PING_INFO_SEQUENCE, + &sequence, &buffer_len); + + printf ("echo reply from %s (%s): icmp_seq=%u time=%.1f ms\n", + host, addr, (unsigned int) sequence, latency); +} + +void time_normalize (struct timespec *ts) +{ + while (ts->tv_nsec < 0) + { + if (ts->tv_sec == 0) + { + ts->tv_nsec = 0; + return; + } + + ts->tv_sec -= 1; + ts->tv_nsec += 1000000000; + } + + while (ts->tv_nsec >= 1000000000) + { + ts->tv_sec += 1; + ts->tv_nsec -= 1000000000; + } +} + +void time_calc (struct timespec *ts_dest, + const struct timespec *ts_int, + const struct timeval *tv_begin, + const struct timeval *tv_end) +{ + ts_dest->tv_sec = tv_begin->tv_sec + ts_int->tv_sec; + ts_dest->tv_nsec = (tv_begin->tv_usec * 1000) + ts_int->tv_nsec; + time_normalize (ts_dest); + + /* Assure that `(begin + interval) > end'. + * This may seem overly complicated, but `tv_sec' is of type `time_t' + * which may be `unsigned. *sigh* */ + if ((tv_end->tv_sec > ts_dest->tv_sec) + || ((tv_end->tv_sec == ts_dest->tv_sec) + && ((tv_end->tv_usec * 1000) > ts_dest->tv_nsec))) + { + ts_dest->tv_sec = 0; + ts_dest->tv_nsec = 0; + return; + } + + ts_dest->tv_sec = ts_dest->tv_sec - tv_end->tv_sec; + ts_dest->tv_nsec = ts_dest->tv_nsec - (tv_end->tv_usec * 1000); + time_normalize (ts_dest); +} + int main (int argc, char **argv) { pingobj_t *ping; pingobj_iter_t *iter; + struct timeval tv_begin; + struct timeval tv_end; + struct timespec ts_wait; + struct timespec ts_int; + + int optind; int i; - if (argc < 2) - { - printf ("Usage: %s [host [host [...]]]\n", argv[0]); - return (1); - } + + optind = read_options (argc, argv); + + if (optind >= argc) + usage_exit (argv[0]); if ((ping = ping_construct ()) == NULL) { @@ -56,7 +215,19 @@ int main (int argc, char **argv) return (1); } - for (i = 1; i < argc; i++) + { + double temp_sec; + double temp_nsec; + + temp_sec = modf (opt_interval, &temp_nsec); + ts_int.tv_sec = (time_t) temp_sec; + ts_int.tv_nsec = (long) (temp_nsec * 1000000000L); + } + + if (opt_addrfamily != PING_DEF_AF) + ping_setopt (ping, PING_OPT_AF, (void *) &opt_addrfamily); + + for (i = optind; i < argc; i++) { if (ping_host_add (ping, argv[i]) > 0) { @@ -67,6 +238,17 @@ int main (int argc, char **argv) while (1) { + int status; + + if (opt_count > 0) + opt_count--; + + if (gettimeofday (&tv_begin, NULL) < 0) + { + perror ("gettimeofday"); + return (1); + } + if (ping_send (ping) < 0) { fprintf (stderr, "ping_send failed\n"); @@ -77,55 +259,32 @@ int main (int argc, char **argv) iter != NULL; iter = ping_iterator_next (iter)) { - char host[NI_MAXHOST]; - char addr[NI_MAXHOST]; - double latency; - uint16_t sequence; - size_t buffer_len; - - buffer_len = sizeof (host); - if (ping_iterator_get_info (iter, PING_INFO_HOSTNAME, - host, &buffer_len) != 0) - { - fprintf (stderr, "ping_iterator_get_info failed.\n"); - continue; - } + print_host (iter); + } + fflush (stdout); - buffer_len = sizeof (addr); - if (ping_iterator_get_info (iter, PING_INFO_ADDRESS, - addr, &buffer_len) != 0) - { - fprintf (stderr, "ping_iterator_get_info failed.\n"); - continue; - } + if (opt_count == 0) + break; - buffer_len = sizeof (latency); - ping_iterator_get_info (iter, PING_INFO_LATENCY, - &latency, &buffer_len); + if (gettimeofday (&tv_end, NULL) < 0) + { + perror ("gettimeofday"); + return (1); + } - buffer_len = sizeof (sequence); - ping_iterator_get_info (iter, PING_INFO_SEQUENCE, - &sequence, &buffer_len); + time_calc (&ts_wait, &ts_int, &tv_begin, &tv_end); - printf ("echo reply from %s (%s): icmp_seq=%u time=%.1f ms\n", - host, addr, (unsigned int) sequence, latency); + while ((status = nanosleep (&ts_wait, &ts_wait)) != 0) + { + if (errno != EINTR) + { + perror ("nanosleep"); + break; + } } + } /* while (opt_count != 0) */ - sleep (1); - } + ping_destroy (ping); return (0); } - -/* - * octo@leeloo:~ $ ping verplant.org - * PING verplant.org (213.95.21.52) 56(84) bytes of data. - * 64 bytes from verplant.org (213.95.21.52): icmp_seq=1 ttl=57 time=141 ms - * 64 bytes from verplant.org (213.95.21.52): icmp_seq=2 ttl=57 time=47.0 ms - * 64 bytes from verplant.org (213.95.21.52): icmp_seq=3 ttl=57 time=112 ms - * 64 bytes from verplant.org (213.95.21.52): icmp_seq=4 ttl=57 time=46.7 ms - * - * --- verplant.org ping statistics --- - * 4 packets transmitted, 4 received, 0% packet loss, time 3002ms - * rtt min/avg/max/mdev = 46.782/86.870/141.373/41.257 ms - */ -- 2.30.2