2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#)networkdelta.c 8.1 (Berkeley) 6/6/93
30 * $FreeBSD: src/usr.sbin/timed/timed/networkdelta.c,v 1.3.2.1 2000/07/01 01:28:10 ps Exp $
31 * $DragonFly: src/usr.sbin/timed/timed/networkdelta.c,v 1.4 2004/03/13 21:08:38 eirikn Exp $
36 static long median(float, float *, long *, long *, unsigned int);
39 * Compute a corrected date.
40 * Compute the median of the reasonable differences. First compute
41 * the median of all authorized differences, and then compute the
42 * median of all differences that are reasonably close to the first
45 * This differs from the original BSD implementation, which looked for
46 * the largest group of machines with essentially the same date.
47 * That assumed that machines with bad clocks would be uniformly
48 * distributed. Unfortunately, in real life networks, the distribution
49 * of machines is not uniform among models of machines, and the
50 * distribution of errors in clocks tends to be quite consistent
51 * for a given model. In other words, all model VI Supre Servres
52 * from GoFast Inc. tend to have about the same error.
53 * The original BSD implementation would chose the clock of the
54 * most common model, and discard all others.
56 * Therefore, get best we can do is to try to average over all
57 * of the machines in the network, while discarding "obviously"
65 long lodelta, hidelta;
73 * compute the median of the good values
78 *xp = 0; /* account for ourself */
79 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
82 && htp->delta != HOSTDOWN) {
90 * If we are the only trusted time keeper, then do not change our
91 * clock. There may be another time keeping service active.
99 fprintf(fd, "median of %d values starting at %ld is about ",
101 med = median(med, &eps, &x[0], xp+1, VALID_RANGE);
104 * compute the median of all values near the good median
106 hidelta = med + GOOD_RANGE;
107 lodelta = med - GOOD_RANGE;
108 higood = med + VGOOD_RANGE;
109 logood = med - VGOOD_RANGE;
113 if (htp->noanswer == 0
114 && htp->delta >= lodelta
115 && htp->delta <= hidelta
117 || (htp->delta >= logood
118 && htp->delta <= higood))) {
121 } while (&self != (htp = htp->l_fwd));
125 fprintf(fd, "nothing close to median %ld\n", med);
131 fprintf(fd, "only value near median is %ld\n", x[0]);
136 fprintf(fd, "median of %td values starting at %ld is ",
138 return median(med, &eps, &x[0], xp, 1);
143 * compute the median of an array of signed integers, using the idea
144 * in <<Numerical Recipes>>.
147 median(float a, /* initial guess for the median */
148 float *eps_ptr, /* spacing near the median */
149 long *x, long *xlim, /* the data */
150 unsigned int gnuf) /* good enough estimate */
153 float ap = LONG_MAX; /* bounds on the median */
154 float am = -LONG_MAX;
156 int npts; /* # of points above & below guess */
157 float xp; /* closet point above the guess */
158 float xm; /* closet point below the guess */
160 float dum, sum, sumx;
162 #define AMP 1.5 /* smoothing constants */
172 for (pass = 1; ; pass++) { /* loop over the data */
179 for (xptr = x; xptr != xlim; xptr++) {
183 if (dum != 0.0) { /* avoid dividing by 0 */
194 dum = 1.0/(eps + dum);
200 if (ap-am < gnuf || sum == 0) {
203 "%ld in %d passes; early out balance=%d\n",
204 (long)a, pass, npts);
205 return a; /* guess was good enough */
208 aa = (sumx/sum-a)*AMP;
209 if (npts >= 2) { /* guess was too low */
211 aa = xp + max(0.0, aa);
215 } else if (npts <= -2) { /* guess was two high */
217 aa = xm + min(0.0, aa);
228 "%ld in %d passes; force out balance=%d\n",
229 (long)a, pass, npts);
232 eps = AFAC*abs(aa - a);
237 if (((x - xlim) % 2) != 0) { /* even number of points? */
238 if (npts == 0) /* yes, return an average */
245 } else if (npts != 0) { /* odd number of points */
253 fprintf(fd, "%ld in %d passes\n", (long)a, pass);