slave.c revision 30830
159191Skris/*-
255714Skris * Copyright (c) 1985, 1993
355714Skris *	The Regents of the University of California.  All rights reserved.
455714Skris *
555714Skris * Redistribution and use in source and binary forms, with or without
655714Skris * modification, are permitted provided that the following conditions
755714Skris * are met:
8280297Sjkim * 1. Redistributions of source code must retain the above copyright
955714Skris *    notice, this list of conditions and the following disclaimer.
1055714Skris * 2. Redistributions in binary form must reproduce the above copyright
1155714Skris *    notice, this list of conditions and the following disclaimer in the
1255714Skris *    documentation and/or other materials provided with the distribution.
1355714Skris * 3. All advertising materials mentioning features or use of this software
1455714Skris *    must display the following acknowledgement:
15280297Sjkim *	This product includes software developed by the University of
1655714Skris *	California, Berkeley and its contributors.
1755714Skris * 4. Neither the name of the University nor the names of its contributors
1855714Skris *    may be used to endorse or promote products derived from this software
1955714Skris *    without specific prior written permission.
2055714Skris *
2155714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22280297Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155714Skris * SUCH DAMAGE.
3255714Skris */
3355714Skris
3455714Skris#ifndef lint
3555714Skris#if 0
3655714Skrisstatic char sccsid[] = "@(#)slave.c	8.1 (Berkeley) 6/6/93";
37280297Sjkim#endif
3855714Skrisstatic const char rcsid[] =
3955714Skris	"$Id: slave.c,v 1.3 1997/10/22 06:19:48 charnier Exp $";
40280297Sjkim#endif /* not lint */
4155714Skris
4255714Skris#include "globals.h"
4355714Skris#include <setjmp.h>
4455714Skris#include "pathnames.h"
4555714Skris
4655714Skrisextern jmp_buf jmpenv;
4755714Skrisextern int Mflag;
4855714Skrisextern int justquit;
4955714Skris
5055714Skrisextern u_short sequence;
5155714Skris
52280297Sjkimstatic char master_name[MAXHOSTNAMELEN+1];
5355714Skrisstatic struct netinfo *old_slavenet;
5455714Skrisstatic int old_status;
5555714Skris
5655714Skrisstatic void schgdate __P((struct tsp *, char *));
5755714Skrisstatic void setmaster __P((struct tsp *));
5855714Skrisstatic void answerdelay __P((void));
5955714Skris
60280297Sjkim#ifdef sgi
61194206Ssimonextern void logwtmp __P((struct timeval *, struct timeval *));
6255714Skris#else
63280297Sjkimextern void logwtmp __P((char *, char *, char *));
64194206Ssimon#endif /* sgi */
6555714Skris
66280297Sjkimint
67325335Sjkimslave()
68325335Sjkim{
69325335Sjkim	int tries;
70325335Sjkim	long electiontime, refusetime, looktime, looptime, adjtime;
71325335Sjkim	u_short seq;
72325335Sjkim	long fastelection;
73325335Sjkim#define FASTTOUT 3
7455714Skris	struct in_addr cadr;
75325335Sjkim	struct timeval otime;
76325335Sjkim	struct sockaddr_in taddr;
77325335Sjkim	char tname[MAXHOSTNAMELEN];
78325335Sjkim	struct tsp *msg, to;
79325335Sjkim	struct timeval ntime, wait;
80325335Sjkim	struct tsp *answer;
81325335Sjkim	int timeout();
82325335Sjkim	char olddate[32];
83325335Sjkim	char newdate[32];
84325335Sjkim	struct netinfo *ntp;
85325335Sjkim	struct hosttbl *htp;
86325335Sjkim
87325335Sjkim
88325335Sjkim	old_slavenet = 0;
89325335Sjkim	seq = 0;
90325335Sjkim	refusetime = 0;
91325335Sjkim	adjtime = 0;
92325335Sjkim
93325335Sjkim	(void)gettimeofday(&ntime, 0);
94325335Sjkim	electiontime = ntime.tv_sec + delay2;
95325335Sjkim	fastelection = ntime.tv_sec + FASTTOUT;
96325335Sjkim	if (justquit)
97325335Sjkim		looktime = electiontime;
98325335Sjkim	else
99325335Sjkim		looktime = fastelection;
100325335Sjkim	looptime = fastelection;
101325335Sjkim
102325335Sjkim	if (slavenet)
103325335Sjkim		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
104325335Sjkim	if (status & MASTER) {
105325335Sjkim		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
106325335Sjkim			if (ntp->status == MASTER)
107325335Sjkim				masterup(ntp);
108325335Sjkim		}
109325335Sjkim	}
110325335Sjkim
111325335Sjkimloop:
112325335Sjkim	get_goodgroup(0);
113325335Sjkim	(void)gettimeofday(&ntime, (struct timezone *)0);
114325335Sjkim	if (ntime.tv_sec > electiontime) {
115325335Sjkim		if (trace)
116325335Sjkim			fprintf(fd, "election timer expired\n");
117325335Sjkim		longjmp(jmpenv, 1);
118325335Sjkim	}
119325335Sjkim
120325335Sjkim	if (ntime.tv_sec >= looktime) {
121325335Sjkim		if (trace)
122325335Sjkim			fprintf(fd, "Looking for nets to master\n");
123325335Sjkim
124325335Sjkim		if (Mflag && nignorednets > 0) {
125325335Sjkim			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
126325335Sjkim				if (ntp->status == IGNORE
127325335Sjkim				    || ntp->status == NOMASTER) {
128325335Sjkim					lookformaster(ntp);
129325335Sjkim					if (ntp->status == MASTER) {
130325335Sjkim						masterup(ntp);
131325335Sjkim					} else if (ntp->status == MASTER) {
132325335Sjkim						ntp->status = NOMASTER;
133325335Sjkim					}
134325335Sjkim				}
135325335Sjkim				if (ntp->status == MASTER
136325335Sjkim				    && --ntp->quit_count < 0)
137325335Sjkim					ntp->quit_count = 0;
138325335Sjkim			}
139325335Sjkim			makeslave(slavenet);	/* prune extras */
140325335Sjkim			setstatus();
141325335Sjkim		}
142325335Sjkim		(void)gettimeofday(&ntime, 0);
143325335Sjkim		looktime = ntime.tv_sec + delay2;
144325335Sjkim	}
145325335Sjkim	if (ntime.tv_sec >= looptime) {
146325335Sjkim		if (trace)
147325335Sjkim			fprintf(fd, "Looking for loops\n");
148325335Sjkim		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
149325335Sjkim		    if (ntp->status == MASTER) {
150325335Sjkim			to.tsp_type = TSP_LOOP;
151325335Sjkim			to.tsp_vers = TSPVERSION;
152325335Sjkim			to.tsp_seq = sequence++;
153325335Sjkim			to.tsp_hopcnt = MAX_HOPCNT;
154325335Sjkim			(void)strcpy(to.tsp_name, hostname);
155325335Sjkim			bytenetorder(&to);
156325335Sjkim			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
157325335Sjkim				   (struct sockaddr*)&ntp->dest_addr,
158325335Sjkim				   sizeof(ntp->dest_addr)) < 0) {
159325335Sjkim				trace_sendto_err(ntp->dest_addr.sin_addr);
160325335Sjkim			}
161325335Sjkim		    }
162325335Sjkim		}
163325335Sjkim		(void)gettimeofday(&ntime, 0);
164325335Sjkim		looptime = ntime.tv_sec + delay2;
165325335Sjkim	}
166325335Sjkim
167325335Sjkim	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
168325335Sjkim	if (wait.tv_sec < 0)
169325335Sjkim		wait.tv_sec = 0;
170325335Sjkim	wait.tv_sec += FASTTOUT;
171325335Sjkim	wait.tv_usec = 0;
172325335Sjkim	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
173325335Sjkim
174325335Sjkim	if (msg != NULL) {
175325335Sjkim		/*
176325335Sjkim		 * filter stuff not for us
177325335Sjkim		 */
178325335Sjkim		switch (msg->tsp_type) {
179325335Sjkim		case TSP_SETDATE:
180325335Sjkim		case TSP_TRACEOFF:
181325335Sjkim		case TSP_TRACEON:
182325335Sjkim			/*
183325335Sjkim			 * XXX check to see they are from ourself
184325335Sjkim			 */
185325335Sjkim			break;
186325335Sjkim
187325335Sjkim		case TSP_TEST:
188325335Sjkim		case TSP_MSITE:
189325335Sjkim			break;
190325335Sjkim
191325335Sjkim		case TSP_MASTERUP:
192325335Sjkim			if (!fromnet) {
193325335Sjkim				if (trace) {
194325335Sjkim					fprintf(fd, "slave ignored: ");
195325335Sjkim					print(msg, &from);
196325335Sjkim				}
197325335Sjkim				goto loop;
198325335Sjkim			}
199325335Sjkim			break;
200325335Sjkim
201325335Sjkim		default:
202325335Sjkim			if (!fromnet
203325335Sjkim			    || fromnet->status == IGNORE
204325335Sjkim			    || fromnet->status == NOMASTER) {
205325335Sjkim				if (trace) {
206325335Sjkim					fprintf(fd, "slave ignored: ");
207325335Sjkim					print(msg, &from);
208325335Sjkim				}
209325335Sjkim				goto loop;
210325335Sjkim			}
211325335Sjkim			break;
212325335Sjkim		}
213325335Sjkim
214325335Sjkim
215325335Sjkim		/*
216325335Sjkim		 * now process the message
217325335Sjkim		 */
218325335Sjkim		switch (msg->tsp_type) {
219325335Sjkim
220325335Sjkim		case TSP_ADJTIME:
221325335Sjkim			if (fromnet != slavenet)
222325335Sjkim				break;
223325335Sjkim			if (!good_host_name(msg->tsp_name)) {
224325335Sjkim				syslog(LOG_NOTICE,
225325335Sjkim				   "attempted time adjustment by %s",
226325335Sjkim				       msg->tsp_name);
227325335Sjkim				suppress(&from, msg->tsp_name, fromnet);
228325335Sjkim				break;
229325335Sjkim			}
230325335Sjkim			/*
231325335Sjkim			 * Speed up loop detection in case we have a loop.
232325335Sjkim			 * Otherwise the clocks can race until the loop
233325335Sjkim			 * is found.
234325335Sjkim			 */
235325335Sjkim			(void)gettimeofday(&otime, 0);
236325335Sjkim			if (adjtime < otime.tv_sec)
237325335Sjkim				looptime -= (looptime-otime.tv_sec)/2 + 1;
238325335Sjkim
239325335Sjkim			setmaster(msg);
240325335Sjkim			if (seq != msg->tsp_seq) {
241325335Sjkim				seq = msg->tsp_seq;
242325335Sjkim				synch(tvtomsround(msg->tsp_time));
243325335Sjkim			}
244325335Sjkim			(void)gettimeofday(&ntime, 0);
245325335Sjkim			electiontime = ntime.tv_sec + delay2;
246325335Sjkim			fastelection = ntime.tv_sec + FASTTOUT;
247325335Sjkim			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
248325335Sjkim			break;
249325335Sjkim
250325335Sjkim		case TSP_SETTIME:
251325335Sjkim			if (fromnet != slavenet)
252325335Sjkim				break;
253325335Sjkim			if (seq == msg->tsp_seq)
254325335Sjkim				break;
255325335Sjkim			seq = msg->tsp_seq;
256325335Sjkim
257325335Sjkim			/* adjust time for residence on the queue */
258325335Sjkim			(void)gettimeofday(&otime, 0);
259325335Sjkim			adj_msg_time(msg,&otime);
260325335Sjkim#ifdef sgi
261325335Sjkim			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
262325335Sjkim			(void)cftime(olddate, "%D %T", &otime.tv_sec);
263325335Sjkim#else
264325335Sjkim			/*
265325335Sjkim			 * the following line is necessary due to syslog
266325335Sjkim			 * calling ctime() which clobbers the static buffer
267325335Sjkim			 */
268325335Sjkim			(void)strcpy(olddate, date());
269325335Sjkim			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
270325335Sjkim#endif /* sgi */
271325335Sjkim
272325335Sjkim			if (!good_host_name(msg->tsp_name)) {
273325335Sjkim				syslog(LOG_NOTICE,
274325335Sjkim			    "attempted time setting by untrusted %s to %s",
275325335Sjkim				       msg->tsp_name, newdate);
276325335Sjkim				suppress(&from, msg->tsp_name, fromnet);
277325335Sjkim				break;
278325335Sjkim			}
279325335Sjkim
280325335Sjkim			setmaster(msg);
281325335Sjkim			timevalsub(&ntime, &msg->tsp_time, &otime);
282325335Sjkim			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
283325335Sjkim				/*
284325335Sjkim				 * do not change the clock if we can adjust it
285325335Sjkim				 */
286325335Sjkim				synch(tvtomsround(ntime));
287325335Sjkim			} else {
288325335Sjkim#ifdef sgi
289325335Sjkim				if (0 > settimeofday(&msg->tsp_time, 0)) {
290325335Sjkim					syslog(LOG_ERR,"settimeofdate(): %m");
291325335Sjkim					break;
292325335Sjkim				}
293325335Sjkim				logwtmp(&otime, &msg->tsp_time);
294325335Sjkim#else
295325335Sjkim				logwtmp("|", "date", "");
296325335Sjkim				(void)settimeofday(&msg->tsp_time, 0);
297325335Sjkim				logwtmp("{", "date", "");
298325335Sjkim#endif /* sgi */
299325335Sjkim				syslog(LOG_NOTICE,
300325335Sjkim				       "date changed by %s from %s",
301325335Sjkim					msg->tsp_name, olddate);
302325335Sjkim				if (status & MASTER)
303325335Sjkim					spreadtime();
304325335Sjkim			}
305325335Sjkim			(void)gettimeofday(&ntime, 0);
306325335Sjkim			electiontime = ntime.tv_sec + delay2;
307325335Sjkim			fastelection = ntime.tv_sec + FASTTOUT;
308325335Sjkim
309325335Sjkim/* This patches a bad protocol bug.  Imagine a system with several networks,
310325335Sjkim * where there are a pair of redundant gateways between a pair of networks,
311325335Sjkim * each running timed.  Assume that we start with a third machine mastering
312325335Sjkim * one of the networks, and one of the gateways mastering the other.
313325335Sjkim * Imagine that the third machine goes away and the non-master gateway
314325335Sjkim * decides to replace it.  If things are timed just 'right,' we will have
315325335Sjkim * each gateway mastering one network for a little while.  If a SETTIME
316325335Sjkim * message gets into the network at that time, perhaps from the newly
317325335Sjkim * masterful gateway as it was taking control, the SETTIME will loop
318325335Sjkim * forever.  Each time a gateway receives it on its slave side, it will
319325335Sjkim * call spreadtime to forward it on its mastered network.  We are now in
320325335Sjkim * a permanent loop, since the SETTIME msgs will keep any clock
321325335Sjkim * in the network from advancing.  Normally, the 'LOOP' stuff will detect
322325335Sjkim * and correct the situation.  However, with the clocks stopped, the
323325335Sjkim * 'looptime' timer cannot expire.  While they are in this state, the
324325335Sjkim * masters will try to saturate the network with SETTIME packets.
32555714Skris */
326280297Sjkim			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
327			break;
328
329		case TSP_MASTERUP:
330			if (slavenet && fromnet != slavenet)
331				break;
332			if (!good_host_name(msg->tsp_name)) {
333				suppress(&from, msg->tsp_name, fromnet);
334				if (electiontime > fastelection)
335					electiontime = fastelection;
336				break;
337			}
338			makeslave(fromnet);
339			setmaster(msg);
340			setstatus();
341			answerdelay();
342			xmit(TSP_SLAVEUP, 0, &from);
343			(void)gettimeofday(&ntime, 0);
344			electiontime = ntime.tv_sec + delay2;
345			fastelection = ntime.tv_sec + FASTTOUT;
346			refusetime = 0;
347			break;
348
349		case TSP_MASTERREQ:
350			if (fromnet->status != SLAVE)
351				break;
352			(void)gettimeofday(&ntime, 0);
353			electiontime = ntime.tv_sec + delay2;
354			break;
355
356		case TSP_SETDATE:
357#ifdef sgi
358			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
359#else
360			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
361#endif /* sgi */
362			schgdate(msg, newdate);
363			break;
364
365		case TSP_SETDATEREQ:
366			if (fromnet->status != MASTER)
367				break;
368#ifdef sgi
369			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
370#else
371			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
372#endif /* sgi */
373			htp = findhost(msg->tsp_name);
374			if (0 == htp) {
375				syslog(LOG_WARNING,
376				       "DATEREQ from uncontrolled machine");
377				break;
378			}
379			if (!htp->good) {
380				syslog(LOG_WARNING,
381				"attempted date change by untrusted %s to %s",
382				       htp->name, newdate);
383				spreadtime();
384				break;
385			}
386			schgdate(msg, newdate);
387			break;
388
389		case TSP_TRACEON:
390			traceon();
391			break;
392
393		case TSP_TRACEOFF:
394			traceoff("Tracing ended at %s\n");
395			break;
396
397		case TSP_SLAVEUP:
398			newslave(msg);
399			break;
400
401		case TSP_ELECTION:
402			if (fromnet->status == SLAVE) {
403				(void)gettimeofday(&ntime, 0);
404				electiontime = ntime.tv_sec + delay2;
405				fastelection = ntime.tv_sec + FASTTOUT;
406				seq = 0;
407				if (!good_host_name(msg->tsp_name)) {
408					syslog(LOG_NOTICE,
409					       "suppress election of %s",
410					       msg->tsp_name);
411					to.tsp_type = TSP_QUIT;
412					electiontime = fastelection;
413				} else if (cadr.s_addr != from.sin_addr.s_addr
414					   && ntime.tv_sec < refusetime) {
415/* if the candidate has to repeat itself, the old code would refuse it
416 * the second time.  That would prevent elections.
417 */
418					to.tsp_type = TSP_REFUSE;
419				} else {
420					cadr.s_addr = from.sin_addr.s_addr;
421					to.tsp_type = TSP_ACCEPT;
422					refusetime = ntime.tv_sec + 30;
423				}
424				taddr = from;
425				(void)strcpy(tname, msg->tsp_name);
426				(void)strcpy(to.tsp_name, hostname);
427				answerdelay();
428				if (!acksend(&to, &taddr, tname,
429					     TSP_ACK, 0, 0))
430					syslog(LOG_WARNING,
431					     "no answer from candidate %s\n",
432					       tname);
433
434			} else {	/* fromnet->status == MASTER */
435				htp = addmach(msg->tsp_name, &from,fromnet);
436				to.tsp_type = TSP_QUIT;
437				(void)strcpy(to.tsp_name, hostname);
438				if (!acksend(&to, &htp->addr, htp->name,
439					     TSP_ACK, 0, htp->noanswer)) {
440					syslog(LOG_ERR,
441					  "no reply from %s to ELECTION-QUIT",
442					       htp->name);
443					(void)remmach(htp);
444				}
445			}
446			break;
447
448		case TSP_CONFLICT:
449			if (fromnet->status != MASTER)
450				break;
451			/*
452			 * After a network partition, there can be
453			 * more than one master: the first slave to
454			 * come up will notify here the situation.
455			 */
456			(void)strcpy(to.tsp_name, hostname);
457
458			/* The other master often gets into the same state,
459			 * with boring results.
460			 */
461			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
462			for (tries = 0; tries < 3; tries++) {
463				to.tsp_type = TSP_RESOLVE;
464				answer = acksend(&to, &ntp->dest_addr,
465						 ANYADDR, TSP_MASTERACK,
466						 ntp, 0);
467				if (answer == NULL)
468					break;
469				htp = addmach(answer->tsp_name,&from,ntp);
470				to.tsp_type = TSP_QUIT;
471				answer = acksend(&to, &htp->addr, htp->name,
472						 TSP_ACK, 0, htp->noanswer);
473				if (!answer) {
474					syslog(LOG_WARNING,
475				  "conflict error: no reply from %s to QUIT",
476						htp->name);
477					(void)remmach(htp);
478				}
479			}
480			masterup(ntp);
481			break;
482
483		case TSP_MSITE:
484			if (!slavenet)
485				break;
486			taddr = from;
487			to.tsp_type = TSP_MSITEREQ;
488			to.tsp_vers = TSPVERSION;
489			to.tsp_seq = 0;
490			(void)strcpy(to.tsp_name, hostname);
491			answer = acksend(&to, &slavenet->dest_addr,
492					 ANYADDR, TSP_ACK,
493					 slavenet, 0);
494			if (answer != NULL
495			    && good_host_name(answer->tsp_name)) {
496				setmaster(answer);
497				to.tsp_type = TSP_ACK;
498				(void)strcpy(to.tsp_name, answer->tsp_name);
499				bytenetorder(&to);
500				if (sendto(sock, (char *)&to,
501					   sizeof(struct tsp), 0,
502					   (struct sockaddr*)&taddr,
503					   sizeof(taddr)) < 0) {
504					trace_sendto_err(taddr.sin_addr);
505				}
506			}
507			break;
508
509		case TSP_MSITEREQ:
510			break;
511
512		case TSP_ACCEPT:
513		case TSP_REFUSE:
514		case TSP_RESOLVE:
515			break;
516
517		case TSP_QUIT:
518			doquit(msg);		/* become a slave */
519			break;
520
521		case TSP_TEST:
522			electiontime = 0;
523			break;
524
525		case TSP_LOOP:
526			/* looking for loops of masters */
527			if (!(status & MASTER))
528				break;
529			if (fromnet->status == SLAVE) {
530			    if (!strcmp(msg->tsp_name, hostname)) {
531				/*
532				 * Someone forwarded our message back to
533				 * us.  There must be a loop.  Tell the
534				 * master of this network to quit.
535				 *
536				 * The other master often gets into
537				 * the same state, with boring results.
538				 */
539				ntp = fromnet;
540				for (tries = 0; tries < 3; tries++) {
541				    to.tsp_type = TSP_RESOLVE;
542				    answer = acksend(&to, &ntp->dest_addr,
543						     ANYADDR, TSP_MASTERACK,
544						     ntp,0);
545				    if (answer == NULL)
546					break;
547				    taddr = from;
548				    (void)strcpy(tname, answer->tsp_name);
549				    to.tsp_type = TSP_QUIT;
550				    (void)strcpy(to.tsp_name, hostname);
551				    if (!acksend(&to, &taddr, tname,
552						 TSP_ACK, 0, 1)) {
553					syslog(LOG_ERR,
554					"no reply from %s to slave LOOP-QUIT",
555						 tname);
556				    } else {
557					electiontime = 0;
558				    }
559				}
560				(void)gettimeofday(&ntime, 0);
561				looptime = ntime.tv_sec + FASTTOUT;
562			    } else {
563				if (msg->tsp_hopcnt-- < 1)
564				    break;
565				bytenetorder(msg);
566				for (ntp = nettab; ntp != 0; ntp = ntp->next) {
567				    if (ntp->status == MASTER
568					&& 0 > sendto(sock, (char *)msg,
569						      sizeof(struct tsp), 0,
570					      (struct sockaddr*)&ntp->dest_addr,
571						      sizeof(ntp->dest_addr)))
572				    trace_sendto_err(ntp->dest_addr.sin_addr);
573				}
574			    }
575			} else {	/* fromnet->status == MASTER */
576			    /*
577			     * We should not have received this from a net
578			     * we are master on.  There must be two masters,
579			     * unless the packet was really from us.
580			     */
581			    if (from.sin_addr.s_addr
582				== fromnet->my_addr.s_addr) {
583				if (trace)
584				    fprintf(fd,"discarding forwarded LOOP\n");
585				break;
586			    }
587
588			    /*
589			     * The other master often gets into the same
590			     * state, with boring results.
591			     */
592			    ntp = fromnet;
593			    for (tries = 0; tries < 3; tries++) {
594				to.tsp_type = TSP_RESOLVE;
595				answer = acksend(&to, &ntp->dest_addr,
596						 ANYADDR, TSP_MASTERACK,
597						ntp,0);
598				if (!answer)
599					break;
600				htp = addmach(answer->tsp_name,
601					      &from,ntp);
602				to.tsp_type = TSP_QUIT;
603				(void)strcpy(to.tsp_name, hostname);
604				if (!acksend(&to,&htp->addr,htp->name,
605					     TSP_ACK, 0, htp->noanswer)) {
606					syslog(LOG_ERR,
607				    "no reply from %s to master LOOP-QUIT",
608					       htp->name);
609					(void)remmach(htp);
610				}
611			    }
612			    (void)gettimeofday(&ntime, 0);
613			    looptime = ntime.tv_sec + FASTTOUT;
614			}
615			break;
616		default:
617			if (trace) {
618				fprintf(fd, "garbage message: ");
619				print(msg, &from);
620			}
621			break;
622		}
623	}
624	goto loop;
625}
626
627
628/*
629 * tell the world who our master is
630 */
631static void
632setmaster(msg)
633	struct tsp *msg;
634{
635	if (slavenet
636	    && (slavenet != old_slavenet
637		|| strcmp(msg->tsp_name, master_name)
638		|| old_status != status)) {
639		(void)strcpy(master_name, msg->tsp_name);
640		old_slavenet = slavenet;
641		old_status = status;
642
643		if (status & MASTER) {
644			syslog(LOG_NOTICE, "submaster to %s", master_name);
645			if (trace)
646				fprintf(fd, "submaster to %s\n", master_name);
647
648		} else {
649			syslog(LOG_NOTICE, "slave to %s", master_name);
650			if (trace)
651				fprintf(fd, "slave to %s\n", master_name);
652		}
653	}
654}
655
656
657
658/*
659 * handle date change request on a slave
660 */
661static void
662schgdate(msg, newdate)
663	struct tsp *msg;
664	char *newdate;
665{
666	struct tsp to;
667	u_short seq;
668	struct sockaddr_in taddr;
669	struct timeval otime;
670
671	if (!slavenet)
672		return;			/* no where to forward */
673
674	taddr = from;
675	seq = msg->tsp_seq;
676
677	syslog(LOG_INFO,
678	       "forwarding date change by %s to %s",
679	       msg->tsp_name, newdate);
680
681	/* adjust time for residence on the queue */
682	(void)gettimeofday(&otime, 0);
683	adj_msg_time(msg, &otime);
684
685	to.tsp_type = TSP_SETDATEREQ;
686	to.tsp_time = msg->tsp_time;
687	(void)strcpy(to.tsp_name, hostname);
688	if (!acksend(&to, &slavenet->dest_addr,
689		     ANYADDR, TSP_DATEACK,
690		     slavenet, 0))
691		return;			/* no answer */
692
693	xmit(TSP_DATEACK, seq, &taddr);
694}
695
696
697/*
698 * Used before answering a broadcast message to avoid network
699 * contention and likely collisions.
700 */
701static void
702answerdelay()
703{
704#ifdef sgi
705	sginap(delay1);
706#else
707	struct timeval timeout;
708
709	timeout.tv_sec = 0;
710	timeout.tv_usec = delay1;
711
712	(void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
713	    &timeout);
714	return;
715#endif /* sgi */
716}
717