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
33 * @(#)slave.c 8.1 (Berkeley) 6/6/93
34 * $FreeBSD: src/usr.sbin/timed/timed/slave.c,v 1.7 1999/08/28 01:20:18 peter Exp $
35 * $DragonFly: src/usr.sbin/timed/timed/slave.c,v 1.3 2003/11/03 19:31:43 eirikn Exp $
40 #include "pathnames.h"
42 extern jmp_buf jmpenv;
46 extern u_short sequence;
48 static char master_name[MAXHOSTNAMELEN];
49 static struct netinfo *old_slavenet;
50 static int old_status;
52 static void schgdate(struct tsp *, char *);
53 static void setmaster(struct tsp *);
54 static void answerdelay(void);
57 extern void logwtmp(struct timeval *, struct timeval *);
59 extern void logwtmp(char *, char *, char *);
66 long electiontime, refusetime, looktime, looptime, adjtime;
72 struct sockaddr_in taddr;
73 char tname[MAXHOSTNAMELEN];
75 struct timeval ntime, wait;
90 (void)gettimeofday(&ntime, 0);
91 electiontime = ntime.tv_sec + delay2;
92 fastelection = ntime.tv_sec + FASTTOUT;
94 looktime = electiontime;
96 looktime = fastelection;
97 looptime = fastelection;
100 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
101 if (status & MASTER) {
102 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
103 if (ntp->status == MASTER)
110 (void)gettimeofday(&ntime, (struct timezone *)0);
111 if (ntime.tv_sec > electiontime) {
113 fprintf(fd, "election timer expired\n");
117 if (ntime.tv_sec >= looktime) {
119 fprintf(fd, "Looking for nets to master\n");
121 if (Mflag && nignorednets > 0) {
122 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
123 if (ntp->status == IGNORE
124 || ntp->status == NOMASTER) {
126 if (ntp->status == MASTER) {
128 } else if (ntp->status == MASTER) {
129 ntp->status = NOMASTER;
132 if (ntp->status == MASTER
133 && --ntp->quit_count < 0)
136 makeslave(slavenet); /* prune extras */
139 (void)gettimeofday(&ntime, 0);
140 looktime = ntime.tv_sec + delay2;
142 if (ntime.tv_sec >= looptime) {
144 fprintf(fd, "Looking for loops\n");
145 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
146 if (ntp->status == MASTER) {
147 to.tsp_type = TSP_LOOP;
148 to.tsp_vers = TSPVERSION;
149 to.tsp_seq = sequence++;
150 to.tsp_hopcnt = MAX_HOPCNT;
151 (void)strcpy(to.tsp_name, hostname);
153 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
154 (struct sockaddr*)&ntp->dest_addr,
155 sizeof(ntp->dest_addr)) < 0) {
156 trace_sendto_err(ntp->dest_addr.sin_addr);
160 (void)gettimeofday(&ntime, 0);
161 looptime = ntime.tv_sec + delay2;
164 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
167 wait.tv_sec += FASTTOUT;
169 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
173 * filter stuff not for us
175 switch (msg->tsp_type) {
180 * XXX check to see they are from ourself
191 fprintf(fd, "slave ignored: ");
200 || fromnet->status == IGNORE
201 || fromnet->status == NOMASTER) {
203 fprintf(fd, "slave ignored: ");
213 * now process the message
215 switch (msg->tsp_type) {
218 if (fromnet != slavenet)
220 if (!good_host_name(msg->tsp_name)) {
222 "attempted time adjustment by %s",
224 suppress(&from, msg->tsp_name, fromnet);
228 * Speed up loop detection in case we have a loop.
229 * Otherwise the clocks can race until the loop
232 (void)gettimeofday(&otime, 0);
233 if (adjtime < otime.tv_sec)
234 looptime -= (looptime-otime.tv_sec)/2 + 1;
237 if (seq != msg->tsp_seq) {
239 synch(tvtomsround(msg->tsp_time));
241 (void)gettimeofday(&ntime, 0);
242 electiontime = ntime.tv_sec + delay2;
243 fastelection = ntime.tv_sec + FASTTOUT;
244 adjtime = ntime.tv_sec + SAMPLEINTVL*2;
248 if (fromnet != slavenet)
250 if (seq == msg->tsp_seq)
254 /* adjust time for residence on the queue */
255 (void)gettimeofday(&otime, 0);
256 adj_msg_time(msg,&otime);
258 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
259 (void)cftime(olddate, "%D %T", &otime.tv_sec);
262 * the following line is necessary due to syslog
263 * calling ctime() which clobbers the static buffer
265 (void)strcpy(olddate, date());
266 tsp_time_sec = msg->tsp_time.tv_sec;
267 (void)strcpy(newdate, ctime(&tsp_time_sec));
270 if (!good_host_name(msg->tsp_name)) {
272 "attempted time setting by untrusted %s to %s",
273 msg->tsp_name, newdate);
274 suppress(&from, msg->tsp_name, fromnet);
279 timevalsub(&ntime, &msg->tsp_time, &otime);
280 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
282 * do not change the clock if we can adjust it
284 synch(tvtomsround(ntime));
287 if (0 > settimeofday(&msg->tsp_time, 0)) {
288 syslog(LOG_ERR,"settimeofdate(): %m");
291 logwtmp(&otime, &msg->tsp_time);
293 logwtmp("|", "date", "");
294 (void)settimeofday(&msg->tsp_time, 0);
295 logwtmp("{", "date", "");
298 "date changed by %s from %s",
299 msg->tsp_name, olddate);
303 (void)gettimeofday(&ntime, 0);
304 electiontime = ntime.tv_sec + delay2;
305 fastelection = ntime.tv_sec + FASTTOUT;
307 /* This patches a bad protocol bug. Imagine a system with several networks,
308 * where there are a pair of redundant gateways between a pair of networks,
309 * each running timed. Assume that we start with a third machine mastering
310 * one of the networks, and one of the gateways mastering the other.
311 * Imagine that the third machine goes away and the non-master gateway
312 * decides to replace it. If things are timed just 'right,' we will have
313 * each gateway mastering one network for a little while. If a SETTIME
314 * message gets into the network at that time, perhaps from the newly
315 * masterful gateway as it was taking control, the SETTIME will loop
316 * forever. Each time a gateway receives it on its slave side, it will
317 * call spreadtime to forward it on its mastered network. We are now in
318 * a permanent loop, since the SETTIME msgs will keep any clock
319 * in the network from advancing. Normally, the 'LOOP' stuff will detect
320 * and correct the situation. However, with the clocks stopped, the
321 * 'looptime' timer cannot expire. While they are in this state, the
322 * masters will try to saturate the network with SETTIME packets.
324 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
328 if (slavenet && fromnet != slavenet)
330 if (!good_host_name(msg->tsp_name)) {
331 suppress(&from, msg->tsp_name, fromnet);
332 if (electiontime > fastelection)
333 electiontime = fastelection;
340 xmit(TSP_SLAVEUP, 0, &from);
341 (void)gettimeofday(&ntime, 0);
342 electiontime = ntime.tv_sec + delay2;
343 fastelection = ntime.tv_sec + FASTTOUT;
348 if (fromnet->status != SLAVE)
350 (void)gettimeofday(&ntime, 0);
351 electiontime = ntime.tv_sec + delay2;
356 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
358 tsp_time_sec = msg->tsp_time.tv_sec;
359 (void)strcpy(newdate, ctime(&tsp_time_sec));
361 schgdate(msg, newdate);
365 if (fromnet->status != MASTER)
368 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
370 tsp_time_sec = msg->tsp_time.tv_sec;
371 (void)strcpy(newdate, ctime(&tsp_time_sec));
373 htp = findhost(msg->tsp_name);
376 "DATEREQ from uncontrolled machine");
381 "attempted date change by untrusted %s to %s",
386 schgdate(msg, newdate);
394 traceoff("Tracing ended at %s\n");
402 if (fromnet->status == SLAVE) {
403 (void)gettimeofday(&ntime, 0);
404 electiontime = ntime.tv_sec + delay2;
405 fastelection = ntime.tv_sec + FASTTOUT;
407 if (!good_host_name(msg->tsp_name)) {
409 "suppress election of %s",
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.
418 to.tsp_type = TSP_REFUSE;
420 cadr.s_addr = from.sin_addr.s_addr;
421 to.tsp_type = TSP_ACCEPT;
422 refusetime = ntime.tv_sec + 30;
425 (void)strcpy(tname, msg->tsp_name);
426 (void)strcpy(to.tsp_name, hostname);
428 if (!acksend(&to, &taddr, tname,
431 "no answer from candidate %s\n",
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)) {
441 "no reply from %s to ELECTION-QUIT",
449 if (fromnet->status != MASTER)
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.
456 (void)strcpy(to.tsp_name, hostname);
458 /* The other master often gets into the same state,
459 * with boring results.
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,
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);
475 "conflict error: no reply from %s to QUIT",
487 to.tsp_type = TSP_MSITEREQ;
488 to.tsp_vers = TSPVERSION;
490 (void)strcpy(to.tsp_name, hostname);
491 answer = acksend(&to, &slavenet->dest_addr,
495 && good_host_name(answer->tsp_name)) {
497 to.tsp_type = TSP_ACK;
498 (void)strcpy(to.tsp_name, answer->tsp_name);
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);
518 doquit(msg); /* become a slave */
526 /* looking for loops of masters */
527 if (!(status & MASTER))
529 if (fromnet->status == SLAVE) {
530 if (!strcmp(msg->tsp_name, hostname)) {
532 * Someone forwarded our message back to
533 * us. There must be a loop. Tell the
534 * master of this network to quit.
536 * The other master often gets into
537 * the same state, with boring results.
540 for (tries = 0; tries < 3; tries++) {
541 to.tsp_type = TSP_RESOLVE;
542 answer = acksend(&to, &ntp->dest_addr,
543 ANYADDR, TSP_MASTERACK,
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,
554 "no reply from %s to slave LOOP-QUIT",
560 (void)gettimeofday(&ntime, 0);
561 looptime = ntime.tv_sec + FASTTOUT;
563 if (msg->tsp_hopcnt-- < 1)
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);
575 } else { /* fromnet->status == MASTER */
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.
581 if (from.sin_addr.s_addr
582 == fromnet->my_addr.s_addr) {
584 fprintf(fd,"discarding forwarded LOOP\n");
589 * The other master often gets into the same
590 * state, with boring results.
593 for (tries = 0; tries < 3; tries++) {
594 to.tsp_type = TSP_RESOLVE;
595 answer = acksend(&to, &ntp->dest_addr,
596 ANYADDR, TSP_MASTERACK,
600 htp = addmach(answer->tsp_name,
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)) {
607 "no reply from %s to master LOOP-QUIT",
612 (void)gettimeofday(&ntime, 0);
613 looptime = ntime.tv_sec + FASTTOUT;
618 fprintf(fd, "garbage message: ");
629 * tell the world who our master is
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;
643 if (status & MASTER) {
644 syslog(LOG_NOTICE, "submaster to %s", master_name);
646 fprintf(fd, "submaster to %s\n", master_name);
649 syslog(LOG_NOTICE, "slave to %s", master_name);
651 fprintf(fd, "slave to %s\n", master_name);
659 * handle date change request on a slave
662 schgdate(msg, newdate)
668 struct sockaddr_in taddr;
669 struct timeval otime;
672 return; /* no where to forward */
678 "forwarding date change by %s to %s",
679 msg->tsp_name, newdate);
681 /* adjust time for residence on the queue */
682 (void)gettimeofday(&otime, 0);
683 adj_msg_time(msg, &otime);
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,
691 return; /* no answer */
693 xmit(TSP_DATEACK, seq, &taddr);
698 * Used before answering a broadcast message to avoid network
699 * contention and likely collisions.
707 struct timeval timeout;
710 timeout.tv_usec = delay1;
712 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,