]>
git.saurik.com Git - apple/network_cmds.git/blob - timed.tproj/timed.tproj/measure.c
6b809b2264ff22bb4cae6f4dec9e99fb41bed773
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1985, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char sccsid
[] = "@(#)measure.c 8.2 (Berkeley) 3/26/95";
62 #ident "$Revision: 1.1.1.1 $"
66 #include <netinet/in_systm.h>
67 #include <netinet/ip.h>
68 #include <netinet/ip_icmp.h>
70 #define MSEC_DAY (SECDAY*1000)
72 #define PACKET_IN 1024
74 #define MSGS 5 /* timestamps to average */
75 #define TRIALS 10 /* max # of timestamps sent */
81 static n_short seqno
= 0;
84 * Measures the differences between machines' clocks using
85 * ICMP timestamp messages.
87 int /* status val defined in globals.h */
88 measure(maxmsec
, wmsec
, hname
, addr
, print
)
89 u_long maxmsec
; /* wait this many msec at most */
90 u_long wmsec
; /* msec to wait for an answer */
92 struct sockaddr_in
*addr
;
93 int print
; /* print complaints on stderr */
100 long sendtime
, recvtime
, histime1
, histime2
;
101 long idelta
, odelta
, total
;
102 long min_idelta
, min_odelta
;
103 struct timeval tdone
, tcur
, ttrans
, twait
, tout
;
104 u_char packet
[PACKET_IN
], opacket
[64];
105 register struct icmp
*icp
= (struct icmp
*) packet
;
106 register struct icmp
*oicp
= (struct icmp
*) opacket
;
107 struct ip
*ip
= (struct ip
*) packet
;
109 min_idelta
= min_odelta
= 0x7fffffff;
110 measure_status
= HOSTDOWN
;
111 measure_delta
= HOSTDOWN
;
114 /* open raw socket used to measure time differences */
116 sock_raw
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
118 syslog(LOG_ERR
, "opening raw socket: %m");
125 * empty the icmp input queue
129 tout
.tv_sec
= tout
.tv_usec
= 0;
130 FD_SET(sock_raw
, &ready
);
131 if (select(sock_raw
+1, &ready
, 0,0, &tout
)) {
132 length
= sizeof(struct sockaddr_in
);
133 cc
= recvfrom(sock_raw
, (char *)packet
, PACKET_IN
, 0,
143 * Choose the smallest transmission time in each of the two
144 * directions. Use these two latter quantities to compute the delta
145 * between the two clocks.
148 oicp
->icmp_type
= ICMP_TSTAMP
;
150 oicp
->icmp_id
= getpid();
151 oicp
->icmp_rtime
= 0;
152 oicp
->icmp_ttime
= 0;
153 oicp
->icmp_seq
= seqno
;
158 sginap(1); /* start at a clock tick */
161 (void)gettimeofday(&tdone
, 0);
162 mstotvround(&tout
, maxmsec
);
163 timevaladd(&tdone
, &tout
); /* when we give up */
165 mstotvround(&twait
, wmsec
);
169 while (rcvcount
< MSGS
) {
170 (void)gettimeofday(&tcur
, 0);
173 * keep sending until we have sent the max
175 if (trials
< TRIALS
) {
177 oicp
->icmp_otime
= htonl((tcur
.tv_sec
% SECDAY
) * 1000
178 + tcur
.tv_usec
/ 1000);
179 oicp
->icmp_cksum
= 0;
180 oicp
->icmp_cksum
= in_cksum((u_short
*)oicp
,
183 count
= sendto(sock_raw
, opacket
, sizeof(*oicp
), 0,
184 (struct sockaddr
*)addr
,
185 sizeof(struct sockaddr
));
187 if (measure_status
== HOSTDOWN
)
188 measure_status
= UNREACHABLE
;
194 timevaladd(&ttrans
, &twait
);
199 while (rcvcount
< trials
) {
200 timevalsub(&tout
, &ttrans
, &tcur
);
204 FD_SET(sock_raw
, &ready
);
205 count
= select(sock_raw
+1, &ready
, (fd_set
*)0,
207 (void)gettimeofday(&tcur
, (struct timezone
*)0);
211 length
= sizeof(struct sockaddr_in
);
212 cc
= recvfrom(sock_raw
, (char *)packet
, PACKET_IN
, 0,
218 * got something. See if it is ours
220 icp
= (struct icmp
*)(packet
+ (ip
->ip_hl
<< 2));
222 || icp
->icmp_type
!= ICMP_TSTAMPREPLY
223 || icp
->icmp_id
!= oicp
->icmp_id
224 || icp
->icmp_seq
< seqno
225 || icp
->icmp_seq
>= oicp
->icmp_seq
)
229 sendtime
= ntohl(icp
->icmp_otime
);
230 recvtime
= ((tcur
.tv_sec
% SECDAY
) * 1000 +
231 tcur
.tv_usec
/ 1000);
233 total
= recvtime
-sendtime
;
234 if (total
< 0) /* do not hassle midnight */
238 histime1
= ntohl(icp
->icmp_rtime
);
239 histime2
= ntohl(icp
->icmp_ttime
);
241 * a host using a time format different from
242 * msec. since midnight UT (as per RFC792) should
243 * set the high order bit of the 32-bit time
244 * value it transmits.
246 if ((histime1
& 0x80000000) != 0) {
247 measure_status
= NONSTDTIME
;
250 measure_status
= GOOD
;
252 idelta
= recvtime
-histime2
;
253 odelta
= histime1
-sendtime
;
255 /* do not be confused by midnight */
256 if (idelta
< -MSEC_DAY
/2) idelta
+= MSEC_DAY
;
257 else if (idelta
> MSEC_DAY
/2) idelta
-= MSEC_DAY
;
259 if (odelta
< -MSEC_DAY
/2) odelta
+= MSEC_DAY
;
260 else if (odelta
> MSEC_DAY
/2) odelta
-= MSEC_DAY
;
262 /* save the quantization error so that we can get a
263 * measurement finer than our system clock.
265 if (total
< MIN_ROUND
) {
266 measure_delta
= (odelta
- idelta
)/2;
270 if (idelta
< min_idelta
)
272 if (odelta
< min_odelta
)
275 measure_delta
= (min_odelta
- min_idelta
)/2;
278 if (tcur
.tv_sec
> tdone
.tv_sec
279 || (tcur
.tv_sec
== tdone
.tv_sec
280 && tcur
.tv_usec
>= tdone
.tv_usec
))
285 seqno
+= TRIALS
; /* allocate our sequence numbers */
288 * If no answer is received for TRIALS consecutive times,
289 * the machine is assumed to be down
291 if (measure_status
== GOOD
) {
294 "measured delta %4d, %d trials to %-15s %s\n",
295 measure_delta
, trials
,
296 inet_ntoa(addr
->sin_addr
), hname
);
300 fprintf(stderr
, "measure %s: %s\n", hname
,
304 syslog(LOG_ERR
, "measure %s: %m", hname
);
306 syslog(LOG_ERR
, "measure: %s did not respond", hname
);
310 "measure: %s failed after %d trials\n",
316 return(measure_status
);
324 * round a number of milliseconds into a struct timeval
338 res
->tv_sec
= x
/1000;
339 res
->tv_usec
= (x
-res
->tv_sec
*1000)*1000;
340 if (res
->tv_usec
< 0) {
341 res
->tv_usec
+= 1000000;
348 struct timeval
*tv1
, *tv2
;
350 tv1
->tv_sec
+= tv2
->tv_sec
;
351 tv1
->tv_usec
+= tv2
->tv_usec
;
352 if (tv1
->tv_usec
>= 1000000) {
354 tv1
->tv_usec
-= 1000000;
356 if (tv1
->tv_usec
< 0) {
358 tv1
->tv_usec
+= 1000000;
363 timevalsub(res
, tv1
, tv2
)
364 struct timeval
*res
, *tv1
, *tv2
;
366 res
->tv_sec
= tv1
->tv_sec
- tv2
->tv_sec
;
367 res
->tv_usec
= tv1
->tv_usec
- tv2
->tv_usec
;
368 if (res
->tv_usec
>= 1000000) {
370 res
->tv_usec
-= 1000000;
372 if (res
->tv_usec
< 0) {
374 res
->tv_usec
+= 1000000;