1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)measure.c 2.7 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 #include "globals.h" 13 #include <protocols/timed.h> 14 #include <netinet/in_systm.h> 15 #include <netinet/ip.h> 16 #include <netinet/ip_icmp.h> 17 18 #define BIASP 43199999 19 #define BIASN -43200000 20 #define MODULO 86400000 21 #define PROCESSING_TIME 5 /* ms. to reduce error in measurement */ 22 23 #define PACKET_IN 1024 24 25 extern int id; 26 int measure_delta; 27 extern int sock_raw; 28 static n_short seqno = 0; 29 30 /* 31 * Measures the differences between machines' clocks using 32 * ICMP timestamp messages. 33 */ 34 35 measure(wait, addr) 36 struct timeval *wait; 37 struct sockaddr_in *addr; 38 { 39 int length; 40 int status; 41 int msgcount, trials; 42 int cc, count; 43 fd_set ready; 44 long sendtime, recvtime, histime; 45 long min1, min2, diff; 46 register long delta1, delta2; 47 struct timeval tv1, tout; 48 u_char packet[PACKET_IN], opacket[64]; 49 register struct icmp *icp = (struct icmp *) packet; 50 register struct icmp *oicp = (struct icmp *) opacket; 51 struct ip *ip = (struct ip *) packet; 52 53 min1 = min2 = 0x7fffffff; 54 status = HOSTDOWN; 55 measure_delta = HOSTDOWN; 56 57 /* empties the icmp input queue */ 58 FD_ZERO(&ready); 59 empty: 60 tout.tv_sec = tout.tv_usec = 0; 61 FD_SET(sock_raw, &ready); 62 if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 63 length = sizeof(struct sockaddr_in); 64 cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 65 (struct sockaddr_in *)NULL, &length); 66 if (cc < 0) 67 return(-1); 68 goto empty; 69 } 70 71 /* 72 * To measure the difference, select MSGS messages whose round-trip 73 * time is smaller than RANGE if ckrange is 1, otherwise simply 74 * select MSGS messages regardless of round-trip transmission time. 75 * Choose the smallest transmission time in each of the two directions. 76 * Use these two latter quantities to compute the delta between 77 * the two clocks. 78 */ 79 80 length = sizeof(struct sockaddr_in); 81 oicp->icmp_type = ICMP_TSTAMP; 82 oicp->icmp_code = 0; 83 oicp->icmp_cksum = 0; 84 oicp->icmp_id = id; 85 oicp->icmp_rtime = 0; 86 oicp->icmp_ttime = 0; 87 FD_ZERO(&ready); 88 msgcount = 0; 89 for (trials = 0; msgcount < MSGS && trials < TRIALS; ++trials) { 90 oicp->icmp_seq = ++seqno; 91 oicp->icmp_cksum = 0; 92 93 tout.tv_sec = wait->tv_sec; 94 tout.tv_usec = wait->tv_usec; 95 96 (void)gettimeofday (&tv1, (struct timezone *)0); 97 sendtime = oicp->icmp_otime = (tv1.tv_sec % (24*60*60)) * 1000 98 + tv1.tv_usec / 1000; 99 oicp->icmp_cksum = in_cksum((u_short *)oicp, sizeof(*oicp)); 100 101 count = sendto(sock_raw, (char *)opacket, sizeof(*oicp), 0, 102 addr, sizeof(struct sockaddr_in)); 103 if (count < 0) { 104 status = UNREACHABLE; 105 return(-1); 106 } 107 for (;;) { 108 FD_SET(sock_raw, &ready); 109 if ((count = select(FD_SETSIZE, &ready, (fd_set *)0, 110 (fd_set *)0, &tout)) <= 0) 111 break; 112 cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 113 (struct sockaddr_in *)NULL, &length); 114 (void)gettimeofday(&tv1, (struct timezone *)0); 115 if (cc < 0) 116 return(-1); 117 icp = (struct icmp *)(packet + (ip->ip_hl << 2)); 118 if((icp->icmp_type == ICMP_TSTAMPREPLY) && 119 icp->icmp_id == id && icp->icmp_seq == seqno) 120 break; 121 } 122 if (count <= 0) 123 continue; /* resend */ 124 recvtime = (tv1.tv_sec % (24*60*60)) * 1000 + 125 tv1.tv_usec / 1000; 126 diff = recvtime - sendtime; 127 /* 128 * diff can be less than 0 aroud midnight 129 */ 130 if (diff < 0) 131 continue; 132 msgcount++; 133 histime = ntohl((u_long)icp->icmp_rtime); 134 /* 135 * a hosts using a time format different from 136 * ms. since midnight UT (as per RFC792) should 137 * set the high order bit of the 32-bit time 138 * value it transmits. 139 */ 140 if ((histime & 0x80000000) != 0) { 141 status = NONSTDTIME; 142 break; 143 } 144 status = GOOD; 145 delta1 = histime - sendtime; 146 /* 147 * Handles wrap-around to avoid that around 148 * midnight small time differences appear 149 * enormous. However, the two machine's clocks 150 * must be within 12 hours from each other. 151 */ 152 if (delta1 < BIASN) 153 delta1 += MODULO; 154 else if (delta1 > BIASP) 155 delta1 -= MODULO; 156 delta2 = recvtime - histime; 157 if (delta2 < BIASN) 158 delta2 += MODULO; 159 else if (delta2 > BIASP) 160 delta2 -= MODULO; 161 if (delta1 < min1) 162 min1 = delta1; 163 if (delta2 < min2) 164 min2 = delta2; 165 if (diff < RANGE) { 166 min1 = delta1; 167 min2 = delta2; 168 break; 169 } 170 } 171 172 /* 173 * If no answer is received for TRIALS consecutive times, 174 * the machine is assumed to be down 175 */ 176 if (status == GOOD) { 177 measure_delta = (min1 - min2)/2 + PROCESSING_TIME; 178 } 179 return(status); 180 } 181