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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93";
38 static const char rcsid[] =
39 "$FreeBSD: src/usr.sbin/timed/timed/slave.c,v 1.7 1999/08/28 01:20:18 peter Exp $";
44 #include "pathnames.h"
46 extern jmp_buf jmpenv;
50 extern u_short sequence;
52 static char master_name[MAXHOSTNAMELEN];
53 static struct netinfo *old_slavenet;
54 static int old_status;
56 static void schgdate __P((struct tsp *, char *));
57 static void setmaster __P((struct tsp *));
58 static void answerdelay __P((void));
61 extern void logwtmp __P((struct timeval *, struct timeval *));
63 extern void logwtmp __P((char *, char *, char *));
70 long electiontime, refusetime, looktime, looptime, adjtime;
76 struct sockaddr_in taddr;
77 char tname[MAXHOSTNAMELEN];
79 struct timeval ntime, wait;
94 (void)gettimeofday(&ntime, 0);
95 electiontime = ntime.tv_sec + delay2;
96 fastelection = ntime.tv_sec + FASTTOUT;
98 looktime = electiontime;
100 looktime = fastelection;
101 looptime = fastelection;
104 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
105 if (status & MASTER) {
106 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
107 if (ntp->status == MASTER)
114 (void)gettimeofday(&ntime, (struct timezone *)0);
115 if (ntime.tv_sec > electiontime) {
117 fprintf(fd, "election timer expired\n");
121 if (ntime.tv_sec >= looktime) {
123 fprintf(fd, "Looking for nets to master\n");
125 if (Mflag && nignorednets > 0) {
126 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
127 if (ntp->status == IGNORE
128 || ntp->status == NOMASTER) {
130 if (ntp->status == MASTER) {
132 } else if (ntp->status == MASTER) {
133 ntp->status = NOMASTER;
136 if (ntp->status == MASTER
137 && --ntp->quit_count < 0)
140 makeslave(slavenet); /* prune extras */
143 (void)gettimeofday(&ntime, 0);
144 looktime = ntime.tv_sec + delay2;
146 if (ntime.tv_sec >= looptime) {
148 fprintf(fd, "Looking for loops\n");
149 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
150 if (ntp->status == MASTER) {
151 to.tsp_type = TSP_LOOP;
152 to.tsp_vers = TSPVERSION;
153 to.tsp_seq = sequence++;
154 to.tsp_hopcnt = MAX_HOPCNT;
155 (void)strcpy(to.tsp_name, hostname);
157 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
158 (struct sockaddr*)&ntp->dest_addr,
159 sizeof(ntp->dest_addr)) < 0) {
160 trace_sendto_err(ntp->dest_addr.sin_addr);
164 (void)gettimeofday(&ntime, 0);
165 looptime = ntime.tv_sec + delay2;
168 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
171 wait.tv_sec += FASTTOUT;
173 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
177 * filter stuff not for us
179 switch (msg->tsp_type) {
184 * XXX check to see they are from ourself
195 fprintf(fd, "slave ignored: ");
204 || fromnet->status == IGNORE
205 || fromnet->status == NOMASTER) {
207 fprintf(fd, "slave ignored: ");
217 * now process the message
219 switch (msg->tsp_type) {
222 if (fromnet != slavenet)
224 if (!good_host_name(msg->tsp_name)) {
226 "attempted time adjustment by %s",
228 suppress(&from, msg->tsp_name, fromnet);
232 * Speed up loop detection in case we have a loop.
233 * Otherwise the clocks can race until the loop
236 (void)gettimeofday(&otime, 0);
237 if (adjtime < otime.tv_sec)
238 looptime -= (looptime-otime.tv_sec)/2 + 1;
241 if (seq != msg->tsp_seq) {
243 synch(tvtomsround(msg->tsp_time));
245 (void)gettimeofday(&ntime, 0);
246 electiontime = ntime.tv_sec + delay2;
247 fastelection = ntime.tv_sec + FASTTOUT;
248 adjtime = ntime.tv_sec + SAMPLEINTVL*2;
252 if (fromnet != slavenet)
254 if (seq == msg->tsp_seq)
258 /* adjust time for residence on the queue */
259 (void)gettimeofday(&otime, 0);
260 adj_msg_time(msg,&otime);
262 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
263 (void)cftime(olddate, "%D %T", &otime.tv_sec);
266 * the following line is necessary due to syslog
267 * calling ctime() which clobbers the static buffer
269 (void)strcpy(olddate, date());
270 tsp_time_sec = msg->tsp_time.tv_sec;
271 (void)strcpy(newdate, ctime(&tsp_time_sec));
274 if (!good_host_name(msg->tsp_name)) {
276 "attempted time setting by untrusted %s to %s",
277 msg->tsp_name, newdate);
278 suppress(&from, msg->tsp_name, fromnet);
283 timevalsub(&ntime, &msg->tsp_time, &otime);
284 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
286 * do not change the clock if we can adjust it
288 synch(tvtomsround(ntime));
291 if (0 > settimeofday(&msg->tsp_time, 0)) {
292 syslog(LOG_ERR,"settimeofdate(): %m");
295 logwtmp(&otime, &msg->tsp_time);
297 logwtmp("|", "date", "");
298 (void)settimeofday(&msg->tsp_time, 0);
299 logwtmp("{", "date", "");
302 "date changed by %s from %s",
303 msg->tsp_name, olddate);
307 (void)gettimeofday(&ntime, 0);
308 electiontime = ntime.tv_sec + delay2;
309 fastelection = ntime.tv_sec + FASTTOUT;
311 /* This patches a bad protocol bug. Imagine a system with several networks,
312 * where there are a pair of redundant gateways between a pair of networks,
313 * each running timed. Assume that we start with a third machine mastering
314 * one of the networks, and one of the gateways mastering the other.
315 * Imagine that the third machine goes away and the non-master gateway
316 * decides to replace it. If things are timed just 'right,' we will have
317 * each gateway mastering one network for a little while. If a SETTIME
318 * message gets into the network at that time, perhaps from the newly
319 * masterful gateway as it was taking control, the SETTIME will loop
320 * forever. Each time a gateway receives it on its slave side, it will
321 * call spreadtime to forward it on its mastered network. We are now in
322 * a permanent loop, since the SETTIME msgs will keep any clock
323 * in the network from advancing. Normally, the 'LOOP' stuff will detect
324 * and correct the situation. However, with the clocks stopped, the
325 * 'looptime' timer cannot expire. While they are in this state, the
326 * masters will try to saturate the network with SETTIME packets.
328 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
332 if (slavenet && fromnet != slavenet)
334 if (!good_host_name(msg->tsp_name)) {
335 suppress(&from, msg->tsp_name, fromnet);
336 if (electiontime > fastelection)
337 electiontime = fastelection;
344 xmit(TSP_SLAVEUP, 0, &from);
345 (void)gettimeofday(&ntime, 0);
346 electiontime = ntime.tv_sec + delay2;
347 fastelection = ntime.tv_sec + FASTTOUT;
352 if (fromnet->status != SLAVE)
354 (void)gettimeofday(&ntime, 0);
355 electiontime = ntime.tv_sec + delay2;
360 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
362 tsp_time_sec = msg->tsp_time.tv_sec;
363 (void)strcpy(newdate, ctime(&tsp_time_sec));
365 schgdate(msg, newdate);
369 if (fromnet->status != MASTER)
372 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
374 tsp_time_sec = msg->tsp_time.tv_sec;
375 (void)strcpy(newdate, ctime(&tsp_time_sec));
377 htp = findhost(msg->tsp_name);
380 "DATEREQ from uncontrolled machine");
385 "attempted date change by untrusted %s to %s",
390 schgdate(msg, newdate);
398 traceoff("Tracing ended at %s\n");
406 if (fromnet->status == SLAVE) {
407 (void)gettimeofday(&ntime, 0);
408 electiontime = ntime.tv_sec + delay2;
409 fastelection = ntime.tv_sec + FASTTOUT;
411 if (!good_host_name(msg->tsp_name)) {
413 "suppress election of %s",
415 to.tsp_type = TSP_QUIT;
416 electiontime = fastelection;
417 } else if (cadr.s_addr != from.sin_addr.s_addr
418 && ntime.tv_sec < refusetime) {
419 /* if the candidate has to repeat itself, the old code would refuse it
420 * the second time. That would prevent elections.
422 to.tsp_type = TSP_REFUSE;
424 cadr.s_addr = from.sin_addr.s_addr;
425 to.tsp_type = TSP_ACCEPT;
426 refusetime = ntime.tv_sec + 30;
429 (void)strcpy(tname, msg->tsp_name);
430 (void)strcpy(to.tsp_name, hostname);
432 if (!acksend(&to, &taddr, tname,
435 "no answer from candidate %s\n",
438 } else { /* fromnet->status == MASTER */
439 htp = addmach(msg->tsp_name, &from,fromnet);
440 to.tsp_type = TSP_QUIT;
441 (void)strcpy(to.tsp_name, hostname);
442 if (!acksend(&to, &htp->addr, htp->name,
443 TSP_ACK, 0, htp->noanswer)) {
445 "no reply from %s to ELECTION-QUIT",
453 if (fromnet->status != MASTER)
456 * After a network partition, there can be
457 * more than one master: the first slave to
458 * come up will notify here the situation.
460 (void)strcpy(to.tsp_name, hostname);
462 /* The other master often gets into the same state,
463 * with boring results.
465 ntp = fromnet; /* (acksend() can leave fromnet=0 */
466 for (tries = 0; tries < 3; tries++) {
467 to.tsp_type = TSP_RESOLVE;
468 answer = acksend(&to, &ntp->dest_addr,
469 ANYADDR, TSP_MASTERACK,
473 htp = addmach(answer->tsp_name,&from,ntp);
474 to.tsp_type = TSP_QUIT;
475 answer = acksend(&to, &htp->addr, htp->name,
476 TSP_ACK, 0, htp->noanswer);
479 "conflict error: no reply from %s to QUIT",
491 to.tsp_type = TSP_MSITEREQ;
492 to.tsp_vers = TSPVERSION;
494 (void)strcpy(to.tsp_name, hostname);
495 answer = acksend(&to, &slavenet->dest_addr,
499 && good_host_name(answer->tsp_name)) {
501 to.tsp_type = TSP_ACK;
502 (void)strcpy(to.tsp_name, answer->tsp_name);
504 if (sendto(sock, (char *)&to,
505 sizeof(struct tsp), 0,
506 (struct sockaddr*)&taddr,
507 sizeof(taddr)) < 0) {
508 trace_sendto_err(taddr.sin_addr);
522 doquit(msg); /* become a slave */
530 /* looking for loops of masters */
531 if (!(status & MASTER))
533 if (fromnet->status == SLAVE) {
534 if (!strcmp(msg->tsp_name, hostname)) {
536 * Someone forwarded our message back to
537 * us. There must be a loop. Tell the
538 * master of this network to quit.
540 * The other master often gets into
541 * the same state, with boring results.
544 for (tries = 0; tries < 3; tries++) {
545 to.tsp_type = TSP_RESOLVE;
546 answer = acksend(&to, &ntp->dest_addr,
547 ANYADDR, TSP_MASTERACK,
552 (void)strcpy(tname, answer->tsp_name);
553 to.tsp_type = TSP_QUIT;
554 (void)strcpy(to.tsp_name, hostname);
555 if (!acksend(&to, &taddr, tname,
558 "no reply from %s to slave LOOP-QUIT",
564 (void)gettimeofday(&ntime, 0);
565 looptime = ntime.tv_sec + FASTTOUT;
567 if (msg->tsp_hopcnt-- < 1)
570 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
571 if (ntp->status == MASTER
572 && 0 > sendto(sock, (char *)msg,
573 sizeof(struct tsp), 0,
574 (struct sockaddr*)&ntp->dest_addr,
575 sizeof(ntp->dest_addr)))
576 trace_sendto_err(ntp->dest_addr.sin_addr);
579 } else { /* fromnet->status == MASTER */
581 * We should not have received this from a net
582 * we are master on. There must be two masters,
583 * unless the packet was really from us.
585 if (from.sin_addr.s_addr
586 == fromnet->my_addr.s_addr) {
588 fprintf(fd,"discarding forwarded LOOP\n");
593 * The other master often gets into the same
594 * state, with boring results.
597 for (tries = 0; tries < 3; tries++) {
598 to.tsp_type = TSP_RESOLVE;
599 answer = acksend(&to, &ntp->dest_addr,
600 ANYADDR, TSP_MASTERACK,
604 htp = addmach(answer->tsp_name,
606 to.tsp_type = TSP_QUIT;
607 (void)strcpy(to.tsp_name, hostname);
608 if (!acksend(&to,&htp->addr,htp->name,
609 TSP_ACK, 0, htp->noanswer)) {
611 "no reply from %s to master LOOP-QUIT",
616 (void)gettimeofday(&ntime, 0);
617 looptime = ntime.tv_sec + FASTTOUT;
622 fprintf(fd, "garbage message: ");
633 * tell the world who our master is
640 && (slavenet != old_slavenet
641 || strcmp(msg->tsp_name, master_name)
642 || old_status != status)) {
643 (void)strcpy(master_name, msg->tsp_name);
644 old_slavenet = slavenet;
647 if (status & MASTER) {
648 syslog(LOG_NOTICE, "submaster to %s", master_name);
650 fprintf(fd, "submaster to %s\n", master_name);
653 syslog(LOG_NOTICE, "slave to %s", master_name);
655 fprintf(fd, "slave to %s\n", master_name);
663 * handle date change request on a slave
666 schgdate(msg, newdate)
672 struct sockaddr_in taddr;
673 struct timeval otime;
676 return; /* no where to forward */
682 "forwarding date change by %s to %s",
683 msg->tsp_name, newdate);
685 /* adjust time for residence on the queue */
686 (void)gettimeofday(&otime, 0);
687 adj_msg_time(msg, &otime);
689 to.tsp_type = TSP_SETDATEREQ;
690 to.tsp_time = msg->tsp_time;
691 (void)strcpy(to.tsp_name, hostname);
692 if (!acksend(&to, &slavenet->dest_addr,
693 ANYADDR, TSP_DATEACK,
695 return; /* no answer */
697 xmit(TSP_DATEACK, seq, &taddr);
702 * Used before answering a broadcast message to avoid network
703 * contention and likely collisions.
711 struct timeval timeout;
714 timeout.tv_usec = delay1;
716 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,