slave.c revision 1553
125184Sjkh/*-
2113674Smtm * Copyright (c) 1985, 1993
3113674Smtm *	The Regents of the University of California.  All rights reserved.
4113674Smtm *
5113674Smtm * Redistribution and use in source and binary forms, with or without
6113674Smtm * modification, are permitted provided that the following conditions
7113674Smtm * are met:
8113674Smtm * 1. Redistributions of source code must retain the above copyright
9113674Smtm *    notice, this list of conditions and the following disclaimer.
10113674Smtm * 2. Redistributions in binary form must reproduce the above copyright
11113674Smtm *    notice, this list of conditions and the following disclaimer in the
12113674Smtm *    documentation and/or other materials provided with the distribution.
13113674Smtm * 3. All advertising materials mentioning features or use of this software
14113674Smtm *    must display the following acknowledgement:
15113674Smtm *	This product includes software developed by the University of
16113674Smtm *	California, Berkeley and its contributors.
17113674Smtm * 4. Neither the name of the University nor the names of its contributors
18113674Smtm *    may be used to endorse or promote products derived from this software
19113674Smtm *    without specific prior written permission.
20113674Smtm *
21113674Smtm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22113674Smtm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23113674Smtm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24113674Smtm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2550472Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2666830Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2725184Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28113674Smtm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29113674Smtm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30113674Smtm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31113674Smtm * SUCH DAMAGE.
3225184Sjkh */
33178356Ssam
34197147Shrs#ifndef lint
35197147Shrsstatic char sccsid[] = "@(#)slave.c	8.1 (Berkeley) 6/6/93";
36178356Ssam#endif /* not lint */
37178356Ssam
38178356Ssam#ifdef sgi
39178356Ssam#ident "$Revision: 1.20 $"
40178356Ssam#endif
41178356Ssam
42178356Ssam#include "globals.h"
43178356Ssam#include <setjmp.h>
44178356Ssam#include "pathnames.h"
45178356Ssam
46178356Ssamextern jmp_buf jmpenv;
47222515Sbzextern int Mflag;
48222515Sbzextern int justquit;
49222515Sbz
50197139Shrsextern u_short sequence;
51178356Ssam
52178356Ssamstatic char master_name[MAXHOSTNAMELEN+1];
53178356Ssamstatic struct netinfo *old_slavenet;
54178356Ssamstatic int old_status;
55197139Shrs
56197147Shrsstatic void schgdate __P((struct tsp *, char *));
57197147Shrsstatic void setmaster __P((struct tsp *));
58178356Ssamstatic void answerdelay __P((void));
59178356Ssam
60178356Ssam#ifdef sgi
61178356Ssamextern void logwtmp __P((struct timeval *, struct timeval *));
62178356Ssam#else
63178356Ssamextern void logwtmp __P((char *, char *, char *));
64178356Ssam#endif /* sgi */
65197139Shrs
66178356Ssamint
67222515Sbzslave()
68222515Sbz{
69222515Sbz	int tries;
70178356Ssam	long electiontime, refusetime, looktime, looptime, adjtime;
71178356Ssam	u_short seq;
72197139Shrs	long fastelection;
73178356Ssam#define FASTTOUT 3
74178356Ssam	struct in_addr cadr;
75178356Ssam	struct timeval otime;
76178356Ssam	struct sockaddr_in taddr;
77113674Smtm	char tname[MAXHOSTNAMELEN];
78113674Smtm	struct tsp *msg, to;
79113674Smtm	struct timeval ntime, wait;
80113674Smtm	struct tsp *answer;
81147088Sbrooks	int timeout();
82147088Sbrooks	char olddate[32];
83113674Smtm	char newdate[32];
84113674Smtm	struct netinfo *ntp;
85113674Smtm	struct hosttbl *htp;
86197139Shrs
87147088Sbrooks
88147088Sbrooks	old_slavenet = 0;
89222515Sbz	seq = 0;
90222515Sbz	refusetime = 0;
91222515Sbz	adjtime = 0;
92222515Sbz
93222515Sbz	(void)gettimeofday(&ntime, 0);
94197139Shrs	electiontime = ntime.tv_sec + delay2;
95147088Sbrooks	fastelection = ntime.tv_sec + FASTTOUT;
96113674Smtm	if (justquit)
97223506Spluknet		looktime = electiontime;
98147088Sbrooks	else
99113674Smtm		looktime = fastelection;
100147088Sbrooks	looptime = fastelection;
101197139Shrs
102197139Shrs	if (slavenet)
103222733Shrs		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
104222733Shrs	if (status & MASTER) {
105222746Shrs		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
106222733Shrs			if (ntp->status == MASTER)
107212574Shrs				masterup(ntp);
108197139Shrs		}
109222733Shrs	}
110222733Shrs
111222733Shrsloop:
112222733Shrs	get_goodgroup(0);
113222733Shrs	(void)gettimeofday(&ntime, (struct timezone *)0);
114222733Shrs	if (ntime.tv_sec > electiontime) {
115222733Shrs		if (trace)
116225521Shrs			fprintf(fd, "election timer expired\n");
117225521Shrs		longjmp(jmpenv, 1);
118225521Shrs	}
119225521Shrs
120225521Shrs	if (ntime.tv_sec >= looktime) {
121225521Shrs		if (trace)
122212574Shrs			fprintf(fd, "Looking for nets to master\n");
123212574Shrs
124197526Shrs		if (Mflag && nignorednets > 0) {
125212574Shrs			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
126212574Shrs				if (ntp->status == IGNORE
127212574Shrs				    || ntp->status == NOMASTER) {
128212574Shrs					lookformaster(ntp);
129225522Shrs					if (ntp->status == MASTER) {
130225522Shrs						masterup(ntp);
131225522Shrs					} else if (ntp->status == MASTER) {
132225522Shrs						ntp->status = NOMASTER;
133225522Shrs					}
134225522Shrs				}
135225522Shrs				if (ntp->status == MASTER
136225522Shrs				    && --ntp->quit_count < 0)
137212574Shrs					ntp->quit_count = 0;
138225522Shrs			}
139212574Shrs			makeslave(slavenet);	/* prune extras */
140212574Shrs			setstatus();
141212574Shrs		}
142212574Shrs		(void)gettimeofday(&ntime, 0);
143212574Shrs		looktime = ntime.tv_sec + delay2;
144212574Shrs	}
145212574Shrs	if (ntime.tv_sec >= looptime) {
146212574Shrs		if (trace)
147212574Shrs			fprintf(fd, "Looking for loops\n");
148225522Shrs		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
149212574Shrs		    if (ntp->status == MASTER) {
150212574Shrs			to.tsp_type = TSP_LOOP;
151197139Shrs			to.tsp_vers = TSPVERSION;
152197139Shrs			to.tsp_seq = sequence++;
153197139Shrs			to.tsp_hopcnt = MAX_HOPCNT;
154197139Shrs			(void)strcpy(to.tsp_name, hostname);
155197139Shrs			bytenetorder(&to);
156197139Shrs			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
157147088Sbrooks				   (struct sockaddr*)&ntp->dest_addr,
158147682Sbrooks				   sizeof(ntp->dest_addr)) < 0) {
159147088Sbrooks				trace_sendto_err(ntp->dest_addr.sin_addr);
160147088Sbrooks			}
161147088Sbrooks		    }
162147088Sbrooks		}
163149726Sbrooks		(void)gettimeofday(&ntime, 0);
164149726Sbrooks		looptime = ntime.tv_sec + delay2;
165149726Sbrooks	}
166157706Sbrooks
167157706Sbrooks	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
168157706Sbrooks	if (wait.tv_sec < 0)
169147088Sbrooks		wait.tv_sec = 0;
170147088Sbrooks	wait.tv_sec += FASTTOUT;
171147088Sbrooks	wait.tv_usec = 0;
172147121Sbrooks	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
173113674Smtm
17425184Sjkh	if (msg != NULL) {
175116029Smtm		/*
176161386Sbrooks		 * filter stuff not for us
177161386Sbrooks		 */
178116029Smtm		switch (msg->tsp_type) {
179116029Smtm		case TSP_SETDATE:
180116029Smtm		case TSP_TRACEOFF:
181197139Shrs		case TSP_TRACEON:
182147121Sbrooks			/*
183116029Smtm			 * XXX check to see they are from ourself
184147088Sbrooks			 */
185147682Sbrooks			break;
186147121Sbrooks
187147088Sbrooks		case TSP_TEST:
188147088Sbrooks		case TSP_MSITE:
189147088Sbrooks			break;
190147088Sbrooks
191147088Sbrooks		case TSP_MASTERUP:
192147088Sbrooks			if (!fromnet) {
193147088Sbrooks				if (trace) {
194161386Sbrooks					fprintf(fd, "slave ignored: ");
195161386Sbrooks					print(msg, &from);
196161386Sbrooks				}
197161386Sbrooks				goto loop;
198157706Sbrooks			}
199147121Sbrooks			break;
200116029Smtm
201116029Smtm		default:
202157706Sbrooks			if (!fromnet
203197147Shrs			    || fromnet->status == IGNORE
204197147Shrs			    || fromnet->status == NOMASTER) {
205197147Shrs				if (trace) {
206197147Shrs					fprintf(fd, "slave ignored: ");
207197147Shrs					print(msg, &from);
208157706Sbrooks				}
209157706Sbrooks				goto loop;
210212578Shrs			}
211197139Shrs			break;
212157706Sbrooks		}
213157706Sbrooks
214157706Sbrooks
215157706Sbrooks		/*
216157706Sbrooks		 * now process the message
217157706Sbrooks		 */
218157736Sbrooks		switch (msg->tsp_type) {
219157706Sbrooks
220157706Sbrooks		case TSP_ADJTIME:
221157706Sbrooks			if (fromnet != slavenet)
222157706Sbrooks				break;
223157706Sbrooks			if (!good_host_name(msg->tsp_name)) {
224157706Sbrooks				syslog(LOG_NOTICE,
225157706Sbrooks				   "attempted time adjustment by %s",
226168033Sache				       msg->tsp_name);
227157706Sbrooks				suppress(&from, msg->tsp_name, fromnet);
228157706Sbrooks				break;
229197139Shrs			}
230147088Sbrooks			/*
231147088Sbrooks			 * Speed up loop detection in case we have a loop.
232147088Sbrooks			 * Otherwise the clocks can race until the loop
233147088Sbrooks			 * is found.
234147088Sbrooks			 */
235212574Shrs			(void)gettimeofday(&otime, 0);
236147088Sbrooks			if (adjtime < otime.tv_sec)
237197139Shrs				looptime -= (looptime-otime.tv_sec)/2 + 1;
238197139Shrs
239147088Sbrooks			setmaster(msg);
240147088Sbrooks			if (seq != msg->tsp_seq) {
241147088Sbrooks				seq = msg->tsp_seq;
242147088Sbrooks				synch(tvtomsround(msg->tsp_time));
243212574Shrs			}
244147088Sbrooks			(void)gettimeofday(&ntime, 0);
245147088Sbrooks			electiontime = ntime.tv_sec + delay2;
246197139Shrs			fastelection = ntime.tv_sec + FASTTOUT;
247147088Sbrooks			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
248147088Sbrooks			break;
249147088Sbrooks
250147088Sbrooks		case TSP_SETTIME:
251197139Shrs			if (fromnet != slavenet)
252197139Shrs				break;
253147088Sbrooks			if (seq == msg->tsp_seq)
254147088Sbrooks				break;
255147088Sbrooks			seq = msg->tsp_seq;
256147088Sbrooks
257147088Sbrooks			/* adjust time for residence on the queue */
258147088Sbrooks			(void)gettimeofday(&otime, 0);
259147088Sbrooks			adj_msg_time(msg,&otime);
260157706Sbrooks#ifdef sgi
261157706Sbrooks			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
262157706Sbrooks			(void)cftime(olddate, "%D %T", &otime.tv_sec);
263157706Sbrooks#else
264157706Sbrooks			/*
265147088Sbrooks			 * the following line is necessary due to syslog
266147088Sbrooks			 * calling ctime() which clobbers the static buffer
267147088Sbrooks			 */
268147088Sbrooks			(void)strcpy(olddate, date());
269147088Sbrooks			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
270147088Sbrooks#endif /* sgi */
271147088Sbrooks
272147088Sbrooks			if (!good_host_name(msg->tsp_name)) {
273147088Sbrooks				syslog(LOG_NOTICE,
274149401Sbrooks			    "attempted time setting by untrusted %s to %s",
275149401Sbrooks				       msg->tsp_name, newdate);
276149401Sbrooks				suppress(&from, msg->tsp_name, fromnet);
277149401Sbrooks				break;
278149401Sbrooks			}
279197139Shrs
280149401Sbrooks			setmaster(msg);
281197139Shrs			timevalsub(&ntime, &msg->tsp_time, &otime);
282149401Sbrooks			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
283149401Sbrooks				/*
284149401Sbrooks				 * do not change the clock if we can adjust it
285149401Sbrooks				 */
286149401Sbrooks				synch(tvtomsround(ntime));
287149401Sbrooks			} else {
288149401Sbrooks#ifdef sgi
289197139Shrs				if (0 > settimeofday(&msg->tsp_time, 0)) {
290149401Sbrooks					syslog(LOG_ERR,"settimeofdate(): %m");
291149401Sbrooks					break;
292149401Sbrooks				}
293147088Sbrooks				logwtmp(&otime, &msg->tsp_time);
294147088Sbrooks#else
295147088Sbrooks				logwtmp("|", "date", "");
296147088Sbrooks				(void)settimeofday(&msg->tsp_time, 0);
297197139Shrs				logwtmp("}", "date", "");
298147088Sbrooks#endif /* sgi */
299197139Shrs				syslog(LOG_NOTICE,
300147088Sbrooks				       "date changed by %s from %s",
301147088Sbrooks					msg->tsp_name, olddate);
302147088Sbrooks				if (status & MASTER)
303147088Sbrooks					spreadtime();
304147088Sbrooks			}
305157706Sbrooks			(void)gettimeofday(&ntime, 0);
306157706Sbrooks			electiontime = ntime.tv_sec + delay2;
307157706Sbrooks			fastelection = ntime.tv_sec + FASTTOUT;
308157706Sbrooks
309157706Sbrooks/* This patches a bad protocol bug.  Imagine a system with several networks,
310157706Sbrooks * where there are a pair of redundant gateways between a pair of networks,
311147088Sbrooks * each running timed.  Assume that we start with a third machine mastering
312147088Sbrooks * one of the networks, and one of the gateways mastering the other.
313197139Shrs * Imagine that the third machine goes away and the non-master gateway
314147088Sbrooks * decides to replace it.  If things are timed just 'right,' we will have
315147088Sbrooks * each gateway mastering one network for a little while.  If a SETTIME
316147088Sbrooks * message gets into the network at that time, perhaps from the newly
317157706Sbrooks * masterful gateway as it was taking control, the SETTIME will loop
318157706Sbrooks * forever.  Each time a gateway receives it on its slave side, it will
319157706Sbrooks * call spreadtime to forward it on its mastered network.  We are now in
320157706Sbrooks * a permanent loop, since the SETTIME msgs will keep any clock
321157706Sbrooks * in the network from advancing.  Normally, the 'LOOP' stuff will detect
322197139Shrs * and correct the situation.  However, with the clocks stopped, the
323157706Sbrooks * 'looptime' timer cannot expire.  While they are in this state, the
324197139Shrs * masters will try to saturate the network with SETTIME packets.
325157706Sbrooks */
326157706Sbrooks			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
327157706Sbrooks			break;
328157706Sbrooks
329157706Sbrooks		case TSP_MASTERUP:
330157706Sbrooks			if (slavenet && fromnet != slavenet)
331157706Sbrooks				break;
332157706Sbrooks			if (!good_host_name(msg->tsp_name)) {
333157706Sbrooks				suppress(&from, msg->tsp_name, fromnet);
334157706Sbrooks				if (electiontime > fastelection)
335197139Shrs					electiontime = fastelection;
336197139Shrs				break;
337157706Sbrooks			}
338157706Sbrooks			makeslave(fromnet);
339147088Sbrooks			setmaster(msg);
340147088Sbrooks			setstatus();
341147088Sbrooks			answerdelay();
342147088Sbrooks			xmit(TSP_SLAVEUP, 0, &from);
343197139Shrs			(void)gettimeofday(&ntime, 0);
344147088Sbrooks			electiontime = ntime.tv_sec + delay2;
345197139Shrs			fastelection = ntime.tv_sec + FASTTOUT;
346147088Sbrooks			refusetime = 0;
347147088Sbrooks			break;
348147088Sbrooks
349147088Sbrooks		case TSP_MASTERREQ:
350147088Sbrooks			if (fromnet->status != SLAVE)
351147088Sbrooks				break;
352147088Sbrooks			(void)gettimeofday(&ntime, 0);
353197139Shrs			electiontime = ntime.tv_sec + delay2;
354147088Sbrooks			break;
355147088Sbrooks
356147088Sbrooks		case TSP_SETDATE:
357197139Shrs#ifdef sgi
358197139Shrs			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
359197139Shrs#else
360197139Shrs			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
361197139Shrs#endif /* sgi */
362197139Shrs			schgdate(msg, newdate);
363197139Shrs			break;
364197139Shrs
365197139Shrs		case TSP_SETDATEREQ:
366222996Shrs			if (fromnet->status != MASTER)
367222996Shrs				break;
368197139Shrs#ifdef sgi
369197697Shrs			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
370197697Shrs#else
371197697Shrs			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
372197697Shrs#endif /* sgi */
373197697Shrs			htp = findhost(msg->tsp_name);
374197697Shrs			if (0 == htp) {
375197697Shrs				syslog(LOG_WARNING,
376197697Shrs				       "DATEREQ from uncontrolled machine");
377197697Shrs				break;
378197697Shrs			}
379197139Shrs			if (!htp->good) {
380197139Shrs				syslog(LOG_WARNING,
381197139Shrs				"attempted date change by untrusted %s to %s",
382197139Shrs				       htp->name, newdate);
383197139Shrs				spreadtime();
384197139Shrs				break;
385212574Shrs			}
386212574Shrs			schgdate(msg, newdate);
387212574Shrs			break;
388212574Shrs
389212574Shrs		case TSP_TRACEON:
390212574Shrs			traceon();
391212574Shrs			break;
392212574Shrs
393212574Shrs		case TSP_TRACEOFF:
394212574Shrs			traceoff("Tracing ended at %s\n");
395212574Shrs			break;
396212574Shrs
397212574Shrs		case TSP_SLAVEUP:
398212577Shrs			newslave(msg);
399212574Shrs			break;
400212574Shrs
401212574Shrs		case TSP_ELECTION:
402212574Shrs			if (fromnet->status == SLAVE) {
403212574Shrs				(void)gettimeofday(&ntime, 0);
404212574Shrs				electiontime = ntime.tv_sec + delay2;
405212574Shrs				fastelection = ntime.tv_sec + FASTTOUT;
406212574Shrs				seq = 0;
407212574Shrs				if (!good_host_name(msg->tsp_name)) {
408212574Shrs					syslog(LOG_NOTICE,
409212574Shrs					       "suppress election of %s",
410212574Shrs					       msg->tsp_name);
411212574Shrs					to.tsp_type = TSP_QUIT;
412162490Sbrooks					electiontime = fastelection;
413162490Sbrooks				} else if (cadr.s_addr != from.sin_addr.s_addr
414162490Sbrooks					   && ntime.tv_sec < refusetime) {
415162490Sbrooks/* if the candidate has to repeat itself, the old code would refuse it
416162490Sbrooks * the second time.  That would prevent elections.
417212574Shrs */
418212574Shrs					to.tsp_type = TSP_REFUSE;
419212574Shrs				} else {
420197139Shrs					cadr.s_addr = from.sin_addr.s_addr;
421162490Sbrooks					to.tsp_type = TSP_ACCEPT;
422162490Sbrooks					refusetime = ntime.tv_sec + 30;
423197139Shrs				}
424197139Shrs				taddr = from;
425212574Shrs				(void)strcpy(tname, msg->tsp_name);
426197139Shrs				(void)strcpy(to.tsp_name, hostname);
427197139Shrs				answerdelay();
428197139Shrs				if (!acksend(&to, &taddr, tname,
429197139Shrs					     TSP_ACK, 0, 0))
430197139Shrs					syslog(LOG_WARNING,
431212574Shrs					     "no answer from candidate %s\n",
432212575Shrs					       tname);
433212575Shrs
434212575Shrs			} else {	/* fromnet->status == MASTER */
435212575Shrs				htp = addmach(msg->tsp_name, &from,fromnet);
436212575Shrs				to.tsp_type = TSP_QUIT;
437212575Shrs				(void)strcpy(to.tsp_name, hostname);
438197139Shrs				if (!acksend(&to, &htp->addr, htp->name,
439212575Shrs					     TSP_ACK, 0, htp->noanswer)) {
440212575Shrs					syslog(LOG_ERR,
441212575Shrs					  "no reply from %s to ELECTION-QUIT",
442212574Shrs					       htp->name);
443212574Shrs					(void)remmach(htp);
444212575Shrs				}
445212575Shrs			}
446197139Shrs			break;
447162490Sbrooks
448162490Sbrooks		case TSP_CONFLICT:
449162490Sbrooks			if (fromnet->status != MASTER)
450197139Shrs				break;
451197139Shrs			/*
452197139Shrs			 * After a network partition, there can be
453197139Shrs			 * more than one master: the first slave to
454197139Shrs			 * come up will notify here the situation.
455197139Shrs			 */
456197139Shrs			(void)strcpy(to.tsp_name, hostname);
457197139Shrs
458212577Shrs			/* The other master often gets into the same state,
459212577Shrs			 * with boring results.
460212577Shrs			 */
461212577Shrs			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
462212577Shrs			for (tries = 0; tries < 3; tries++) {
463212577Shrs				to.tsp_type = TSP_RESOLVE;
464197139Shrs				answer = acksend(&to, &ntp->dest_addr,
465212577Shrs						 ANYADDR, TSP_MASTERACK,
466212577Shrs						 ntp, 0);
467212574Shrs				if (answer == NULL)
468212574Shrs					break;
469212574Shrs				htp = addmach(answer->tsp_name,&from,ntp);
470212577Shrs				to.tsp_type = TSP_QUIT;
471212577Shrs				answer = acksend(&to, &htp->addr, htp->name,
472212577Shrs						 TSP_ACK, 0, htp->noanswer);
473197139Shrs				if (!answer) {
474197139Shrs					syslog(LOG_WARNING,
475197139Shrs				  "conflict error: no reply from %s to QUIT",
476197526Shrs						htp->name);
477197526Shrs					(void)remmach(htp);
478197526Shrs				}
479197526Shrs			}
480212574Shrs			masterup(ntp);
481212574Shrs			break;
482212577Shrs
483197526Shrs		case TSP_MSITE:
484212577Shrs			if (!slavenet)
485197526Shrs				break;
486197526Shrs			taddr = from;
487212574Shrs			to.tsp_type = TSP_MSITEREQ;
488212574Shrs			to.tsp_vers = TSPVERSION;
489212574Shrs			to.tsp_seq = 0;
490212574Shrs			(void)strcpy(to.tsp_name, hostname);
491212574Shrs			answer = acksend(&to, &slavenet->dest_addr,
492212574Shrs					 ANYADDR, TSP_ACK,
493212574Shrs					 slavenet, 0);
494212574Shrs			if (answer != NULL
495212574Shrs			    && good_host_name(answer->tsp_name)) {
496212574Shrs				setmaster(answer);
497212574Shrs				to.tsp_type = TSP_ACK;
498212574Shrs				(void)strcpy(to.tsp_name, answer->tsp_name);
499212574Shrs				bytenetorder(&to);
500212574Shrs				if (sendto(sock, (char *)&to,
501212574Shrs					   sizeof(struct tsp), 0,
502212574Shrs					   (struct sockaddr*)&taddr, sizeof(taddr)) < 0) {
503212574Shrs					trace_sendto_err(taddr.sin_addr);
504212574Shrs				}
505212574Shrs			}
506197139Shrs			break;
507197139Shrs
508197139Shrs		case TSP_MSITEREQ:
509161386Sbrooks			break;
510161386Sbrooks
511161386Sbrooks		case TSP_ACCEPT:
512161386Sbrooks		case TSP_REFUSE:
513197139Shrs		case TSP_RESOLVE:
514169889Sthompsa			break;
515161386Sbrooks
516161386Sbrooks		case TSP_QUIT:
517152441Sbrooks			doquit(msg);		/* become a slave */
518212578Shrs			break;
519152441Sbrooks
520152441Sbrooks		case TSP_TEST:
521197139Shrs			electiontime = 0;
522152441Sbrooks			break;
523197139Shrs
524197139Shrs		case TSP_LOOP:
525222515Sbz			/* looking for loops of masters */
526222515Sbz			if (!(status & MASTER))
527222515Sbz				break;
528222515Sbz			if (fromnet->status == SLAVE) {
529222515Sbz			    if (!strcmp(msg->tsp_name, hostname)) {
530222515Sbz				/*
531222515Sbz				 * Someone forwarded our message back to
532197139Shrs				 * us.  There must be a loop.  Tell the
533197139Shrs				 * master of this network to quit.
534197139Shrs				 *
535197139Shrs				 * The other master often gets into
536152441Sbrooks				 * the same state, with boring results.
537152441Sbrooks				 */
538197139Shrs				ntp = fromnet;
539197139Shrs				for (tries = 0; tries < 3; tries++) {
540197139Shrs				    to.tsp_type = TSP_RESOLVE;
541197139Shrs				    answer = acksend(&to, &ntp->dest_addr,
542197139Shrs						     ANYADDR, TSP_MASTERACK,
543197139Shrs						     ntp,0);
544197139Shrs				    if (answer == NULL)
545197139Shrs					break;
546197139Shrs				    taddr = from;
547197139Shrs				    (void)strcpy(tname, answer->tsp_name);
548197139Shrs				    to.tsp_type = TSP_QUIT;
549197139Shrs				    (void)strcpy(to.tsp_name, hostname);
550197139Shrs				    if (!acksend(&to, &taddr, tname,
551197139Shrs						 TSP_ACK, 0, 1)) {
552197139Shrs					syslog(LOG_ERR,
553197139Shrs					"no reply from %s to slave LOOP-QUIT",
554197139Shrs						 tname);
555197139Shrs				    } else {
556197139Shrs					electiontime = 0;
557197139Shrs				    }
558197139Shrs				}
559197139Shrs				(void)gettimeofday(&ntime, 0);
560197139Shrs				looptime = ntime.tv_sec + FASTTOUT;
561152441Sbrooks			    } else {
562197147Shrs				if (msg->tsp_hopcnt-- < 1)
563152441Sbrooks				    break;
564152441Sbrooks				bytenetorder(msg);
565197139Shrs				for (ntp = nettab; ntp != 0; ntp = ntp->next) {
566152441Sbrooks				    if (ntp->status == MASTER
567161386Sbrooks					&& 0 > sendto(sock, (char *)msg,
568161386Sbrooks						      sizeof(struct tsp), 0,
569161386Sbrooks					      (struct sockaddr*)&ntp->dest_addr,
570161386Sbrooks						      sizeof(ntp->dest_addr)))
571161386Sbrooks				    trace_sendto_err(ntp->dest_addr.sin_addr);
572161386Sbrooks				}
573161386Sbrooks			    }
574161386Sbrooks			} else {	/* fromnet->status == MASTER */
575161386Sbrooks			    /*
576161386Sbrooks			     * We should not have received this from a net
577161386Sbrooks			     * we are master on.  There must be two masters,
578161386Sbrooks			     * unless the packet was really from us.
579161386Sbrooks			     */
580161386Sbrooks			    if (from.sin_addr.s_addr
581161386Sbrooks				== fromnet->my_addr.s_addr) {
582161386Sbrooks				if (trace)
583161386Sbrooks				    fprintf(fd,"discarding forwarded LOOP\n");
584161386Sbrooks				break;
585161386Sbrooks			    }
586161386Sbrooks
587197139Shrs			    /*
588161386Sbrooks			     * The other master often gets into the same
589161386Sbrooks			     * state, with boring results.
590161386Sbrooks			     */
591152441Sbrooks			    ntp = fromnet;
592152441Sbrooks			    for (tries = 0; tries < 3; tries++) {
593197139Shrs				to.tsp_type = TSP_RESOLVE;
594197139Shrs				answer = acksend(&to, &ntp->dest_addr,
595197139Shrs						 ANYADDR, TSP_MASTERACK,
596197139Shrs						ntp,0);
597197139Shrs				if (!answer)
598197139Shrs					break;
599197139Shrs				htp = addmach(answer->tsp_name,
600197139Shrs					      &from,ntp);
601197139Shrs				to.tsp_type = TSP_QUIT;
602197139Shrs				(void)strcpy(to.tsp_name, hostname);
603197139Shrs				if (!acksend(&to,&htp->addr,htp->name,
604197139Shrs					     TSP_ACK, 0, htp->noanswer)) {
605197139Shrs					syslog(LOG_ERR,
606197139Shrs				    "no reply from %s to master LOOP-QUIT",
607197139Shrs					       htp->name);
608197139Shrs					(void)remmach(htp);
609197139Shrs				}
610197139Shrs			    }
611197139Shrs			    (void)gettimeofday(&ntime, 0);
612197139Shrs			    looptime = ntime.tv_sec + FASTTOUT;
613197139Shrs			}
614197139Shrs			break;
615197139Shrs		default:
616197139Shrs			if (trace) {
617197139Shrs				fprintf(fd, "garbage message: ");
618197139Shrs				print(msg, &from);
619197139Shrs			}
620197139Shrs			break;
621197139Shrs		}
622197139Shrs	}
623197139Shrs	goto loop;
624197139Shrs}
625197139Shrs
626197139Shrs
627197139Shrs/*
628197139Shrs * tell the world who our master is
629152441Sbrooks */
630197147Shrsstatic void
631197147Shrssetmaster(msg)
632152441Sbrooks	struct tsp *msg;
633197147Shrs{
634197139Shrs	if (slavenet
635212578Shrs	    && (slavenet != old_slavenet
636152441Sbrooks		|| strcmp(msg->tsp_name, master_name)
637152441Sbrooks		|| old_status != status)) {
638152441Sbrooks		(void)strcpy(master_name, msg->tsp_name);
639212578Shrs		old_slavenet = slavenet;
640152441Sbrooks		old_status = status;
641157706Sbrooks
642212578Shrs		if (status & MASTER) {
643152441Sbrooks			syslog(LOG_NOTICE, "submaster to %s", master_name);
644152441Sbrooks			if (trace)
645152441Sbrooks				fprintf(fd, "submaster to %s\n", master_name);
646152441Sbrooks
647152441Sbrooks		} else {
648152441Sbrooks			syslog(LOG_NOTICE, "slave to %s", master_name);
649152441Sbrooks			if (trace)
650152441Sbrooks				fprintf(fd, "slave to %s\n", master_name);
651152441Sbrooks		}
652152441Sbrooks	}
653152441Sbrooks}
654152441Sbrooks
655212578Shrs
656152441Sbrooks
657152441Sbrooks/*
658152441Sbrooks * handle date change request on a slave
659152441Sbrooks */
660152441Sbrooksstatic void
661152441Sbrooksschgdate(msg, newdate)
662152441Sbrooks	struct tsp *msg;
663152441Sbrooks	char *newdate;
664152441Sbrooks{
665152441Sbrooks	struct tsp to;
666152441Sbrooks	u_short seq;
667152441Sbrooks	struct sockaddr_in taddr;
668197139Shrs	struct timeval otime;
669152441Sbrooks
670152441Sbrooks	if (!slavenet)
671152441Sbrooks		return;			/* no where to forward */
672197139Shrs
673113674Smtm	taddr = from;
674113674Smtm	seq = msg->tsp_seq;
675113674Smtm
676113674Smtm	syslog(LOG_INFO,
677113674Smtm	       "forwarding date change by %s to %s",
678113674Smtm	       msg->tsp_name, newdate);
679197139Shrs
680113674Smtm	/* adjust time for residence on the queue */
681197139Shrs	(void)gettimeofday(&otime, 0);
682197139Shrs	adj_msg_time(msg, &otime);
683197139Shrs
684197139Shrs	to.tsp_type = TSP_SETDATEREQ;
685197139Shrs	to.tsp_time = msg->tsp_time;
686197139Shrs	(void)strcpy(to.tsp_name, hostname);
687197139Shrs	if (!acksend(&to, &slavenet->dest_addr,
688197139Shrs		     ANYADDR, TSP_DATEACK,
689197139Shrs		     slavenet, 0))
690197139Shrs		return;			/* no answer */
691197139Shrs
692197139Shrs	xmit(TSP_DATEACK, seq, &taddr);
693197139Shrs}
694197139Shrs
695197139Shrs
696197139Shrs/*
697197139Shrs * Used before answering a broadcast message to avoid network
698197139Shrs * contention and likely collisions.
699197139Shrs */
700197139Shrsstatic void
701197139Shrsanswerdelay()
702197139Shrs{
703113674Smtm#ifdef sgi
704113674Smtm	sginap(delay1);
705157706Sbrooks#else
706197139Shrs	struct timeval timeout;
707197139Shrs
708197139Shrs	timeout.tv_sec = 0;
709197139Shrs	timeout.tv_usec = delay1;
710197139Shrs
711197139Shrs	(void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
712197139Shrs	    &timeout);
713197139Shrs	return;
714197147Shrs#endif /* sgi */
715197139Shrs}
716197139Shrs