ping: use the monotonic clock to measure durations
Submitted by: Ján Sučan <sucanjan@gmail.com> MFC after: 2 weeks Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21245
This commit is contained in:
parent
65a828b471
commit
dd1a9e7f89
@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define INADDR_LEN ((int)sizeof(in_addr_t))
|
#define INADDR_LEN ((int)sizeof(in_addr_t))
|
||||||
@ -119,7 +120,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
struct tv32 {
|
struct tv32 {
|
||||||
int32_t tv32_sec;
|
int32_t tv32_sec;
|
||||||
int32_t tv32_usec;
|
int32_t tv32_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* various options */
|
/* various options */
|
||||||
@ -217,11 +218,10 @@ static char *pr_addr(struct in_addr);
|
|||||||
static char *pr_ntime(n_time);
|
static char *pr_ntime(n_time);
|
||||||
static void pr_icmph(struct icmp *);
|
static void pr_icmph(struct icmp *);
|
||||||
static void pr_iph(struct ip *);
|
static void pr_iph(struct ip *);
|
||||||
static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
|
static void pr_pack(char *, int, struct sockaddr_in *, struct timespec *);
|
||||||
static void pr_retip(struct ip *);
|
static void pr_retip(struct ip *);
|
||||||
static void status(int);
|
static void status(int);
|
||||||
static void stopit(int);
|
static void stopit(int);
|
||||||
static void tvsub(struct timeval *, const struct timeval *);
|
|
||||||
static void usage(void) __dead2;
|
static void usage(void) __dead2;
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -229,7 +229,7 @@ main(int argc, char *const *argv)
|
|||||||
{
|
{
|
||||||
struct sockaddr_in from, sock_in;
|
struct sockaddr_in from, sock_in;
|
||||||
struct in_addr ifaddr;
|
struct in_addr ifaddr;
|
||||||
struct timeval last, intvl;
|
struct timespec last, intvl;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct ip *ip;
|
struct ip *ip;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
@ -247,7 +247,7 @@ main(int argc, char *const *argv)
|
|||||||
long ltmp;
|
long ltmp;
|
||||||
int almost_done, ch, df, hold, i, icmp_len, mib[4], preload;
|
int almost_done, ch, df, hold, i, icmp_len, mib[4], preload;
|
||||||
int ssend_errno, srecv_errno, tos, ttl;
|
int ssend_errno, srecv_errno, tos, ttl;
|
||||||
char ctrl[CMSG_SPACE(sizeof(struct timeval))];
|
char ctrl[CMSG_SPACE(sizeof(struct timespec))];
|
||||||
char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
|
char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
|
||||||
#ifdef IP_OPTIONS
|
#ifdef IP_OPTIONS
|
||||||
char rspace[MAX_IPOPTLEN]; /* record route space */
|
char rspace[MAX_IPOPTLEN]; /* record route space */
|
||||||
@ -871,19 +871,19 @@ main(int argc, char *const *argv)
|
|||||||
while (preload--) /* fire off them quickies */
|
while (preload--) /* fire off them quickies */
|
||||||
pinger();
|
pinger();
|
||||||
}
|
}
|
||||||
(void)gettimeofday(&last, NULL);
|
(void)clock_gettime(CLOCK_MONOTONIC, &last);
|
||||||
|
|
||||||
if (options & F_FLOOD) {
|
if (options & F_FLOOD) {
|
||||||
intvl.tv_sec = 0;
|
intvl.tv_sec = 0;
|
||||||
intvl.tv_usec = 10000;
|
intvl.tv_nsec = 10000000;
|
||||||
} else {
|
} else {
|
||||||
intvl.tv_sec = interval / 1000;
|
intvl.tv_sec = interval / 1000;
|
||||||
intvl.tv_usec = interval % 1000 * 1000;
|
intvl.tv_nsec = interval % 1000 * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
almost_done = 0;
|
almost_done = 0;
|
||||||
while (!finish_up) {
|
while (!finish_up) {
|
||||||
struct timeval now, timeout;
|
struct timespec now, timeout;
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
int cc, n;
|
int cc, n;
|
||||||
|
|
||||||
@ -892,24 +892,16 @@ main(int argc, char *const *argv)
|
|||||||
errx(EX_OSERR, "descriptor too large");
|
errx(EX_OSERR, "descriptor too large");
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_SET(srecv, &rfds);
|
FD_SET(srecv, &rfds);
|
||||||
(void)gettimeofday(&now, NULL);
|
(void)clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
|
timespecadd(&last, &intvl, &timeout);
|
||||||
timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
|
timespecsub(&timeout, &now, &timeout);
|
||||||
while (timeout.tv_usec < 0) {
|
|
||||||
timeout.tv_usec += 1000000;
|
|
||||||
timeout.tv_sec--;
|
|
||||||
}
|
|
||||||
while (timeout.tv_usec >= 1000000) {
|
|
||||||
timeout.tv_usec -= 1000000;
|
|
||||||
timeout.tv_sec++;
|
|
||||||
}
|
|
||||||
if (timeout.tv_sec < 0)
|
if (timeout.tv_sec < 0)
|
||||||
timerclear(&timeout);
|
timespecclear(&timeout);
|
||||||
n = select(srecv + 1, &rfds, NULL, NULL, &timeout);
|
n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
continue; /* Must be EINTR. */
|
continue; /* Must be EINTR. */
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
struct timeval *tv = NULL;
|
struct timespec *tv = NULL;
|
||||||
#ifdef SO_TIMESTAMP
|
#ifdef SO_TIMESTAMP
|
||||||
struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
|
struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
|
||||||
|
|
||||||
@ -932,7 +924,7 @@ main(int argc, char *const *argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (tv == NULL) {
|
if (tv == NULL) {
|
||||||
(void)gettimeofday(&now, NULL);
|
(void)clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
tv = &now;
|
tv = &now;
|
||||||
}
|
}
|
||||||
pr_pack((char *)packet, cc, &from, tv);
|
pr_pack((char *)packet, cc, &from, tv);
|
||||||
@ -956,17 +948,17 @@ main(int argc, char *const *argv)
|
|||||||
if (almost_done)
|
if (almost_done)
|
||||||
break;
|
break;
|
||||||
almost_done = 1;
|
almost_done = 1;
|
||||||
intvl.tv_usec = 0;
|
intvl.tv_nsec = 0;
|
||||||
if (nreceived) {
|
if (nreceived) {
|
||||||
intvl.tv_sec = 2 * tmax / 1000;
|
intvl.tv_sec = 2 * tmax / 1000;
|
||||||
if (!intvl.tv_sec)
|
if (!intvl.tv_sec)
|
||||||
intvl.tv_sec = 1;
|
intvl.tv_sec = 1;
|
||||||
} else {
|
} else {
|
||||||
intvl.tv_sec = waittime / 1000;
|
intvl.tv_sec = waittime / 1000;
|
||||||
intvl.tv_usec = waittime % 1000 * 1000;
|
intvl.tv_nsec = waittime % 1000 * 1000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void)gettimeofday(&last, NULL);
|
(void)clock_gettime(CLOCK_MONOTONIC, &last);
|
||||||
if (ntransmitted - nreceived - 1 > nmissedmax) {
|
if (ntransmitted - nreceived - 1 > nmissedmax) {
|
||||||
nmissedmax = ntransmitted - nreceived - 1;
|
nmissedmax = ntransmitted - nreceived - 1;
|
||||||
if (options & F_MISSED)
|
if (options & F_MISSED)
|
||||||
@ -1003,13 +995,13 @@ stopit(int sig __unused)
|
|||||||
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
|
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
|
||||||
* will be added on by the kernel. The ID field is our UNIX process ID,
|
* will be added on by the kernel. The ID field is our UNIX process ID,
|
||||||
* and the sequence number is an ascending integer. The first TIMEVAL_LEN
|
* and the sequence number is an ascending integer. The first TIMEVAL_LEN
|
||||||
* bytes of the data portion are used to hold a UNIX "timeval" struct in
|
* bytes of the data portion are used to hold a UNIX "timespec" struct in
|
||||||
* host byte-order, to compute the round-trip time.
|
* host byte-order, to compute the round-trip time.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
pinger(void)
|
pinger(void)
|
||||||
{
|
{
|
||||||
struct timeval now;
|
struct timespec now;
|
||||||
struct tv32 tv32;
|
struct tv32 tv32;
|
||||||
struct ip *ip;
|
struct ip *ip;
|
||||||
struct icmp *icp;
|
struct icmp *icp;
|
||||||
@ -1027,13 +1019,18 @@ pinger(void)
|
|||||||
CLR(ntransmitted % mx_dup_ck);
|
CLR(ntransmitted % mx_dup_ck);
|
||||||
|
|
||||||
if ((options & F_TIME) || timing) {
|
if ((options & F_TIME) || timing) {
|
||||||
(void)gettimeofday(&now, NULL);
|
(void)clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
/*
|
||||||
tv32.tv32_sec = htonl(now.tv_sec);
|
* Truncate seconds down to 32 bits in order
|
||||||
tv32.tv32_usec = htonl(now.tv_usec);
|
* to fit the timestamp within 8 bytes of the
|
||||||
|
* packet. We're only concerned with
|
||||||
|
* durations, not absolute times.
|
||||||
|
*/
|
||||||
|
tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
|
||||||
|
tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec);
|
||||||
if (options & F_TIME)
|
if (options & F_TIME)
|
||||||
icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
|
icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
|
||||||
* 1000 + now.tv_usec / 1000);
|
* 1000 + now.tv_nsec / 1000000);
|
||||||
if (timing)
|
if (timing)
|
||||||
bcopy((void *)&tv32,
|
bcopy((void *)&tv32,
|
||||||
(void *)&outpack[ICMP_MINLEN + phdr_len],
|
(void *)&outpack[ICMP_MINLEN + phdr_len],
|
||||||
@ -1079,7 +1076,7 @@ pinger(void)
|
|||||||
* program to be run without having intermingled output (or statistics!).
|
* program to be run without having intermingled output (or statistics!).
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
|
pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv)
|
||||||
{
|
{
|
||||||
struct in_addr ina;
|
struct in_addr ina;
|
||||||
u_char *cp, *dp;
|
u_char *cp, *dp;
|
||||||
@ -1112,7 +1109,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
|
|||||||
++nreceived;
|
++nreceived;
|
||||||
triptime = 0.0;
|
triptime = 0.0;
|
||||||
if (timing) {
|
if (timing) {
|
||||||
struct timeval tv1;
|
struct timespec tv1;
|
||||||
struct tv32 tv32;
|
struct tv32 tv32;
|
||||||
#ifndef icmp_data
|
#ifndef icmp_data
|
||||||
tp = &icp->icmp_ip;
|
tp = &icp->icmp_ip;
|
||||||
@ -1126,10 +1123,10 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
|
|||||||
/* Copy to avoid alignment problems: */
|
/* Copy to avoid alignment problems: */
|
||||||
memcpy(&tv32, tp, sizeof(tv32));
|
memcpy(&tv32, tp, sizeof(tv32));
|
||||||
tv1.tv_sec = ntohl(tv32.tv32_sec);
|
tv1.tv_sec = ntohl(tv32.tv32_sec);
|
||||||
tv1.tv_usec = ntohl(tv32.tv32_usec);
|
tv1.tv_nsec = ntohl(tv32.tv32_nsec);
|
||||||
tvsub(tv, &tv1);
|
timespecsub(tv, &tv1, tv);
|
||||||
triptime = ((double)tv->tv_sec) * 1000.0 +
|
triptime = ((double)tv->tv_sec) * 1000.0 +
|
||||||
((double)tv->tv_usec) / 1000.0;
|
((double)tv->tv_nsec) / 1000000.0;
|
||||||
tsum += triptime;
|
tsum += triptime;
|
||||||
tsumsq += triptime * triptime;
|
tsumsq += triptime * triptime;
|
||||||
if (triptime < tmin)
|
if (triptime < tmin)
|
||||||
@ -1383,22 +1380,6 @@ in_cksum(u_short *addr, int len)
|
|||||||
return(answer);
|
return(answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* tvsub --
|
|
||||||
* Subtract 2 timeval structs: out = out - in. Out is assumed to
|
|
||||||
* be >= in.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
tvsub(struct timeval *out, const struct timeval *in)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ((out->tv_usec -= in->tv_usec) < 0) {
|
|
||||||
--out->tv_sec;
|
|
||||||
out->tv_usec += 1000000;
|
|
||||||
}
|
|
||||||
out->tv_sec -= in->tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* status --
|
* status --
|
||||||
* Print out statistics when SIGINFO is received.
|
* Print out statistics when SIGINFO is received.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user