BSD 4_3_Reno release
[unix-history] / usr / src / usr.sbin / timed / timed / measure.c
CommitLineData
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 21static 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
37extern int id;
38int measure_delta;
39extern int sock_raw;
e0f10bd9 40static 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 47measure(wait, addr)
42883c48 48struct timeval *wait;
75d5ce8a 49struct 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
71empty:
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}