summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Kerola <kerolasa@iki.fi>2018-10-31 22:44:33 +0000
committerSami Kerola <kerolasa@iki.fi>2018-11-11 10:47:57 +0000
commit3f896aea85996f175800f5eac0c7e7df3cfe5471 (patch)
tree187d37ca772ad4b67fb2f1f352c25a2d30be3da3
parenteba74fc13cc19e70d8392c75dbe061cfff41ac13 (diff)
downloadiputils-3f896aea85996f175800f5eac0c7e7df3cfe5471.tar.gz
traceroute6: use monotonic clock
Use clock_gettime(3) CLOCK_MONOTONIC_RAW to determine time difference. This measurement is ideal to this use case, as in traceroute6 one does not care what is the time but how long packages are traveling back and forth. Notice that CLOCK_MONOTONIC_RAW is not subject to discontinuous jumps by system administrator manually adjusting time, or incremental adjustments performed by adjtime(3) and NTP. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
-rw-r--r--traceroute6.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/traceroute6.c b/traceroute6.c
index 189afc6..9e91b68 100644
--- a/traceroute6.c
+++ b/traceroute6.c
@@ -240,6 +240,7 @@
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <time.h>
#include <unistd.h>
#if __linux__
@@ -283,7 +284,6 @@ struct run_state {
int sndsock; /* send (udp) socket file descriptor */
char *sendbuff;
int datalen;
- struct timezone tz; /* leftover */
struct sockaddr_in6 whereto; /* Who to try to reach */
struct sockaddr_in6 saddr;
struct sockaddr_in6 firsthop;
@@ -304,7 +304,7 @@ struct run_state {
struct pkt_format {
uint32_t ident;
uint32_t seq;
- struct timeval tv;
+ struct timespec ts;
};
/*
@@ -385,7 +385,7 @@ static void send_probe(struct run_state *ctl, uint32_t seq, int ttl)
pkt->ident = htonl(ctl->ident);
pkt->seq = htonl(seq);
- gettimeofday(&pkt->tv, &ctl->tz);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &pkt->ts);
i = setsockopt(ctl->sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
if (i < 0) {
@@ -406,12 +406,19 @@ static void send_probe(struct run_state *ctl, uint32_t seq, int ttl)
}
}
-static double deltaT(struct timeval *t1p, struct timeval *t2p)
+static double deltaT(struct timespec *a, struct timespec *b)
{
+ struct timespec c;
double dt;
- dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
- (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ if ((b->tv_nsec - a->tv_nsec) < 0) {
+ c.tv_sec = b->tv_sec - a->tv_sec - 1UL;
+ c.tv_nsec = b->tv_nsec - a->tv_nsec + 1000000000UL;
+ } else {
+ c.tv_sec = b->tv_sec - a->tv_sec;
+ c.tv_nsec = b->tv_nsec - a->tv_nsec;
+ }
+ dt = (double)(c.tv_sec * 1000.0L) + (double)(c.tv_nsec / 1000000.0L);
return (dt);
}
@@ -473,7 +480,7 @@ static char const *pr_type(const uint8_t t)
}
static int packet_ok(struct run_state *ctl, int cc, struct sockaddr_in6 *from,
- struct in6_addr *to, uint32_t seq, struct timeval *tv)
+ struct in6_addr *to, uint32_t seq, struct timespec *ts)
{
struct icmp6_hdr *icp = (struct icmp6_hdr *)ctl->packet;
uint8_t type, code;
@@ -501,7 +508,7 @@ static int packet_ok(struct run_state *ctl, int cc, struct sockaddr_in6 *from,
pkt = (struct pkt_format *)(up + 1);
if (ntohl(pkt->ident) == (uint32_t) ctl->ident && ntohl(pkt->seq) == seq) {
- *tv = pkt->tv;
+ *ts = pkt->ts;
return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
}
}
@@ -847,14 +854,13 @@ int main(int argc, char **argv)
for (probe = 0; probe < ctl.nprobes; ++probe) {
ssize_t cc;
uint8_t reset_timer = 1;
- struct timeval t1, t2;
- struct timezone tzone;
+ struct timespec t1, t2;
struct in6_addr to_addr;
- gettimeofday(&t1, &tzone);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &t1);
send_probe(&ctl, ++seq, ttl);
while ((cc = wait_for_reply(&ctl, &from, &to_addr, reset_timer)) != 0) {
- gettimeofday(&t2, &tzone);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &t2);
if ((i = packet_ok(&ctl, cc, &from, &to_addr, seq, &t1))) {
if (memcmp(&from.sin6_addr, &lastaddr,
sizeof(from.sin6_addr))) {
@@ -862,7 +868,7 @@ int main(int argc, char **argv)
memcpy(&lastaddr,
&from.sin6_addr, sizeof(lastaddr));
}
- printf(" %g ms", deltaT(&t1, &t2));
+ printf(" %.4f ms", deltaT(&t1, &t2));
switch (i - 1) {
case ICMP6_DST_UNREACH_NOPORT:
got_there = 1;