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
,