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