Home | History | Annotate | Line # | Download | only in timed
      1 /*	$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1985, 1993 The Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)correct.c	8.1 (Berkeley) 6/6/93";
     36 #else
     37 __RCSID("$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 christos Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include "globals.h"
     42 #include <math.h>
     43 #include <sys/types.h>
     44 #include <sys/times.h>
     45 
     46 static void adjclock(struct timeval*);
     47 
     48 /*
     49  * sends to the slaves the corrections for their clocks after fixing our
     50  * own
     51  */
     52 void
     53 correct(long avdelta)
     54 {
     55 	struct hosttbl *htp;
     56 	long corr;
     57 	struct timeval adjlocal, tmptv;
     58 	struct tsp to;
     59 	struct tsp *answer;
     60 
     61 	mstotvround(&adjlocal, avdelta);
     62 
     63 	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
     64 		if (htp->delta != HOSTDOWN)  {
     65 			corr = avdelta - htp->delta;
     66 /* If the other machine is off in the weeds, set its time directly.
     67  *	If a slave gets the wrong day, the original code would simply
     68  *	fix the minutes.  If you fix a network partition, you can get
     69  *	into such situations.
     70  */
     71 			if (htp->need_set
     72 			    || corr >= MAXADJ*1000
     73 			    || corr <= -MAXADJ*1000) {
     74 				htp->need_set = 0;
     75 				(void)gettimeofday(&tmptv,0);
     76 				timeradd(&tmptv, &adjlocal, &tmptv);
     77 				to.tsp_time.tv_sec = tmptv.tv_sec;
     78 				to.tsp_time.tv_usec = tmptv.tv_usec;
     79 				to.tsp_type = TSP_SETTIME;
     80 			} else {
     81 				tmptv.tv_sec = to.tsp_time.tv_sec ;
     82 				tmptv.tv_usec = to.tsp_time.tv_usec ;
     83 				mstotvround(&tmptv, corr);
     84 				to.tsp_time.tv_sec = tmptv.tv_sec;
     85 				to.tsp_time.tv_usec = tmptv.tv_usec;
     86 				to.tsp_type = TSP_ADJTIME;
     87 			}
     88 			set_tsp_name(&to, hostname);
     89 			answer = acksend(&to, &htp->addr, htp->name,
     90 					 TSP_ACK, 0, 0);
     91 			if (!answer) {
     92 				htp->delta = HOSTDOWN;
     93 				syslog(LOG_WARNING,
     94 				       "no reply to time correction from %s",
     95 				       htp->name);
     96 				if (++htp->noanswer >= LOSTHOST) {
     97 					if (trace) {
     98 						fprintf(fd,
     99 					     "purging %s for not answering\n",
    100 							htp->name);
    101 						(void)fflush(fd);
    102 					}
    103 					htp = remmach(htp);
    104 				}
    105 			}
    106 		}
    107 	}
    108 
    109 	/*
    110 	 * adjust our own clock now that we are not sending it out
    111 	 */
    112 	adjclock(&adjlocal);
    113 }
    114 
    115 
    116 static void
    117 adjclock(struct timeval *corr)
    118 {
    119 	static int passes = 0;
    120 	static int smoother = 0;
    121 	long delta;			/* adjustment in usec */
    122 	long ndelta;
    123 	struct timeval now;
    124 	struct timeval adj;
    125 
    126 	if (!timerisset(corr))
    127 		return;
    128 
    129 	adj = *corr;
    130 	if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
    131 		delta = adj.tv_sec*1000000 + adj.tv_usec;
    132 		/* If the correction is less than the minimum round
    133 		 *	trip time for an ICMP packet, and thus
    134 		 *	less than the likely error in the measurement,
    135 		 *	do not do the entire correction.  Do half
    136 		 *	or a quarter of it.
    137 		 */
    138 
    139 		if (delta > -MIN_ROUND*1000
    140 		    && delta < MIN_ROUND*1000) {
    141 			if (smoother <= 4)
    142 				smoother++;
    143 			ndelta = (unsigned long)delta >> smoother;
    144 			if (delta < 0) {
    145 				long mask = (long)~0 &
    146 				    ~((1 << ((sizeof(long) * NBBY) - smoother))
    147 				    - 1);
    148 				ndelta |= mask;
    149 			}
    150 			if (trace)
    151 				fprintf(fd,
    152 					"trimming delta %ld usec to %ld\n",
    153 					delta, ndelta);
    154 			adj.tv_usec = ndelta;
    155 			adj.tv_sec = 0;
    156 		} else if (smoother > 0) {
    157 			smoother--;
    158 		}
    159 		if (0 > adjtime(corr, 0)) {
    160 			syslog(LOG_ERR, "adjtime: %m");
    161 		}
    162 		if (passes > 1
    163 		    && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
    164 			smoother = 0;
    165 			passes = 0;
    166 			syslog(LOG_WARNING,
    167 			       "large time adjustment of %+.3f sec",
    168 			       delta/1000000.0);
    169 		}
    170 	} else {
    171 		syslog(LOG_WARNING,
    172 		       "clock correction %ld sec too large to adjust",
    173 		       (long)adj.tv_sec);
    174 		(void) gettimeofday(&now, 0);
    175 		timeradd(&now, corr, &now);
    176 		if (settimeofday(&now, 0) < 0)
    177 			syslog(LOG_ERR, "settimeofday: %m");
    178 	}
    179 }
    180 
    181 
    182 /* adjust the time in a message by the time it
    183  *	spent in the queue
    184  */
    185 void
    186 adj_msg_time(struct tsp *msg, struct timeval *now)
    187 {
    188 	struct timeval diff;
    189 
    190 	timersub(now, &from_when, &diff);
    191 	timeradd(&msg->tsp_time, &diff, &msg->tsp_time);
    192 }
    193