11553Srgrimes/*-
21553Srgrimes * Copyright (c) 1985, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
301553Srgrimes#ifndef lint
3130642Scharnier#if 0
321553Srgrimesstatic char sccsid[] = "@(#)slave.c	8.1 (Berkeley) 6/6/93";
3330642Scharnier#endif
3430642Scharnierstatic const char rcsid[] =
3550479Speter  "$FreeBSD: stable/11/usr.sbin/timed/timed/slave.c 331722 2018-03-29 02:50:57Z eadler $";
361553Srgrimes#endif /* not lint */
371553Srgrimes
381553Srgrimes#include "globals.h"
391553Srgrimes#include <setjmp.h>
40202204Sed#include <utmpx.h>
411553Srgrimes#include "pathnames.h"
421553Srgrimes
431553Srgrimesextern jmp_buf jmpenv;
441553Srgrimesextern int Mflag;
451553Srgrimesextern int justquit;
461553Srgrimes
471553Srgrimesextern u_short sequence;
481553Srgrimes
4930872Scharnierstatic char master_name[MAXHOSTNAMELEN];
501553Srgrimesstatic struct netinfo *old_slavenet;
511553Srgrimesstatic int old_status;
521553Srgrimes
53173412Skevlostatic void schgdate(struct tsp *, char *);
54173412Skevlostatic void setmaster(struct tsp *);
55173412Skevlostatic void answerdelay(void);
561553Srgrimes
57331090Seadlervoid
58246209Scharnierslave(void)
591553Srgrimes{
601553Srgrimes	int tries;
611553Srgrimes	long electiontime, refusetime, looktime, looptime, adjtime;
621553Srgrimes	u_short seq;
631553Srgrimes	long fastelection;
641553Srgrimes#define FASTTOUT 3
651553Srgrimes	struct in_addr cadr;
661553Srgrimes	struct timeval otime;
671553Srgrimes	struct sockaddr_in taddr;
681553Srgrimes	char tname[MAXHOSTNAMELEN];
691553Srgrimes	struct tsp *msg, to;
7086644Sjhb	struct timeval ntime, wait, tmptv;
7137267Sbde	time_t tsp_time_sec;
721553Srgrimes	struct tsp *answer;
731553Srgrimes	int timeout();
741553Srgrimes	char olddate[32];
751553Srgrimes	char newdate[32];
761553Srgrimes	struct netinfo *ntp;
771553Srgrimes	struct hosttbl *htp;
78202204Sed	struct utmpx utx;
791553Srgrimes
801553Srgrimes
81299707Spfg	old_slavenet = NULL;
821553Srgrimes	seq = 0;
831553Srgrimes	refusetime = 0;
841553Srgrimes	adjtime = 0;
851553Srgrimes
86239991Sed	(void)gettimeofday(&ntime, NULL);
871553Srgrimes	electiontime = ntime.tv_sec + delay2;
881553Srgrimes	fastelection = ntime.tv_sec + FASTTOUT;
891553Srgrimes	if (justquit)
901553Srgrimes		looktime = electiontime;
911553Srgrimes	else
921553Srgrimes		looktime = fastelection;
931553Srgrimes	looptime = fastelection;
941553Srgrimes
951553Srgrimes	if (slavenet)
961553Srgrimes		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
971553Srgrimes	if (status & MASTER) {
981553Srgrimes		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
991553Srgrimes			if (ntp->status == MASTER)
1001553Srgrimes				masterup(ntp);
1011553Srgrimes		}
1021553Srgrimes	}
1031553Srgrimes
1041553Srgrimesloop:
1051553Srgrimes	get_goodgroup(0);
106239991Sed	(void)gettimeofday(&ntime, NULL);
1071553Srgrimes	if (ntime.tv_sec > electiontime) {
1081553Srgrimes		if (trace)
1091553Srgrimes			fprintf(fd, "election timer expired\n");
1101553Srgrimes		longjmp(jmpenv, 1);
1111553Srgrimes	}
1121553Srgrimes
1131553Srgrimes	if (ntime.tv_sec >= looktime) {
1141553Srgrimes		if (trace)
1151553Srgrimes			fprintf(fd, "Looking for nets to master\n");
1161553Srgrimes
1171553Srgrimes		if (Mflag && nignorednets > 0) {
1181553Srgrimes			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
1191553Srgrimes				if (ntp->status == IGNORE
1201553Srgrimes				    || ntp->status == NOMASTER) {
1211553Srgrimes					lookformaster(ntp);
1221553Srgrimes					if (ntp->status == MASTER) {
1231553Srgrimes						masterup(ntp);
1241553Srgrimes					} else if (ntp->status == MASTER) {
1251553Srgrimes						ntp->status = NOMASTER;
1261553Srgrimes					}
1271553Srgrimes				}
1281553Srgrimes				if (ntp->status == MASTER
1291553Srgrimes				    && --ntp->quit_count < 0)
1301553Srgrimes					ntp->quit_count = 0;
1311553Srgrimes			}
1321553Srgrimes			makeslave(slavenet);	/* prune extras */
1331553Srgrimes			setstatus();
1341553Srgrimes		}
135239991Sed		(void)gettimeofday(&ntime, NULL);
1361553Srgrimes		looktime = ntime.tv_sec + delay2;
1371553Srgrimes	}
1381553Srgrimes	if (ntime.tv_sec >= looptime) {
1391553Srgrimes		if (trace)
1401553Srgrimes			fprintf(fd, "Looking for loops\n");
1411553Srgrimes		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
1421553Srgrimes		    if (ntp->status == MASTER) {
1431553Srgrimes			to.tsp_type = TSP_LOOP;
1441553Srgrimes			to.tsp_vers = TSPVERSION;
1451553Srgrimes			to.tsp_seq = sequence++;
1461553Srgrimes			to.tsp_hopcnt = MAX_HOPCNT;
14730830Scharnier			(void)strcpy(to.tsp_name, hostname);
1481553Srgrimes			bytenetorder(&to);
1491553Srgrimes			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
1501553Srgrimes				   (struct sockaddr*)&ntp->dest_addr,
1511553Srgrimes				   sizeof(ntp->dest_addr)) < 0) {
1521553Srgrimes				trace_sendto_err(ntp->dest_addr.sin_addr);
1531553Srgrimes			}
1541553Srgrimes		    }
1551553Srgrimes		}
156239991Sed		(void)gettimeofday(&ntime, NULL);
1571553Srgrimes		looptime = ntime.tv_sec + delay2;
1581553Srgrimes	}
1591553Srgrimes
1601553Srgrimes	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
1611553Srgrimes	if (wait.tv_sec < 0)
1621553Srgrimes		wait.tv_sec = 0;
1631553Srgrimes	wait.tv_sec += FASTTOUT;
1641553Srgrimes	wait.tv_usec = 0;
1651553Srgrimes	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
1661553Srgrimes
1671553Srgrimes	if (msg != NULL) {
1681553Srgrimes		/*
1691553Srgrimes		 * filter stuff not for us
1701553Srgrimes		 */
1711553Srgrimes		switch (msg->tsp_type) {
1721553Srgrimes		case TSP_SETDATE:
1731553Srgrimes		case TSP_TRACEOFF:
1741553Srgrimes		case TSP_TRACEON:
1751553Srgrimes			/*
1761553Srgrimes			 * XXX check to see they are from ourself
1771553Srgrimes			 */
1781553Srgrimes			break;
1791553Srgrimes
1801553Srgrimes		case TSP_TEST:
1811553Srgrimes		case TSP_MSITE:
1821553Srgrimes			break;
1831553Srgrimes
1841553Srgrimes		case TSP_MASTERUP:
1851553Srgrimes			if (!fromnet) {
1861553Srgrimes				if (trace) {
1871553Srgrimes					fprintf(fd, "slave ignored: ");
1881553Srgrimes					print(msg, &from);
1891553Srgrimes				}
1901553Srgrimes				goto loop;
1911553Srgrimes			}
1921553Srgrimes			break;
1931553Srgrimes
1941553Srgrimes		default:
1951553Srgrimes			if (!fromnet
1961553Srgrimes			    || fromnet->status == IGNORE
1971553Srgrimes			    || fromnet->status == NOMASTER) {
1981553Srgrimes				if (trace) {
1991553Srgrimes					fprintf(fd, "slave ignored: ");
2001553Srgrimes					print(msg, &from);
2011553Srgrimes				}
2021553Srgrimes				goto loop;
2031553Srgrimes			}
2041553Srgrimes			break;
2051553Srgrimes		}
2061553Srgrimes
2071553Srgrimes
2081553Srgrimes		/*
2091553Srgrimes		 * now process the message
2101553Srgrimes		 */
2111553Srgrimes		switch (msg->tsp_type) {
2121553Srgrimes
2131553Srgrimes		case TSP_ADJTIME:
2141553Srgrimes			if (fromnet != slavenet)
2151553Srgrimes				break;
2161553Srgrimes			if (!good_host_name(msg->tsp_name)) {
2171553Srgrimes				syslog(LOG_NOTICE,
2181553Srgrimes				   "attempted time adjustment by %s",
2191553Srgrimes				       msg->tsp_name);
2201553Srgrimes				suppress(&from, msg->tsp_name, fromnet);
2211553Srgrimes				break;
2221553Srgrimes			}
2231553Srgrimes			/*
2241553Srgrimes			 * Speed up loop detection in case we have a loop.
2251553Srgrimes			 * Otherwise the clocks can race until the loop
2261553Srgrimes			 * is found.
2271553Srgrimes			 */
228239991Sed			(void)gettimeofday(&otime, NULL);
2291553Srgrimes			if (adjtime < otime.tv_sec)
2301553Srgrimes				looptime -= (looptime-otime.tv_sec)/2 + 1;
2311553Srgrimes
2321553Srgrimes			setmaster(msg);
2331553Srgrimes			if (seq != msg->tsp_seq) {
2341553Srgrimes				seq = msg->tsp_seq;
2351553Srgrimes				synch(tvtomsround(msg->tsp_time));
2361553Srgrimes			}
237239991Sed			(void)gettimeofday(&ntime, NULL);
2381553Srgrimes			electiontime = ntime.tv_sec + delay2;
2391553Srgrimes			fastelection = ntime.tv_sec + FASTTOUT;
2401553Srgrimes			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
2411553Srgrimes			break;
2421553Srgrimes
2431553Srgrimes		case TSP_SETTIME:
2441553Srgrimes			if (fromnet != slavenet)
2451553Srgrimes				break;
2461553Srgrimes			if (seq == msg->tsp_seq)
2471553Srgrimes				break;
2481553Srgrimes			seq = msg->tsp_seq;
2491553Srgrimes
2501553Srgrimes			/* adjust time for residence on the queue */
251239991Sed			(void)gettimeofday(&otime, NULL);
2521553Srgrimes			adj_msg_time(msg,&otime);
2531553Srgrimes			/*
2541553Srgrimes			 * the following line is necessary due to syslog
2551553Srgrimes			 * calling ctime() which clobbers the static buffer
2561553Srgrimes			 */
257299709Spfg			(void)strlcpy(olddate, date(), sizeof(olddate));
25837267Sbde			tsp_time_sec = msg->tsp_time.tv_sec;
259299709Spfg			(void)strlcpy(newdate, ctime(&tsp_time_sec),
260299709Spfg			    sizeof(newdate));
2611553Srgrimes
2621553Srgrimes			if (!good_host_name(msg->tsp_name)) {
2631553Srgrimes				syslog(LOG_NOTICE,
2641553Srgrimes			    "attempted time setting by untrusted %s to %s",
2651553Srgrimes				       msg->tsp_name, newdate);
2661553Srgrimes				suppress(&from, msg->tsp_name, fromnet);
2671553Srgrimes				break;
2681553Srgrimes			}
2691553Srgrimes
2701553Srgrimes			setmaster(msg);
27186644Sjhb 			tmptv.tv_sec = msg->tsp_time.tv_sec;
27286644Sjhb 			tmptv.tv_usec = msg->tsp_time.tv_usec;
27386644Sjhb			timevalsub(&ntime, &tmptv, &otime);
2741553Srgrimes			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
2751553Srgrimes				/*
2761553Srgrimes				 * do not change the clock if we can adjust it
2771553Srgrimes				 */
2781553Srgrimes				synch(tvtomsround(ntime));
2791553Srgrimes			} else {
280202204Sed				utx.ut_type = OLD_TIME;
281202204Sed				gettimeofday(&utx.ut_tv, NULL);
282202204Sed				pututxline(&utx);
283202204Sed				(void)settimeofday(&tmptv, 0);
284202204Sed				utx.ut_type = NEW_TIME;
285202204Sed				gettimeofday(&utx.ut_tv, NULL);
286202204Sed				pututxline(&utx);
2871553Srgrimes				syslog(LOG_NOTICE,
2881553Srgrimes				       "date changed by %s from %s",
2891553Srgrimes					msg->tsp_name, olddate);
2901553Srgrimes				if (status & MASTER)
2911553Srgrimes					spreadtime();
2921553Srgrimes			}
293239991Sed			(void)gettimeofday(&ntime, NULL);
2941553Srgrimes			electiontime = ntime.tv_sec + delay2;
2951553Srgrimes			fastelection = ntime.tv_sec + FASTTOUT;
2961553Srgrimes
2971553Srgrimes/* This patches a bad protocol bug.  Imagine a system with several networks,
2981553Srgrimes * where there are a pair of redundant gateways between a pair of networks,
2991553Srgrimes * each running timed.  Assume that we start with a third machine mastering
3001553Srgrimes * one of the networks, and one of the gateways mastering the other.
3011553Srgrimes * Imagine that the third machine goes away and the non-master gateway
3021553Srgrimes * decides to replace it.  If things are timed just 'right,' we will have
3031553Srgrimes * each gateway mastering one network for a little while.  If a SETTIME
3041553Srgrimes * message gets into the network at that time, perhaps from the newly
3051553Srgrimes * masterful gateway as it was taking control, the SETTIME will loop
3061553Srgrimes * forever.  Each time a gateway receives it on its slave side, it will
3071553Srgrimes * call spreadtime to forward it on its mastered network.  We are now in
3081553Srgrimes * a permanent loop, since the SETTIME msgs will keep any clock
3091553Srgrimes * in the network from advancing.  Normally, the 'LOOP' stuff will detect
3101553Srgrimes * and correct the situation.  However, with the clocks stopped, the
3111553Srgrimes * 'looptime' timer cannot expire.  While they are in this state, the
3121553Srgrimes * masters will try to saturate the network with SETTIME packets.
3131553Srgrimes */
3141553Srgrimes			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
3151553Srgrimes			break;
3161553Srgrimes
3171553Srgrimes		case TSP_MASTERUP:
3181553Srgrimes			if (slavenet && fromnet != slavenet)
3191553Srgrimes				break;
3201553Srgrimes			if (!good_host_name(msg->tsp_name)) {
3211553Srgrimes				suppress(&from, msg->tsp_name, fromnet);
3221553Srgrimes				if (electiontime > fastelection)
3231553Srgrimes					electiontime = fastelection;
3241553Srgrimes				break;
3251553Srgrimes			}
3261553Srgrimes			makeslave(fromnet);
3271553Srgrimes			setmaster(msg);
3281553Srgrimes			setstatus();
3291553Srgrimes			answerdelay();
3301553Srgrimes			xmit(TSP_SLAVEUP, 0, &from);
331239991Sed			(void)gettimeofday(&ntime, NULL);
3321553Srgrimes			electiontime = ntime.tv_sec + delay2;
3331553Srgrimes			fastelection = ntime.tv_sec + FASTTOUT;
3341553Srgrimes			refusetime = 0;
3351553Srgrimes			break;
3361553Srgrimes
3371553Srgrimes		case TSP_MASTERREQ:
3381553Srgrimes			if (fromnet->status != SLAVE)
3391553Srgrimes				break;
340239991Sed			(void)gettimeofday(&ntime, NULL);
3411553Srgrimes			electiontime = ntime.tv_sec + delay2;
3421553Srgrimes			break;
3431553Srgrimes
3441553Srgrimes		case TSP_SETDATE:
34537267Sbde			tsp_time_sec = msg->tsp_time.tv_sec;
346299709Spfg			(void)strlcpy(newdate, ctime(&tsp_time_sec),
347299709Spfg			    sizeof(newdate));
3481553Srgrimes			schgdate(msg, newdate);
3491553Srgrimes			break;
3501553Srgrimes
3511553Srgrimes		case TSP_SETDATEREQ:
3521553Srgrimes			if (fromnet->status != MASTER)
3531553Srgrimes				break;
35437267Sbde			tsp_time_sec = msg->tsp_time.tv_sec;
355299709Spfg			(void)strlcpy(newdate, ctime(&tsp_time_sec),
356299709Spfg			    sizeof(newdate));
3571553Srgrimes			htp = findhost(msg->tsp_name);
358299707Spfg			if (htp == NULL) {
3591553Srgrimes				syslog(LOG_WARNING,
3601553Srgrimes				       "DATEREQ from uncontrolled machine");
3611553Srgrimes				break;
3621553Srgrimes			}
3631553Srgrimes			if (!htp->good) {
3641553Srgrimes				syslog(LOG_WARNING,
3651553Srgrimes				"attempted date change by untrusted %s to %s",
3661553Srgrimes				       htp->name, newdate);
3671553Srgrimes				spreadtime();
3681553Srgrimes				break;
3691553Srgrimes			}
3701553Srgrimes			schgdate(msg, newdate);
3711553Srgrimes			break;
3721553Srgrimes
3731553Srgrimes		case TSP_TRACEON:
3741553Srgrimes			traceon();
3751553Srgrimes			break;
3761553Srgrimes
3771553Srgrimes		case TSP_TRACEOFF:
3781553Srgrimes			traceoff("Tracing ended at %s\n");
3791553Srgrimes			break;
3801553Srgrimes
3811553Srgrimes		case TSP_SLAVEUP:
3821553Srgrimes			newslave(msg);
3831553Srgrimes			break;
3841553Srgrimes
3851553Srgrimes		case TSP_ELECTION:
3861553Srgrimes			if (fromnet->status == SLAVE) {
387239991Sed				(void)gettimeofday(&ntime, NULL);
3881553Srgrimes				electiontime = ntime.tv_sec + delay2;
3891553Srgrimes				fastelection = ntime.tv_sec + FASTTOUT;
3901553Srgrimes				seq = 0;
3911553Srgrimes				if (!good_host_name(msg->tsp_name)) {
3921553Srgrimes					syslog(LOG_NOTICE,
3931553Srgrimes					       "suppress election of %s",
3941553Srgrimes					       msg->tsp_name);
3951553Srgrimes					to.tsp_type = TSP_QUIT;
3961553Srgrimes					electiontime = fastelection;
3971553Srgrimes				} else if (cadr.s_addr != from.sin_addr.s_addr
3981553Srgrimes					   && ntime.tv_sec < refusetime) {
3991553Srgrimes/* if the candidate has to repeat itself, the old code would refuse it
4001553Srgrimes * the second time.  That would prevent elections.
4011553Srgrimes */
4021553Srgrimes					to.tsp_type = TSP_REFUSE;
4031553Srgrimes				} else {
4041553Srgrimes					cadr.s_addr = from.sin_addr.s_addr;
4051553Srgrimes					to.tsp_type = TSP_ACCEPT;
4061553Srgrimes					refusetime = ntime.tv_sec + 30;
4071553Srgrimes				}
4081553Srgrimes				taddr = from;
40930830Scharnier				(void)strcpy(tname, msg->tsp_name);
41030830Scharnier				(void)strcpy(to.tsp_name, hostname);
4111553Srgrimes				answerdelay();
4121553Srgrimes				if (!acksend(&to, &taddr, tname,
4131553Srgrimes					     TSP_ACK, 0, 0))
4141553Srgrimes					syslog(LOG_WARNING,
4151553Srgrimes					     "no answer from candidate %s\n",
4161553Srgrimes					       tname);
4171553Srgrimes
4181553Srgrimes			} else {	/* fromnet->status == MASTER */
4191553Srgrimes				htp = addmach(msg->tsp_name, &from,fromnet);
4201553Srgrimes				to.tsp_type = TSP_QUIT;
42130830Scharnier				(void)strcpy(to.tsp_name, hostname);
4221553Srgrimes				if (!acksend(&to, &htp->addr, htp->name,
4231553Srgrimes					     TSP_ACK, 0, htp->noanswer)) {
4241553Srgrimes					syslog(LOG_ERR,
4251553Srgrimes					  "no reply from %s to ELECTION-QUIT",
4261553Srgrimes					       htp->name);
4271553Srgrimes					(void)remmach(htp);
4281553Srgrimes				}
4291553Srgrimes			}
4301553Srgrimes			break;
4311553Srgrimes
4321553Srgrimes		case TSP_CONFLICT:
4331553Srgrimes			if (fromnet->status != MASTER)
4341553Srgrimes				break;
4351553Srgrimes			/*
4361553Srgrimes			 * After a network partition, there can be
4371553Srgrimes			 * more than one master: the first slave to
4381553Srgrimes			 * come up will notify here the situation.
4391553Srgrimes			 */
44030830Scharnier			(void)strcpy(to.tsp_name, hostname);
4411553Srgrimes
4421553Srgrimes			/* The other master often gets into the same state,
4431553Srgrimes			 * with boring results.
4441553Srgrimes			 */
4451553Srgrimes			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
4461553Srgrimes			for (tries = 0; tries < 3; tries++) {
4471553Srgrimes				to.tsp_type = TSP_RESOLVE;
4481553Srgrimes				answer = acksend(&to, &ntp->dest_addr,
4491553Srgrimes						 ANYADDR, TSP_MASTERACK,
4501553Srgrimes						 ntp, 0);
4511553Srgrimes				if (answer == NULL)
4521553Srgrimes					break;
4531553Srgrimes				htp = addmach(answer->tsp_name,&from,ntp);
4541553Srgrimes				to.tsp_type = TSP_QUIT;
4551553Srgrimes				answer = acksend(&to, &htp->addr, htp->name,
4561553Srgrimes						 TSP_ACK, 0, htp->noanswer);
4571553Srgrimes				if (!answer) {
4581553Srgrimes					syslog(LOG_WARNING,
4591553Srgrimes				  "conflict error: no reply from %s to QUIT",
4601553Srgrimes						htp->name);
4611553Srgrimes					(void)remmach(htp);
4621553Srgrimes				}
4631553Srgrimes			}
4641553Srgrimes			masterup(ntp);
4651553Srgrimes			break;
4661553Srgrimes
4671553Srgrimes		case TSP_MSITE:
4681553Srgrimes			if (!slavenet)
4691553Srgrimes				break;
4701553Srgrimes			taddr = from;
4711553Srgrimes			to.tsp_type = TSP_MSITEREQ;
4721553Srgrimes			to.tsp_vers = TSPVERSION;
4731553Srgrimes			to.tsp_seq = 0;
47430830Scharnier			(void)strcpy(to.tsp_name, hostname);
4751553Srgrimes			answer = acksend(&to, &slavenet->dest_addr,
4761553Srgrimes					 ANYADDR, TSP_ACK,
4771553Srgrimes					 slavenet, 0);
4781553Srgrimes			if (answer != NULL
4791553Srgrimes			    && good_host_name(answer->tsp_name)) {
4801553Srgrimes				setmaster(answer);
4811553Srgrimes				to.tsp_type = TSP_ACK;
48230830Scharnier				(void)strcpy(to.tsp_name, answer->tsp_name);
4831553Srgrimes				bytenetorder(&to);
4841553Srgrimes				if (sendto(sock, (char *)&to,
4851553Srgrimes					   sizeof(struct tsp), 0,
48630642Scharnier					   (struct sockaddr*)&taddr,
48730830Scharnier					   sizeof(taddr)) < 0) {
4881553Srgrimes					trace_sendto_err(taddr.sin_addr);
4891553Srgrimes				}
4901553Srgrimes			}
4911553Srgrimes			break;
4921553Srgrimes
4931553Srgrimes		case TSP_MSITEREQ:
4941553Srgrimes			break;
4951553Srgrimes
4961553Srgrimes		case TSP_ACCEPT:
4971553Srgrimes		case TSP_REFUSE:
4981553Srgrimes		case TSP_RESOLVE:
4991553Srgrimes			break;
5001553Srgrimes
5011553Srgrimes		case TSP_QUIT:
5021553Srgrimes			doquit(msg);		/* become a slave */
5031553Srgrimes			break;
5041553Srgrimes
5051553Srgrimes		case TSP_TEST:
5061553Srgrimes			electiontime = 0;
5071553Srgrimes			break;
5081553Srgrimes
5091553Srgrimes		case TSP_LOOP:
5101553Srgrimes			/* looking for loops of masters */
5111553Srgrimes			if (!(status & MASTER))
5121553Srgrimes				break;
5131553Srgrimes			if (fromnet->status == SLAVE) {
5141553Srgrimes			    if (!strcmp(msg->tsp_name, hostname)) {
5151553Srgrimes				/*
5161553Srgrimes				 * Someone forwarded our message back to
5171553Srgrimes				 * us.  There must be a loop.  Tell the
5181553Srgrimes				 * master of this network to quit.
5191553Srgrimes				 *
5201553Srgrimes				 * The other master often gets into
5211553Srgrimes				 * the same state, with boring results.
5221553Srgrimes				 */
5231553Srgrimes				ntp = fromnet;
5241553Srgrimes				for (tries = 0; tries < 3; tries++) {
5251553Srgrimes				    to.tsp_type = TSP_RESOLVE;
5261553Srgrimes				    answer = acksend(&to, &ntp->dest_addr,
5271553Srgrimes						     ANYADDR, TSP_MASTERACK,
5281553Srgrimes						     ntp,0);
5291553Srgrimes				    if (answer == NULL)
5301553Srgrimes					break;
5311553Srgrimes				    taddr = from;
53230830Scharnier				    (void)strcpy(tname, answer->tsp_name);
5331553Srgrimes				    to.tsp_type = TSP_QUIT;
53430830Scharnier				    (void)strcpy(to.tsp_name, hostname);
5351553Srgrimes				    if (!acksend(&to, &taddr, tname,
5361553Srgrimes						 TSP_ACK, 0, 1)) {
5371553Srgrimes					syslog(LOG_ERR,
5381553Srgrimes					"no reply from %s to slave LOOP-QUIT",
5391553Srgrimes						 tname);
5401553Srgrimes				    } else {
5411553Srgrimes					electiontime = 0;
5421553Srgrimes				    }
5431553Srgrimes				}
544239991Sed				(void)gettimeofday(&ntime, NULL);
5451553Srgrimes				looptime = ntime.tv_sec + FASTTOUT;
5461553Srgrimes			    } else {
5471553Srgrimes				if (msg->tsp_hopcnt-- < 1)
5481553Srgrimes				    break;
5491553Srgrimes				bytenetorder(msg);
550299707Spfg				for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
5511553Srgrimes				    if (ntp->status == MASTER
5521553Srgrimes					&& 0 > sendto(sock, (char *)msg,
5531553Srgrimes						      sizeof(struct tsp), 0,
5541553Srgrimes					      (struct sockaddr*)&ntp->dest_addr,
5551553Srgrimes						      sizeof(ntp->dest_addr)))
5561553Srgrimes				    trace_sendto_err(ntp->dest_addr.sin_addr);
5571553Srgrimes				}
5581553Srgrimes			    }
5591553Srgrimes			} else {	/* fromnet->status == MASTER */
5601553Srgrimes			    /*
5611553Srgrimes			     * We should not have received this from a net
5621553Srgrimes			     * we are master on.  There must be two masters,
5631553Srgrimes			     * unless the packet was really from us.
5641553Srgrimes			     */
5651553Srgrimes			    if (from.sin_addr.s_addr
5661553Srgrimes				== fromnet->my_addr.s_addr) {
5671553Srgrimes				if (trace)
5681553Srgrimes				    fprintf(fd,"discarding forwarded LOOP\n");
5691553Srgrimes				break;
5701553Srgrimes			    }
5711553Srgrimes
5721553Srgrimes			    /*
5731553Srgrimes			     * The other master often gets into the same
5741553Srgrimes			     * state, with boring results.
5751553Srgrimes			     */
5761553Srgrimes			    ntp = fromnet;
5771553Srgrimes			    for (tries = 0; tries < 3; tries++) {
5781553Srgrimes				to.tsp_type = TSP_RESOLVE;
5791553Srgrimes				answer = acksend(&to, &ntp->dest_addr,
5801553Srgrimes						 ANYADDR, TSP_MASTERACK,
5811553Srgrimes						ntp,0);
5821553Srgrimes				if (!answer)
5831553Srgrimes					break;
5841553Srgrimes				htp = addmach(answer->tsp_name,
5851553Srgrimes					      &from,ntp);
5861553Srgrimes				to.tsp_type = TSP_QUIT;
58730830Scharnier				(void)strcpy(to.tsp_name, hostname);
5881553Srgrimes				if (!acksend(&to,&htp->addr,htp->name,
5891553Srgrimes					     TSP_ACK, 0, htp->noanswer)) {
5901553Srgrimes					syslog(LOG_ERR,
5911553Srgrimes				    "no reply from %s to master LOOP-QUIT",
5921553Srgrimes					       htp->name);
5931553Srgrimes					(void)remmach(htp);
5941553Srgrimes				}
5951553Srgrimes			    }
596239991Sed			    (void)gettimeofday(&ntime, NULL);
5971553Srgrimes			    looptime = ntime.tv_sec + FASTTOUT;
5981553Srgrimes			}
5991553Srgrimes			break;
6001553Srgrimes		default:
6011553Srgrimes			if (trace) {
6021553Srgrimes				fprintf(fd, "garbage message: ");
6031553Srgrimes				print(msg, &from);
6041553Srgrimes			}
6051553Srgrimes			break;
6061553Srgrimes		}
6071553Srgrimes	}
6081553Srgrimes	goto loop;
6091553Srgrimes}
6101553Srgrimes
6111553Srgrimes
6121553Srgrimes/*
6131553Srgrimes * tell the world who our master is
6141553Srgrimes */
6151553Srgrimesstatic void
616246209Scharniersetmaster(struct tsp *msg)
6171553Srgrimes{
6181553Srgrimes	if (slavenet
6191553Srgrimes	    && (slavenet != old_slavenet
6201553Srgrimes		|| strcmp(msg->tsp_name, master_name)
6211553Srgrimes		|| old_status != status)) {
62230830Scharnier		(void)strcpy(master_name, msg->tsp_name);
6231553Srgrimes		old_slavenet = slavenet;
6241553Srgrimes		old_status = status;
6251553Srgrimes
6261553Srgrimes		if (status & MASTER) {
6271553Srgrimes			syslog(LOG_NOTICE, "submaster to %s", master_name);
6281553Srgrimes			if (trace)
6291553Srgrimes				fprintf(fd, "submaster to %s\n", master_name);
6301553Srgrimes
6311553Srgrimes		} else {
6321553Srgrimes			syslog(LOG_NOTICE, "slave to %s", master_name);
6331553Srgrimes			if (trace)
6341553Srgrimes				fprintf(fd, "slave to %s\n", master_name);
6351553Srgrimes		}
6361553Srgrimes	}
6371553Srgrimes}
6381553Srgrimes
6391553Srgrimes
6401553Srgrimes
6411553Srgrimes/*
6421553Srgrimes * handle date change request on a slave
6431553Srgrimes */
6441553Srgrimesstatic void
645246209Scharnierschgdate(struct tsp *msg, char *newdate)
6461553Srgrimes{
6471553Srgrimes	struct tsp to;
6481553Srgrimes	u_short seq;
6491553Srgrimes	struct sockaddr_in taddr;
6501553Srgrimes	struct timeval otime;
6511553Srgrimes
6521553Srgrimes	if (!slavenet)
6531553Srgrimes		return;			/* no where to forward */
6541553Srgrimes
6551553Srgrimes	taddr = from;
6561553Srgrimes	seq = msg->tsp_seq;
6571553Srgrimes
6581553Srgrimes	syslog(LOG_INFO,
6591553Srgrimes	       "forwarding date change by %s to %s",
6601553Srgrimes	       msg->tsp_name, newdate);
6611553Srgrimes
6621553Srgrimes	/* adjust time for residence on the queue */
663239991Sed	(void)gettimeofday(&otime, NULL);
6641553Srgrimes	adj_msg_time(msg, &otime);
6651553Srgrimes
6661553Srgrimes	to.tsp_type = TSP_SETDATEREQ;
6671553Srgrimes	to.tsp_time = msg->tsp_time;
66830830Scharnier	(void)strcpy(to.tsp_name, hostname);
6691553Srgrimes	if (!acksend(&to, &slavenet->dest_addr,
6701553Srgrimes		     ANYADDR, TSP_DATEACK,
6711553Srgrimes		     slavenet, 0))
6721553Srgrimes		return;			/* no answer */
6731553Srgrimes
6741553Srgrimes	xmit(TSP_DATEACK, seq, &taddr);
6751553Srgrimes}
6761553Srgrimes
6771553Srgrimes
6781553Srgrimes/*
6791553Srgrimes * Used before answering a broadcast message to avoid network
6801553Srgrimes * contention and likely collisions.
6811553Srgrimes */
6821553Srgrimesstatic void
683246209Scharnieranswerdelay(void)
6841553Srgrimes{
6851553Srgrimes	struct timeval timeout;
6861553Srgrimes
6871553Srgrimes	timeout.tv_sec = 0;
6881553Srgrimes	timeout.tv_usec = delay1;
6891553Srgrimes
6901553Srgrimes	(void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
6911553Srgrimes	    &timeout);
6921553Srgrimes	return;
6931553Srgrimes}
694