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