Home | History | Annotate | Line # | Download | only in timed
      1 /*	$NetBSD: slave.c,v 1.19 2018/01/16 07:57:58 maya 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[] = "@(#)slave.c	8.1 (Berkeley) 6/6/93";
     36 #else
     37 __RCSID("$NetBSD: slave.c,v 1.19 2018/01/16 07:57:58 maya Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include "globals.h"
     42 #include <setjmp.h>
     43 #include "pathnames.h"
     44 
     45 extern jmp_buf jmpenv;
     46 extern int Mflag;
     47 extern int justquit;
     48 
     49 extern u_short sequence;
     50 
     51 static char master_name[MAXHOSTNAMELEN+1];
     52 static struct netinfo *old_slavenet;
     53 static int old_status;
     54 
     55 static void schgdate(struct tsp *, char *);
     56 static void setmaster(struct tsp *);
     57 static void answerdelay(void);
     58 
     59 void
     60 slave(void)
     61 {
     62 	int tries;
     63 	long electiontime, refusetime, looktime, looptime, adjusttime;
     64 	u_short seq;
     65 	long fastelection;
     66 #define FASTTOUT 3
     67 	struct in_addr cadr;
     68 	struct timeval otime;
     69 	struct sockaddr_in taddr;
     70 	char tname[MAXHOSTNAMELEN];
     71 	struct tsp *msg, to;
     72 	struct timeval ntime, wait, tmptv;
     73 	time_t tmpt;
     74 	struct tsp *answer;
     75 	char olddate[32];
     76 	char newdate[32];
     77 	struct netinfo *ntp;
     78 	struct hosttbl *htp;
     79 
     80 	memset(&cadr, 0, sizeof(cadr));	/* XXX gcc */
     81 	old_slavenet = 0;
     82 	seq = 0;
     83 	refusetime = 0;
     84 	adjusttime = 0;
     85 
     86 	(void)gettimeofday(&ntime, 0);
     87 	electiontime = ntime.tv_sec + delay2;
     88 	fastelection = ntime.tv_sec + FASTTOUT;
     89 	if (justquit)
     90 		looktime = electiontime;
     91 	else
     92 		looktime = fastelection;
     93 	looptime = fastelection;
     94 
     95 	if (slavenet)
     96 		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
     97 	if (status & MASTER) {
     98 		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
     99 			if (ntp->status == MASTER)
    100 				masterup(ntp);
    101 		}
    102 	}
    103 
    104 loop:
    105 	get_goodgroup(0);
    106 	(void)gettimeofday(&ntime, (struct timezone *)0);
    107 	if (ntime.tv_sec > electiontime) {
    108 		if (trace)
    109 			fprintf(fd, "election timer expired\n");
    110 		longjmp(jmpenv, 1);
    111 	}
    112 
    113 	if (ntime.tv_sec >= looktime) {
    114 		if (trace)
    115 			fprintf(fd, "Looking for nets to master\n");
    116 
    117 		if (Mflag && nignorednets > 0) {
    118 			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
    119 				if (ntp->status == IGNORE
    120 				    || ntp->status == NOMASTER) {
    121 					lookformaster(ntp);
    122 					if (ntp->status == MASTER) {
    123 						masterup(ntp);
    124 					} else if (ntp->status == MASTER) {
    125 						ntp->status = NOMASTER;
    126 					}
    127 				}
    128 				if (ntp->status == MASTER
    129 				    && --ntp->quit_count < 0)
    130 					ntp->quit_count = 0;
    131 			}
    132 			makeslave(slavenet);	/* prune extras */
    133 			setstatus();
    134 		}
    135 		(void)gettimeofday(&ntime, 0);
    136 		looktime = ntime.tv_sec + delay2;
    137 	}
    138 	if (ntime.tv_sec >= looptime) {
    139 		if (trace)
    140 			fprintf(fd, "Looking for loops\n");
    141 		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
    142 		    if (ntp->status == MASTER) {
    143 			to.tsp_type = TSP_LOOP;
    144 			to.tsp_vers = TSPVERSION;
    145 			to.tsp_seq = sequence++;
    146 			to.tsp_hopcnt = MAX_HOPCNT;
    147 			set_tsp_name(&to, hostname);
    148 			bytenetorder(&to);
    149 			(void)sendtsp(sock, &to, &ntp->dest_addr);
    150 		    }
    151 		}
    152 		(void)gettimeofday(&ntime, 0);
    153 		looptime = ntime.tv_sec + delay2;
    154 	}
    155 
    156 	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
    157 	if (wait.tv_sec < 0)
    158 		wait.tv_sec = 0;
    159 	wait.tv_sec += FASTTOUT;
    160 	wait.tv_usec = 0;
    161 	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
    162 
    163 	if (msg != NULL) {
    164 		/*
    165 		 * filter stuff not for us
    166 		 */
    167 		switch (msg->tsp_type) {
    168 		case TSP_SETDATE:
    169 		case TSP_TRACEOFF:
    170 		case TSP_TRACEON:
    171 			/*
    172 			 * XXX check to see they are from ourself
    173 			 */
    174 			break;
    175 
    176 		case TSP_TEST:
    177 		case TSP_MSITE:
    178 			break;
    179 
    180 		case TSP_MASTERUP:
    181 			if (!fromnet) {
    182 				if (trace) {
    183 					fprintf(fd, "slave ignored: ");
    184 					print(msg, &from);
    185 				}
    186 				goto loop;
    187 			}
    188 			break;
    189 
    190 		default:
    191 			if (!fromnet
    192 			    || fromnet->status == IGNORE
    193 			    || fromnet->status == NOMASTER) {
    194 				if (trace) {
    195 					fprintf(fd, "slave ignored: ");
    196 					print(msg, &from);
    197 				}
    198 				goto loop;
    199 			}
    200 			break;
    201 		}
    202 
    203 
    204 		/*
    205 		 * now process the message
    206 		 */
    207 		switch (msg->tsp_type) {
    208 
    209 		case TSP_ADJTIME:
    210 			if (fromnet != slavenet)
    211 				break;
    212 			if (!good_host_name(msg->tsp_name)) {
    213 				syslog(LOG_NOTICE,
    214 				   "attempted time adjustment by %s",
    215 				       msg->tsp_name);
    216 				suppress(&from, msg->tsp_name, fromnet);
    217 				break;
    218 			}
    219 			/*
    220 			 * Speed up loop detection in case we have a loop.
    221 			 * Otherwise the clocks can race until the loop
    222 			 * is found.
    223 			 */
    224 			(void)gettimeofday(&otime, 0);
    225 			if (adjusttime < otime.tv_sec)
    226 				looptime -= (looptime-otime.tv_sec)/2 + 1;
    227 
    228 			setmaster(msg);
    229 			if (seq != msg->tsp_seq) {
    230 				seq = msg->tsp_seq;
    231 				synch((long)tvtomsround(msg->tsp_time));
    232 			}
    233 			(void)gettimeofday(&ntime, 0);
    234 			electiontime = ntime.tv_sec + delay2;
    235 			fastelection = ntime.tv_sec + FASTTOUT;
    236 			adjusttime = ntime.tv_sec + SAMPLEINTVL*2;
    237 			break;
    238 
    239 		case TSP_SETTIME:
    240 			if (fromnet != slavenet)
    241 				break;
    242 			if (seq == msg->tsp_seq)
    243 				break;
    244 			seq = msg->tsp_seq;
    245 
    246 			/* adjust time for residence on the queue */
    247 			(void)gettimeofday(&otime, 0);
    248 			adj_msg_time(msg,&otime);
    249 
    250 			/*
    251 			 * the following line is necessary due to syslog
    252 			 * calling ctime() which clobbers the static buffer
    253 			 */
    254 			(void)strlcpy(olddate, date(), sizeof(olddate));
    255 			tmpt = msg->tsp_time.tv_sec;
    256 			(void)strlcpy(newdate, ctime(&tmpt), sizeof(newdate));
    257 
    258 			if (!good_host_name(msg->tsp_name)) {
    259 				syslog(LOG_NOTICE,
    260 			    "attempted time setting by untrusted %s to %s",
    261 				       msg->tsp_name, newdate);
    262 				suppress(&from, msg->tsp_name, fromnet);
    263 				break;
    264 			}
    265 
    266 			setmaster(msg);
    267 			timersub(&msg->tsp_time, &otime, &ntime);
    268 			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
    269 				/*
    270 				 * do not change the clock if we can adjust it
    271 				 */
    272 				synch(tvtomsround(ntime));
    273 			} else {
    274 				update_time(&tmptv, msg);
    275 				syslog(LOG_NOTICE,
    276 				       "date changed by %s from %s",
    277 					msg->tsp_name, olddate);
    278 				if (status & MASTER)
    279 					spreadtime();
    280 			}
    281 			(void)gettimeofday(&ntime, 0);
    282 			electiontime = ntime.tv_sec + delay2;
    283 			fastelection = ntime.tv_sec + FASTTOUT;
    284 
    285 /* This patches a bad protocol bug.  Imagine a system with several networks,
    286  * where there are a pair of redundant gateways between a pair of networks,
    287  * each running timed.  Assume that we start with a third machine mastering
    288  * one of the networks, and one of the gateways mastering the other.
    289  * Imagine that the third machine goes away and the non-master gateway
    290  * decides to replace it.  If things are timed just 'right,' we will have
    291  * each gateway mastering one network for a little while.  If a SETTIME
    292  * message gets into the network at that time, perhaps from the newly
    293  * masterful gateway as it was taking control, the SETTIME will loop
    294  * forever.  Each time a gateway receives it on its slave side, it will
    295  * call spreadtime to forward it on its mastered network.  We are now in
    296  * a permanent loop, since the SETTIME msgs will keep any clock
    297  * in the network from advancing.  Normally, the 'LOOP' stuff will detect
    298  * and correct the situation.  However, with the clocks stopped, the
    299  * 'looptime' timer cannot expire.  While they are in this state, the
    300  * masters will try to saturate the network with SETTIME packets.
    301  */
    302 			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
    303 			break;
    304 
    305 		case TSP_MASTERUP:
    306 			if (slavenet && fromnet != slavenet)
    307 				break;
    308 			if (!good_host_name(msg->tsp_name)) {
    309 				suppress(&from, msg->tsp_name, fromnet);
    310 				if (electiontime > fastelection)
    311 					electiontime = fastelection;
    312 				break;
    313 			}
    314 			makeslave(fromnet);
    315 			setmaster(msg);
    316 			setstatus();
    317 			answerdelay();
    318 			xmit(TSP_SLAVEUP, 0, &from);
    319 			(void)gettimeofday(&ntime, 0);
    320 			electiontime = ntime.tv_sec + delay2;
    321 			fastelection = ntime.tv_sec + FASTTOUT;
    322 			refusetime = 0;
    323 			break;
    324 
    325 		case TSP_MASTERREQ:
    326 			if (fromnet->status != SLAVE)
    327 				break;
    328 			(void)gettimeofday(&ntime, 0);
    329 			electiontime = ntime.tv_sec + delay2;
    330 			break;
    331 
    332 		case TSP_SETDATE:
    333 			tmpt = msg->tsp_time.tv_sec;
    334 			(void)strlcpy(newdate, ctime(&tmpt), sizeof(newdate));
    335 			schgdate(msg, newdate);
    336 			break;
    337 
    338 		case TSP_SETDATEREQ:
    339 			if (fromnet->status != MASTER)
    340 				break;
    341 			tmpt = msg->tsp_time.tv_sec;
    342 			(void)strlcpy(newdate, ctime(&tmpt), sizeof(newdate));
    343 			htp = findhost(msg->tsp_name);
    344 			if (0 == htp) {
    345 				syslog(LOG_WARNING,
    346 				       "DATEREQ from uncontrolled machine");
    347 				break;
    348 			}
    349 			if (!htp->good) {
    350 				syslog(LOG_WARNING,
    351 				"attempted date change by untrusted %s to %s",
    352 				       htp->name, newdate);
    353 				spreadtime();
    354 				break;
    355 			}
    356 			schgdate(msg, newdate);
    357 			break;
    358 
    359 		case TSP_TRACEON:
    360 			traceon();
    361 			break;
    362 
    363 		case TSP_TRACEOFF:
    364 			traceoff("Tracing ended at %s\n");
    365 			break;
    366 
    367 		case TSP_SLAVEUP:
    368 			newslave(msg);
    369 			break;
    370 
    371 		case TSP_ELECTION:
    372 			if (fromnet->status == SLAVE) {
    373 				(void)gettimeofday(&ntime, 0);
    374 				electiontime = ntime.tv_sec + delay2;
    375 				fastelection = ntime.tv_sec + FASTTOUT;
    376 				seq = 0;
    377 				if (!good_host_name(msg->tsp_name)) {
    378 					syslog(LOG_NOTICE,
    379 					       "suppress election of %s",
    380 					       msg->tsp_name);
    381 					to.tsp_type = TSP_QUIT;
    382 					electiontime = fastelection;
    383 				} else if (cadr.s_addr != from.sin_addr.s_addr
    384 					   && ntime.tv_sec < refusetime) {
    385 /* if the candidate has to repeat itself, the old code would refuse it
    386  * the second time.  That would prevent elections.
    387  */
    388 					to.tsp_type = TSP_REFUSE;
    389 				} else {
    390 					cadr.s_addr = from.sin_addr.s_addr;
    391 					to.tsp_type = TSP_ACCEPT;
    392 					refusetime = ntime.tv_sec + 30;
    393 				}
    394 				taddr = from;
    395 				get_tsp_name(msg, tname, sizeof(tname));
    396 				set_tsp_name(&to, hostname);
    397 				answerdelay();
    398 				if (!acksend(&to, &taddr, tname,
    399 					     TSP_ACK, 0, 0))
    400 					syslog(LOG_WARNING,
    401 					     "no answer from candidate %s\n",
    402 					       tname);
    403 
    404 			} else {	/* fromnet->status == MASTER */
    405 				htp = addmach(msg->tsp_name, &from,fromnet);
    406 				to.tsp_type = TSP_QUIT;
    407 				set_tsp_name(&to, hostname);
    408 				if (!acksend(&to, &htp->addr, htp->name,
    409 					     TSP_ACK, 0, htp->noanswer)) {
    410 					syslog(LOG_ERR,
    411 					  "no reply from %s to ELECTION-QUIT",
    412 					       htp->name);
    413 					(void)remmach(htp);
    414 				}
    415 			}
    416 			break;
    417 
    418 		case TSP_CONFLICT:
    419 			if (fromnet->status != MASTER)
    420 				break;
    421 			/*
    422 			 * After a network partition, there can be
    423 			 * more than one master: the first slave to
    424 			 * come up will notify here the situation.
    425 			 */
    426 			set_tsp_name(&to, hostname);
    427 
    428 			/* The other master often gets into the same state,
    429 			 * with boring results.
    430 			 */
    431 			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
    432 			for (tries = 0; tries < 3; tries++) {
    433 				to.tsp_type = TSP_RESOLVE;
    434 				answer = acksend(&to, &ntp->dest_addr,
    435 						 ANYADDR, TSP_MASTERACK,
    436 						 ntp, 0);
    437 				if (answer == NULL)
    438 					break;
    439 				htp = addmach(answer->tsp_name,&from,ntp);
    440 				to.tsp_type = TSP_QUIT;
    441 				answer = acksend(&to, &htp->addr, htp->name,
    442 						 TSP_ACK, 0, htp->noanswer);
    443 				if (!answer) {
    444 					syslog(LOG_WARNING,
    445 				  "conflict error: no reply from %s to QUIT",
    446 						htp->name);
    447 					(void)remmach(htp);
    448 				}
    449 			}
    450 			masterup(ntp);
    451 			break;
    452 
    453 		case TSP_MSITE:
    454 			if (!slavenet)
    455 				break;
    456 			taddr = from;
    457 			to.tsp_type = TSP_MSITEREQ;
    458 			to.tsp_vers = TSPVERSION;
    459 			to.tsp_seq = 0;
    460 			set_tsp_name(&to, hostname);
    461 			answer = acksend(&to, &slavenet->dest_addr,
    462 					 ANYADDR, TSP_ACK,
    463 					 slavenet, 0);
    464 			if (answer != NULL
    465 			    && good_host_name(answer->tsp_name)) {
    466 				setmaster(answer);
    467 				to.tsp_type = TSP_ACK;
    468 				set_tsp_name(&to, answer->tsp_name);
    469 				bytenetorder(&to);
    470 				(void)sendtsp(sock, &to, &taddr);
    471 			}
    472 			break;
    473 
    474 		case TSP_MSITEREQ:
    475 			break;
    476 
    477 		case TSP_ACCEPT:
    478 		case TSP_REFUSE:
    479 		case TSP_RESOLVE:
    480 			break;
    481 
    482 		case TSP_QUIT:
    483 			doquit(msg);		/* become a slave */
    484 			break;
    485 
    486 		case TSP_TEST:
    487 			electiontime = 0;
    488 			break;
    489 
    490 		case TSP_LOOP:
    491 			/* looking for loops of masters */
    492 			if (!(status & MASTER))
    493 				break;
    494 			if (fromnet->status == SLAVE) {
    495 			    if (!strcmp(msg->tsp_name, hostname)) {
    496 				/*
    497 				 * Someone forwarded our message back to
    498 				 * us.  There must be a loop.  Tell the
    499 				 * master of this network to quit.
    500 				 *
    501 				 * The other master often gets into
    502 				 * the same state, with boring results.
    503 				 */
    504 				ntp = fromnet;
    505 				for (tries = 0; tries < 3; tries++) {
    506 				    to.tsp_type = TSP_RESOLVE;
    507 				    answer = acksend(&to, &ntp->dest_addr,
    508 						     ANYADDR, TSP_MASTERACK,
    509 						     ntp,0);
    510 				    if (answer == NULL)
    511 					break;
    512 				    taddr = from;
    513 				    get_tsp_name(answer, tname, sizeof(tname));
    514 				    to.tsp_type = TSP_QUIT;
    515 				    set_tsp_name(&to, hostname);
    516 				    if (!acksend(&to, &taddr, tname,
    517 						 TSP_ACK, 0, 1)) {
    518 					syslog(LOG_ERR,
    519 					"no reply from %s to slave LOOP-QUIT",
    520 						 tname);
    521 				    } else {
    522 					electiontime = 0;
    523 				    }
    524 				}
    525 				(void)gettimeofday(&ntime, 0);
    526 				looptime = ntime.tv_sec + FASTTOUT;
    527 			    } else {
    528 				if (msg->tsp_hopcnt-- < 1)
    529 				    break;
    530 				bytenetorder(msg);
    531 				for (ntp = nettab; ntp != 0; ntp = ntp->next) {
    532 				    if (ntp->status == MASTER)
    533 					    (void)sendtsp(sock, msg,
    534 						&ntp->dest_addr);
    535 				}
    536 			    }
    537 			} else {	/* fromnet->status == MASTER */
    538 			    /*
    539 			     * We should not have received this from a net
    540 			     * we are master on.  There must be two masters,
    541 			     * unless the packet was really from us.
    542 			     */
    543 			    if (from.sin_addr.s_addr
    544 				== fromnet->my_addr.s_addr) {
    545 				if (trace)
    546 				    fprintf(fd,"discarding forwarded LOOP\n");
    547 				break;
    548 			    }
    549 
    550 			    /*
    551 			     * The other master often gets into the same
    552 			     * state, with boring results.
    553 			     */
    554 			    ntp = fromnet;
    555 			    for (tries = 0; tries < 3; tries++) {
    556 				to.tsp_type = TSP_RESOLVE;
    557 				answer = acksend(&to, &ntp->dest_addr,
    558 						 ANYADDR, TSP_MASTERACK,
    559 						ntp,0);
    560 				if (!answer)
    561 					break;
    562 				htp = addmach(answer->tsp_name,
    563 					      &from,ntp);
    564 				to.tsp_type = TSP_QUIT;
    565 				set_tsp_name(&to, hostname);
    566 				if (!acksend(&to,&htp->addr,htp->name,
    567 					     TSP_ACK, 0, htp->noanswer)) {
    568 					syslog(LOG_ERR,
    569 				    "no reply from %s to master LOOP-QUIT",
    570 					       htp->name);
    571 					(void)remmach(htp);
    572 				}
    573 			    }
    574 			    (void)gettimeofday(&ntime, 0);
    575 			    looptime = ntime.tv_sec + FASTTOUT;
    576 			}
    577 			break;
    578 		default:
    579 			if (trace) {
    580 				fprintf(fd, "garbage message: ");
    581 				print(msg, &from);
    582 			}
    583 			break;
    584 		}
    585 	}
    586 	goto loop;
    587 }
    588 
    589 
    590 /*
    591  * tell the world who our master is
    592  */
    593 static void
    594 setmaster(struct tsp *msg)
    595 {
    596 	if (slavenet
    597 	    && (slavenet != old_slavenet
    598 		|| strcmp(msg->tsp_name, master_name)
    599 		|| old_status != status)) {
    600 		get_tsp_name(msg, master_name, sizeof(master_name));
    601 		old_slavenet = slavenet;
    602 		old_status = status;
    603 
    604 		if (status & MASTER) {
    605 			syslog(LOG_NOTICE, "submaster to %s", master_name);
    606 			if (trace)
    607 				fprintf(fd, "submaster to %s\n", master_name);
    608 
    609 		} else {
    610 			syslog(LOG_NOTICE, "slave to %s", master_name);
    611 			if (trace)
    612 				fprintf(fd, "slave to %s\n", master_name);
    613 		}
    614 	}
    615 }
    616 
    617 
    618 
    619 /*
    620  * handle date change request on a slave
    621  */
    622 static void
    623 schgdate(struct tsp *msg, char *newdate)
    624 {
    625 	struct tsp to;
    626 	u_short seq;
    627 	struct sockaddr_in taddr;
    628 	struct timeval otime;
    629 
    630 	if (!slavenet)
    631 		return;			/* no where to forward */
    632 
    633 	taddr = from;
    634 	seq = msg->tsp_seq;
    635 
    636 	syslog(LOG_INFO,
    637 	       "forwarding date change by %s to %s",
    638 	       msg->tsp_name, newdate);
    639 
    640 	/* adjust time for residence on the queue */
    641 	(void)gettimeofday(&otime, 0);
    642 	adj_msg_time(msg, &otime);
    643 
    644 	to.tsp_type = TSP_SETDATEREQ;
    645 	to.tsp_time = msg->tsp_time;
    646 	set_tsp_name(&to, hostname);
    647 	if (!acksend(&to, &slavenet->dest_addr,
    648 		     ANYADDR, TSP_DATEACK,
    649 		     slavenet, 0))
    650 		return;			/* no answer */
    651 
    652 	xmit(TSP_DATEACK, seq, &taddr);
    653 }
    654 
    655 
    656 /*
    657  * Used before answering a broadcast message to avoid network
    658  * contention and likely collisions.
    659  */
    660 static void
    661 answerdelay(void)
    662 {
    663 	struct timespec timeout;
    664 
    665 	timeout.tv_sec = 0;
    666 	timeout.tv_nsec = delay1 * 1000;
    667 
    668 	nanosleep(&timeout, NULL);
    669 	return;
    670 }
    671