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.9 2004/09/05 02:20:15 dillon 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);
60 long electiontime, refusetime, looktime, looptime, adjusttime;
66 struct sockaddr_in taddr;
67 char tname[MAXHOSTNAMELEN];
69 struct timeval ntime, wait;
83 gettimeofday(&ntime, 0);
84 electiontime = ntime.tv_sec + delay2;
85 fastelection = ntime.tv_sec + FASTTOUT;
87 looktime = electiontime;
89 looktime = fastelection;
90 looptime = fastelection;
93 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
94 if (status & MASTER) {
95 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
96 if (ntp->status == MASTER)
103 gettimeofday(&ntime, (struct timezone *)0);
104 if (ntime.tv_sec > electiontime) {
106 fprintf(fd, "election timer expired\n");
110 if (ntime.tv_sec >= looktime) {
112 fprintf(fd, "Looking for nets to master\n");
114 if (Mflag && nignorednets > 0) {
115 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
116 if (ntp->status == IGNORE
117 || ntp->status == NOMASTER) {
119 if (ntp->status == MASTER) {
121 } else if (ntp->status == MASTER) {
122 ntp->status = NOMASTER;
125 if (ntp->status == MASTER
126 && --ntp->quit_count < 0)
129 makeslave(slavenet); /* prune extras */
132 gettimeofday(&ntime, 0);
133 looktime = ntime.tv_sec + delay2;
135 if (ntime.tv_sec >= looptime) {
137 fprintf(fd, "Looking for loops\n");
138 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
139 if (ntp->status == MASTER) {
140 to.tsp_type = TSP_LOOP;
141 to.tsp_vers = TSPVERSION;
142 to.tsp_seq = sequence++;
143 to.tsp_hopcnt = MAX_HOPCNT;
144 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
146 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
147 (struct sockaddr*)&ntp->dest_addr,
148 sizeof(ntp->dest_addr)) < 0) {
149 trace_sendto_err(ntp->dest_addr.sin_addr);
153 gettimeofday(&ntime, 0);
154 looptime = ntime.tv_sec + delay2;
157 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
160 wait.tv_sec += FASTTOUT;
162 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
166 * filter stuff not for us
168 switch (msg->tsp_type) {
173 * XXX check to see they are from ourself
184 fprintf(fd, "slave ignored: ");
193 || fromnet->status == IGNORE
194 || fromnet->status == NOMASTER) {
196 fprintf(fd, "slave ignored: ");
206 * now process the message
208 switch (msg->tsp_type) {
211 if (fromnet != slavenet)
213 if (!good_host_name(msg->tsp_name)) {
215 "attempted time adjustment by %s",
217 suppress(&from, msg->tsp_name, fromnet);
221 * Speed up loop detection in case we have a loop.
222 * Otherwise the clocks can race until the loop
225 gettimeofday(&otime, 0);
226 if (adjusttime < otime.tv_sec)
227 looptime -= (looptime-otime.tv_sec)/2 + 1;
230 if (seq != msg->tsp_seq) {
232 synch(tvtomsround(msg->tsp_time));
234 gettimeofday(&ntime, 0);
235 electiontime = ntime.tv_sec + delay2;
236 fastelection = ntime.tv_sec + FASTTOUT;
237 adjusttime = ntime.tv_sec + SAMPLEINTVL*2;
241 if (fromnet != slavenet)
243 if (seq == msg->tsp_seq)
247 /* adjust time for residence on the queue */
248 gettimeofday(&otime, 0);
249 adj_msg_time(msg,&otime);
252 * the following line is necessary due to syslog
253 * calling ctime() which clobbers the static buffer
255 strlcpy(olddate, date(), sizeof(olddate));
256 tsp_time_sec = msg->tsp_time.tv_sec;
257 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
259 if (!good_host_name(msg->tsp_name)) {
261 "attempted time setting by untrusted %s to %s",
262 msg->tsp_name, newdate);
263 suppress(&from, msg->tsp_name, fromnet);
268 timevalsub(&ntime, &msg->tsp_time, &otime);
269 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
271 * do not change the clock if we can adjust it
273 synch(tvtomsround(ntime));
275 logwtmp("|", "date", "");
276 settimeofday(&msg->tsp_time, 0);
277 logwtmp("{", "date", "");
279 "date changed by %s from %s",
280 msg->tsp_name, olddate);
284 gettimeofday(&ntime, 0);
285 electiontime = ntime.tv_sec + delay2;
286 fastelection = ntime.tv_sec + FASTTOUT;
288 /* This patches a bad protocol bug. Imagine a system with several networks,
289 * where there are a pair of redundant gateways between a pair of networks,
290 * each running timed. Assume that we start with a third machine mastering
291 * one of the networks, and one of the gateways mastering the other.
292 * Imagine that the third machine goes away and the non-master gateway
293 * decides to replace it. If things are timed just 'right,' we will have
294 * each gateway mastering one network for a little while. If a SETTIME
295 * message gets into the network at that time, perhaps from the newly
296 * masterful gateway as it was taking control, the SETTIME will loop
297 * forever. Each time a gateway receives it on its slave side, it will
298 * call spreadtime to forward it on its mastered network. We are now in
299 * a permanent loop, since the SETTIME msgs will keep any clock
300 * in the network from advancing. Normally, the 'LOOP' stuff will detect
301 * and correct the situation. However, with the clocks stopped, the
302 * 'looptime' timer cannot expire. While they are in this state, the
303 * masters will try to saturate the network with SETTIME packets.
305 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
309 if (slavenet && fromnet != slavenet)
311 if (!good_host_name(msg->tsp_name)) {
312 suppress(&from, msg->tsp_name, fromnet);
313 if (electiontime > fastelection)
314 electiontime = fastelection;
321 xmit(TSP_SLAVEUP, 0, &from);
322 gettimeofday(&ntime, 0);
323 electiontime = ntime.tv_sec + delay2;
324 fastelection = ntime.tv_sec + FASTTOUT;
329 if (fromnet->status != SLAVE)
331 gettimeofday(&ntime, 0);
332 electiontime = ntime.tv_sec + delay2;
336 tsp_time_sec = msg->tsp_time.tv_sec;
337 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
338 schgdate(msg, newdate);
342 if (fromnet->status != MASTER)
344 tsp_time_sec = msg->tsp_time.tv_sec;
345 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
346 htp = findhost(msg->tsp_name);
349 "DATEREQ from uncontrolled machine");
354 "attempted date change by untrusted %s to %s",
359 schgdate(msg, newdate);
367 traceoff("Tracing ended at %s\n");
375 if (fromnet->status == SLAVE) {
376 gettimeofday(&ntime, 0);
377 electiontime = ntime.tv_sec + delay2;
378 fastelection = ntime.tv_sec + FASTTOUT;
380 if (!good_host_name(msg->tsp_name)) {
382 "suppress election of %s",
384 to.tsp_type = TSP_QUIT;
385 electiontime = fastelection;
386 } else if (cadr.s_addr != from.sin_addr.s_addr
387 && ntime.tv_sec < refusetime) {
388 /* if the candidate has to repeat itself, the old code would refuse it
389 * the second time. That would prevent elections.
391 to.tsp_type = TSP_REFUSE;
393 cadr.s_addr = from.sin_addr.s_addr;
394 to.tsp_type = TSP_ACCEPT;
395 refusetime = ntime.tv_sec + 30;
398 strlcpy(tname, msg->tsp_name, sizeof(tname));
399 strlcpy(to.tsp_name, hostname,
400 sizeof(to.tsp_name));
402 if (!acksend(&to, &taddr, tname,
405 "no answer from candidate %s\n",
408 } else { /* fromnet->status == MASTER */
409 htp = addmach(msg->tsp_name, &from,fromnet);
410 to.tsp_type = TSP_QUIT;
411 strlcpy(to.tsp_name, hostname,
412 sizeof(to.tsp_name));
413 if (!acksend(&to, &htp->addr, htp->name,
414 TSP_ACK, 0, htp->noanswer)) {
416 "no reply from %s to ELECTION-QUIT",
424 if (fromnet->status != MASTER)
427 * After a network partition, there can be
428 * more than one master: the first slave to
429 * come up will notify here the situation.
431 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
433 /* The other master often gets into the same state,
434 * with boring results.
436 ntp = fromnet; /* (acksend() can leave fromnet=0 */
437 for (tries = 0; tries < 3; tries++) {
438 to.tsp_type = TSP_RESOLVE;
439 answer = acksend(&to, &ntp->dest_addr,
440 ANYADDR, TSP_MASTERACK,
444 htp = addmach(answer->tsp_name,&from,ntp);
445 to.tsp_type = TSP_QUIT;
446 answer = acksend(&to, &htp->addr, htp->name,
447 TSP_ACK, 0, htp->noanswer);
450 "conflict error: no reply from %s to QUIT",
462 to.tsp_type = TSP_MSITEREQ;
463 to.tsp_vers = TSPVERSION;
465 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
466 answer = acksend(&to, &slavenet->dest_addr,
470 && good_host_name(answer->tsp_name)) {
472 to.tsp_type = TSP_ACK;
473 strlcpy(to.tsp_name, answer->tsp_name,
474 sizeof(to.tsp_name));
476 if (sendto(sock, (char *)&to,
477 sizeof(struct tsp), 0,
478 (struct sockaddr*)&taddr,
479 sizeof(taddr)) < 0) {
480 trace_sendto_err(taddr.sin_addr);
494 doquit(msg); /* become a slave */
502 /* looking for loops of masters */
503 if (!(status & MASTER))
505 if (fromnet->status == SLAVE) {
506 if (!strcmp(msg->tsp_name, hostname)) {
508 * Someone forwarded our message back to
509 * us. There must be a loop. Tell the
510 * master of this network to quit.
512 * The other master often gets into
513 * the same state, with boring results.
516 for (tries = 0; tries < 3; tries++) {
517 to.tsp_type = TSP_RESOLVE;
518 answer = acksend(&to, &ntp->dest_addr,
519 ANYADDR, TSP_MASTERACK,
524 strlcpy(tname, answer->tsp_name,
526 to.tsp_type = TSP_QUIT;
527 strlcpy(to.tsp_name, hostname,
528 sizeof(to.tsp_name));
529 if (!acksend(&to, &taddr, tname,
532 "no reply from %s to slave LOOP-QUIT",
538 gettimeofday(&ntime, 0);
539 looptime = ntime.tv_sec + FASTTOUT;
541 if (msg->tsp_hopcnt-- < 1)
544 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
545 if (ntp->status == MASTER
546 && 0 > sendto(sock, (char *)msg,
547 sizeof(struct tsp), 0,
548 (struct sockaddr*)&ntp->dest_addr,
549 sizeof(ntp->dest_addr)))
550 trace_sendto_err(ntp->dest_addr.sin_addr);
553 } else { /* fromnet->status == MASTER */
555 * We should not have received this from a net
556 * we are master on. There must be two masters,
557 * unless the packet was really from us.
559 if (from.sin_addr.s_addr
560 == fromnet->my_addr.s_addr) {
562 fprintf(fd,"discarding forwarded LOOP\n");
567 * The other master often gets into the same
568 * state, with boring results.
571 for (tries = 0; tries < 3; tries++) {
572 to.tsp_type = TSP_RESOLVE;
573 answer = acksend(&to, &ntp->dest_addr,
574 ANYADDR, TSP_MASTERACK,
578 htp = addmach(answer->tsp_name,
580 to.tsp_type = TSP_QUIT;
581 strlcpy(to.tsp_name, hostname,
582 sizeof(to.tsp_name));
583 if (!acksend(&to,&htp->addr,htp->name,
584 TSP_ACK, 0, htp->noanswer)) {
586 "no reply from %s to master LOOP-QUIT",
591 gettimeofday(&ntime, 0);
592 looptime = ntime.tv_sec + FASTTOUT;
597 fprintf(fd, "garbage message: ");
608 * tell the world who our master is
611 setmaster(struct tsp *msg)
615 && (slavenet != old_slavenet
616 || strcmp(msg->tsp_name, master_name)
617 || old_status != status)) {
618 strlcpy(master_name, msg->tsp_name, sizeof(master_name));
619 old_slavenet = slavenet;
622 if (status & MASTER) {
623 syslog(LOG_NOTICE, "submaster to %s", master_name);
625 fprintf(fd, "submaster to %s\n", master_name);
628 syslog(LOG_NOTICE, "slave to %s", master_name);
630 fprintf(fd, "slave to %s\n", master_name);
638 * handle date change request on a slave
641 schgdate(struct tsp *msg, char *newdate)
645 struct sockaddr_in taddr;
646 struct timeval otime;
649 return; /* no where to forward */
655 "forwarding date change by %s to %s",
656 msg->tsp_name, newdate);
658 /* adjust time for residence on the queue */
659 gettimeofday(&otime, 0);
660 adj_msg_time(msg, &otime);
662 to.tsp_type = TSP_SETDATEREQ;
663 to.tsp_time = msg->tsp_time;
664 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
665 if (!acksend(&to, &slavenet->dest_addr,
666 ANYADDR, TSP_DATEACK,
668 return; /* no answer */
670 xmit(TSP_DATEACK, seq, &taddr);
675 * Used before answering a broadcast message to avoid network
676 * contention and likely collisions.
682 struct timeval timeout;
685 timeout.tv_usec = delay1;
687 select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,