/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)measure.c 2.4 (Berkeley) 5/28/86"; #endif not lint #include "globals.h" #include #include #include #include #define BIASP 43199999 #define BIASN -43200000 #define MODULO 86400000 #define PROCESSING_TIME 5 /* ms. to reduce error in measurement */ #define PACKET_IN 1024 extern int id; int measure_delta; extern int sock_raw; static n_short seqno = 0; /* * Measures the differences between machines' clocks using * ICMP timestamp messages. */ measure(wait, addr) struct timeval *wait; struct sockaddr_in *addr; { int length; int status; int msgcount, trials; int cc, count; fd_set ready; long sendtime, recvtime, histime; long min1, min2, diff; register long delta1, delta2; struct timeval tv1, tout; u_char packet[PACKET_IN], opacket[64]; register struct icmp *icp = (struct icmp *) packet; register struct icmp *oicp = (struct icmp *) opacket; struct ip *ip = (struct ip *) packet; min1 = min2 = 0x7fffffff; status = HOSTDOWN; measure_delta = HOSTDOWN; /* empties the icmp input queue */ FD_ZERO(&ready); empty: tout.tv_sec = tout.tv_usec = 0; FD_SET(sock_raw, &ready); if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { length = sizeof(struct sockaddr_in); cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, (struct sockaddr_in *)NULL, &length); if (cc < 0) return(-1); goto empty; } /* * To measure the difference, select MSGS messages whose round-trip * time is smaller than RANGE if ckrange is 1, otherwise simply * select MSGS messages regardless of round-trip transmission time. * Choose the smallest transmission time in each of the two directions. * Use these two latter quantities to compute the delta between * the two clocks. */ length = sizeof(struct sockaddr_in); oicp->icmp_type = ICMP_TSTAMP; oicp->icmp_code = 0; oicp->icmp_cksum = 0; oicp->icmp_id = id; oicp->icmp_rtime = 0; oicp->icmp_ttime = 0; FD_ZERO(&ready); msgcount = 0; for (trials = 0; msgcount < MSGS && trials < TRIALS; ++trials) { oicp->icmp_seq = ++seqno; oicp->icmp_cksum = 0; tout.tv_sec = wait->tv_sec; tout.tv_usec = wait->tv_usec; (void)gettimeofday (&tv1, (struct timezone *)0); sendtime = oicp->icmp_otime = (tv1.tv_sec % (24*60*60)) * 1000 + tv1.tv_usec / 1000; oicp->icmp_cksum = in_cksum((u_short *)oicp, sizeof(*oicp)); count = sendto(sock_raw, (char *)opacket, sizeof(*oicp), 0, addr, sizeof(struct sockaddr_in)); if (count < 0) { status = UNREACHABLE; return(-1); } for (;;) { FD_SET(sock_raw, &ready); if ((count = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) <= 0) break; cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, (struct sockaddr_in *)NULL, &length); (void)gettimeofday(&tv1, (struct timezone *)0); if (cc < 0) return(-1); icp = (struct icmp *)(packet + (ip->ip_hl << 2)); if((icp->icmp_type == ICMP_TSTAMPREPLY) && icp->icmp_id == id && icp->icmp_seq == seqno) break; } if (count <= 0) continue; /* resend */ recvtime = (tv1.tv_sec % (24*60*60)) * 1000 + tv1.tv_usec / 1000; diff = recvtime - sendtime; /* * diff can be less than 0 aroud midnight */ if (diff < 0) continue; msgcount++; histime = ntohl((u_long)icp->icmp_rtime); /* * a hosts using a time format different from * ms. since midnight UT (as per RFC792) should * set the high order bit of the 32-bit time * value it transmits. */ if ((histime & 0x80000000) != 0) { status = NONSTDTIME; break; } status = GOOD; delta1 = histime - sendtime; /* * Handles wrap-around to avoid that around * midnight small time differences appear * enormous. However, the two machine's clocks * must be within 12 hours from each other. */ if (delta1 < BIASN) delta1 += MODULO; else if (delta1 > BIASP) delta1 -= MODULO; delta2 = recvtime - histime; if (delta2 < BIASN) delta2 += MODULO; else if (delta2 > BIASP) delta2 -= MODULO; if (delta1 < min1) min1 = delta1; if (delta2 < min2) min2 = delta2; if (diff < RANGE) { min1 = delta1; min2 = delta2; break; } } /* * If no answer is received for TRIALS consecutive times, * the machine is assumed to be down */ if (status == GOOD) { measure_delta = (min1 - min2)/2 + PROCESSING_TIME; } return(status); }