2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93";
34 static const char rcsid[] =
41 #include "pathnames.h"
43 extern jmp_buf jmpenv;
47 extern u_short sequence;
49 static char master_name[MAXHOSTNAMELEN];
50 static struct netinfo *old_slavenet;
51 static int old_status;
53 static void schgdate(struct tsp *, char *);
54 static void setmaster(struct tsp *);
55 static void answerdelay(void);
61 long electiontime, refusetime, looktime, looptime, adjtime;
67 struct sockaddr_in taddr;
68 char tname[MAXHOSTNAMELEN];
70 struct timeval ntime, wait, tmptv;
86 (void)gettimeofday(&ntime, NULL);
87 electiontime = ntime.tv_sec + delay2;
88 fastelection = ntime.tv_sec + FASTTOUT;
90 looktime = electiontime;
92 looktime = fastelection;
93 looptime = fastelection;
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)
106 (void)gettimeofday(&ntime, NULL);
107 if (ntime.tv_sec > electiontime) {
109 fprintf(fd, "election timer expired\n");
113 if (ntime.tv_sec >= looktime) {
115 fprintf(fd, "Looking for nets to master\n");
117 if (Mflag && nignorednets > 0) {
118 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
119 if (ntp->status == IGNORE
120 || ntp->status == NOMASTER) {
122 if (ntp->status == MASTER) {
124 } else if (ntp->status == MASTER) {
125 ntp->status = NOMASTER;
128 if (ntp->status == MASTER
129 && --ntp->quit_count < 0)
132 makeslave(slavenet); /* prune extras */
135 (void)gettimeofday(&ntime, NULL);
136 looktime = ntime.tv_sec + delay2;
138 if (ntime.tv_sec >= looptime) {
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 (void)strcpy(to.tsp_name, hostname);
149 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
150 (struct sockaddr*)&ntp->dest_addr,
151 sizeof(ntp->dest_addr)) < 0) {
152 trace_sendto_err(ntp->dest_addr.sin_addr);
156 (void)gettimeofday(&ntime, NULL);
157 looptime = ntime.tv_sec + delay2;
160 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
163 wait.tv_sec += FASTTOUT;
165 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
169 * filter stuff not for us
171 switch (msg->tsp_type) {
176 * XXX check to see they are from ourself
187 fprintf(fd, "slave ignored: ");
196 || fromnet->status == IGNORE
197 || fromnet->status == NOMASTER) {
199 fprintf(fd, "slave ignored: ");
209 * now process the message
211 switch (msg->tsp_type) {
214 if (fromnet != slavenet)
216 if (!good_host_name(msg->tsp_name)) {
218 "attempted time adjustment by %s",
220 suppress(&from, msg->tsp_name, fromnet);
224 * Speed up loop detection in case we have a loop.
225 * Otherwise the clocks can race until the loop
228 (void)gettimeofday(&otime, NULL);
229 if (adjtime < otime.tv_sec)
230 looptime -= (looptime-otime.tv_sec)/2 + 1;
233 if (seq != msg->tsp_seq) {
235 synch(tvtomsround(msg->tsp_time));
237 (void)gettimeofday(&ntime, NULL);
238 electiontime = ntime.tv_sec + delay2;
239 fastelection = ntime.tv_sec + FASTTOUT;
240 adjtime = ntime.tv_sec + SAMPLEINTVL*2;
244 if (fromnet != slavenet)
246 if (seq == msg->tsp_seq)
250 /* adjust time for residence on the queue */
251 (void)gettimeofday(&otime, NULL);
252 adj_msg_time(msg,&otime);
254 * the following line is necessary due to syslog
255 * calling ctime() which clobbers the static buffer
257 (void)strcpy(olddate, date());
258 tsp_time_sec = msg->tsp_time.tv_sec;
259 (void)strcpy(newdate, ctime(&tsp_time_sec));
261 if (!good_host_name(msg->tsp_name)) {
263 "attempted time setting by untrusted %s to %s",
264 msg->tsp_name, newdate);
265 suppress(&from, msg->tsp_name, fromnet);
270 tmptv.tv_sec = msg->tsp_time.tv_sec;
271 tmptv.tv_usec = msg->tsp_time.tv_usec;
272 timevalsub(&ntime, &tmptv, &otime);
273 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
275 * do not change the clock if we can adjust it
277 synch(tvtomsround(ntime));
279 utx.ut_type = OLD_TIME;
280 gettimeofday(&utx.ut_tv, NULL);
282 (void)settimeofday(&tmptv, 0);
283 utx.ut_type = NEW_TIME;
284 gettimeofday(&utx.ut_tv, NULL);
287 "date changed by %s from %s",
288 msg->tsp_name, olddate);
292 (void)gettimeofday(&ntime, NULL);
293 electiontime = ntime.tv_sec + delay2;
294 fastelection = ntime.tv_sec + FASTTOUT;
296 /* This patches a bad protocol bug. Imagine a system with several networks,
297 * where there are a pair of redundant gateways between a pair of networks,
298 * each running timed. Assume that we start with a third machine mastering
299 * one of the networks, and one of the gateways mastering the other.
300 * Imagine that the third machine goes away and the non-master gateway
301 * decides to replace it. If things are timed just 'right,' we will have
302 * each gateway mastering one network for a little while. If a SETTIME
303 * message gets into the network at that time, perhaps from the newly
304 * masterful gateway as it was taking control, the SETTIME will loop
305 * forever. Each time a gateway receives it on its slave side, it will
306 * call spreadtime to forward it on its mastered network. We are now in
307 * a permanent loop, since the SETTIME msgs will keep any clock
308 * in the network from advancing. Normally, the 'LOOP' stuff will detect
309 * and correct the situation. However, with the clocks stopped, the
310 * 'looptime' timer cannot expire. While they are in this state, the
311 * masters will try to saturate the network with SETTIME packets.
313 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
317 if (slavenet && fromnet != slavenet)
319 if (!good_host_name(msg->tsp_name)) {
320 suppress(&from, msg->tsp_name, fromnet);
321 if (electiontime > fastelection)
322 electiontime = fastelection;
329 xmit(TSP_SLAVEUP, 0, &from);
330 (void)gettimeofday(&ntime, NULL);
331 electiontime = ntime.tv_sec + delay2;
332 fastelection = ntime.tv_sec + FASTTOUT;
337 if (fromnet->status != SLAVE)
339 (void)gettimeofday(&ntime, NULL);
340 electiontime = ntime.tv_sec + delay2;
344 tsp_time_sec = msg->tsp_time.tv_sec;
345 (void)strcpy(newdate, ctime(&tsp_time_sec));
346 schgdate(msg, newdate);
350 if (fromnet->status != MASTER)
352 tsp_time_sec = msg->tsp_time.tv_sec;
353 (void)strcpy(newdate, ctime(&tsp_time_sec));
354 htp = findhost(msg->tsp_name);
357 "DATEREQ from uncontrolled machine");
362 "attempted date change by untrusted %s to %s",
367 schgdate(msg, newdate);
375 traceoff("Tracing ended at %s\n");
383 if (fromnet->status == SLAVE) {
384 (void)gettimeofday(&ntime, NULL);
385 electiontime = ntime.tv_sec + delay2;
386 fastelection = ntime.tv_sec + FASTTOUT;
388 if (!good_host_name(msg->tsp_name)) {
390 "suppress election of %s",
392 to.tsp_type = TSP_QUIT;
393 electiontime = fastelection;
394 } else if (cadr.s_addr != from.sin_addr.s_addr
395 && ntime.tv_sec < refusetime) {
396 /* if the candidate has to repeat itself, the old code would refuse it
397 * the second time. That would prevent elections.
399 to.tsp_type = TSP_REFUSE;
401 cadr.s_addr = from.sin_addr.s_addr;
402 to.tsp_type = TSP_ACCEPT;
403 refusetime = ntime.tv_sec + 30;
406 (void)strcpy(tname, msg->tsp_name);
407 (void)strcpy(to.tsp_name, hostname);
409 if (!acksend(&to, &taddr, tname,
412 "no answer from candidate %s\n",
415 } else { /* fromnet->status == MASTER */
416 htp = addmach(msg->tsp_name, &from,fromnet);
417 to.tsp_type = TSP_QUIT;
418 (void)strcpy(to.tsp_name, hostname);
419 if (!acksend(&to, &htp->addr, htp->name,
420 TSP_ACK, 0, htp->noanswer)) {
422 "no reply from %s to ELECTION-QUIT",
430 if (fromnet->status != MASTER)
433 * After a network partition, there can be
434 * more than one master: the first slave to
435 * come up will notify here the situation.
437 (void)strcpy(to.tsp_name, hostname);
439 /* The other master often gets into the same state,
440 * with boring results.
442 ntp = fromnet; /* (acksend() can leave fromnet=0 */
443 for (tries = 0; tries < 3; tries++) {
444 to.tsp_type = TSP_RESOLVE;
445 answer = acksend(&to, &ntp->dest_addr,
446 ANYADDR, TSP_MASTERACK,
450 htp = addmach(answer->tsp_name,&from,ntp);
451 to.tsp_type = TSP_QUIT;
452 answer = acksend(&to, &htp->addr, htp->name,
453 TSP_ACK, 0, htp->noanswer);
456 "conflict error: no reply from %s to QUIT",
468 to.tsp_type = TSP_MSITEREQ;
469 to.tsp_vers = TSPVERSION;
471 (void)strcpy(to.tsp_name, hostname);
472 answer = acksend(&to, &slavenet->dest_addr,
476 && good_host_name(answer->tsp_name)) {
478 to.tsp_type = TSP_ACK;
479 (void)strcpy(to.tsp_name, answer->tsp_name);
481 if (sendto(sock, (char *)&to,
482 sizeof(struct tsp), 0,
483 (struct sockaddr*)&taddr,
484 sizeof(taddr)) < 0) {
485 trace_sendto_err(taddr.sin_addr);
499 doquit(msg); /* become a slave */
507 /* looking for loops of masters */
508 if (!(status & MASTER))
510 if (fromnet->status == SLAVE) {
511 if (!strcmp(msg->tsp_name, hostname)) {
513 * Someone forwarded our message back to
514 * us. There must be a loop. Tell the
515 * master of this network to quit.
517 * The other master often gets into
518 * the same state, with boring results.
521 for (tries = 0; tries < 3; tries++) {
522 to.tsp_type = TSP_RESOLVE;
523 answer = acksend(&to, &ntp->dest_addr,
524 ANYADDR, TSP_MASTERACK,
529 (void)strcpy(tname, answer->tsp_name);
530 to.tsp_type = TSP_QUIT;
531 (void)strcpy(to.tsp_name, hostname);
532 if (!acksend(&to, &taddr, tname,
535 "no reply from %s to slave LOOP-QUIT",
541 (void)gettimeofday(&ntime, NULL);
542 looptime = ntime.tv_sec + FASTTOUT;
544 if (msg->tsp_hopcnt-- < 1)
547 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
548 if (ntp->status == MASTER
549 && 0 > sendto(sock, (char *)msg,
550 sizeof(struct tsp), 0,
551 (struct sockaddr*)&ntp->dest_addr,
552 sizeof(ntp->dest_addr)))
553 trace_sendto_err(ntp->dest_addr.sin_addr);
556 } else { /* fromnet->status == MASTER */
558 * We should not have received this from a net
559 * we are master on. There must be two masters,
560 * unless the packet was really from us.
562 if (from.sin_addr.s_addr
563 == fromnet->my_addr.s_addr) {
565 fprintf(fd,"discarding forwarded LOOP\n");
570 * The other master often gets into the same
571 * state, with boring results.
574 for (tries = 0; tries < 3; tries++) {
575 to.tsp_type = TSP_RESOLVE;
576 answer = acksend(&to, &ntp->dest_addr,
577 ANYADDR, TSP_MASTERACK,
581 htp = addmach(answer->tsp_name,
583 to.tsp_type = TSP_QUIT;
584 (void)strcpy(to.tsp_name, hostname);
585 if (!acksend(&to,&htp->addr,htp->name,
586 TSP_ACK, 0, htp->noanswer)) {
588 "no reply from %s to master LOOP-QUIT",
593 (void)gettimeofday(&ntime, NULL);
594 looptime = ntime.tv_sec + FASTTOUT;
599 fprintf(fd, "garbage message: ");
610 * tell the world who our master is
613 setmaster(struct tsp *msg)
616 && (slavenet != old_slavenet
617 || strcmp(msg->tsp_name, master_name)
618 || old_status != status)) {
619 (void)strcpy(master_name, msg->tsp_name);
620 old_slavenet = slavenet;
623 if (status & MASTER) {
624 syslog(LOG_NOTICE, "submaster to %s", master_name);
626 fprintf(fd, "submaster to %s\n", master_name);
629 syslog(LOG_NOTICE, "slave to %s", master_name);
631 fprintf(fd, "slave to %s\n", master_name);
639 * handle date change request on a slave
642 schgdate(struct tsp *msg, char *newdate)
646 struct sockaddr_in taddr;
647 struct timeval otime;
650 return; /* no where to forward */
656 "forwarding date change by %s to %s",
657 msg->tsp_name, newdate);
659 /* adjust time for residence on the queue */
660 (void)gettimeofday(&otime, NULL);
661 adj_msg_time(msg, &otime);
663 to.tsp_type = TSP_SETDATEREQ;
664 to.tsp_time = msg->tsp_time;
665 (void)strcpy(to.tsp_name, hostname);
666 if (!acksend(&to, &slavenet->dest_addr,
667 ANYADDR, TSP_DATEACK,
669 return; /* no answer */
671 xmit(TSP_DATEACK, seq, &taddr);
676 * Used before answering a broadcast message to avoid network
677 * contention and likely collisions.
682 struct timeval timeout;
685 timeout.tv_usec = delay1;
687 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,