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 $
39 #include "pathnames.h"
41 extern jmp_buf jmpenv;
45 extern u_short sequence;
47 static char master_name[MAXHOSTNAMELEN];
48 static struct netinfo *old_slavenet;
49 static int old_status;
51 static void schgdate(struct tsp *, char *);
52 static void setmaster(struct tsp *);
53 static void answerdelay(void);
59 long electiontime, refusetime, looktime, looptime, adjusttime;
65 struct sockaddr_in taddr;
66 char tname[MAXHOSTNAMELEN];
68 struct timeval ntime, wait;
82 gettimeofday(&ntime, 0);
83 electiontime = ntime.tv_sec + delay2;
84 fastelection = ntime.tv_sec + FASTTOUT;
86 looktime = electiontime;
88 looktime = fastelection;
89 looptime = fastelection;
92 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
93 if (status & MASTER) {
94 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
95 if (ntp->status == MASTER)
102 gettimeofday(&ntime, NULL);
103 if (ntime.tv_sec > electiontime) {
105 fprintf(fd, "election timer expired\n");
109 if (ntime.tv_sec >= looktime) {
111 fprintf(fd, "Looking for nets to master\n");
113 if (Mflag && nignorednets > 0) {
114 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
115 if (ntp->status == IGNORE
116 || ntp->status == NOMASTER) {
118 if (ntp->status == MASTER) {
120 } else if (ntp->status == MASTER) {
121 ntp->status = NOMASTER;
124 if (ntp->status == MASTER
125 && --ntp->quit_count < 0)
128 makeslave(slavenet); /* prune extras */
131 gettimeofday(&ntime, 0);
132 looktime = ntime.tv_sec + delay2;
134 if (ntime.tv_sec >= looptime) {
136 fprintf(fd, "Looking for loops\n");
137 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
138 if (ntp->status == MASTER) {
139 to.tsp_type = TSP_LOOP;
140 to.tsp_vers = TSPVERSION;
141 to.tsp_seq = sequence++;
142 to.tsp_hopcnt = MAX_HOPCNT;
143 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
145 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
146 (struct sockaddr*)&ntp->dest_addr,
147 sizeof(ntp->dest_addr)) < 0) {
148 trace_sendto_err(ntp->dest_addr.sin_addr);
152 gettimeofday(&ntime, 0);
153 looptime = ntime.tv_sec + delay2;
156 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
159 wait.tv_sec += FASTTOUT;
161 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
165 * filter stuff not for us
167 switch (msg->tsp_type) {
172 * XXX check to see they are from ourself
183 fprintf(fd, "slave ignored: ");
192 || fromnet->status == IGNORE
193 || fromnet->status == NOMASTER) {
195 fprintf(fd, "slave ignored: ");
205 * now process the message
207 switch (msg->tsp_type) {
210 if (fromnet != slavenet)
212 if (!good_host_name(msg->tsp_name)) {
214 "attempted time adjustment by %s",
216 suppress(&from, msg->tsp_name, fromnet);
220 * Speed up loop detection in case we have a loop.
221 * Otherwise the clocks can race until the loop
224 gettimeofday(&otime, 0);
225 if (adjusttime < otime.tv_sec)
226 looptime -= (looptime-otime.tv_sec)/2 + 1;
229 if (seq != msg->tsp_seq) {
231 synch(tvtomsround(msg->tsp_time));
233 gettimeofday(&ntime, 0);
234 electiontime = ntime.tv_sec + delay2;
235 fastelection = ntime.tv_sec + FASTTOUT;
236 adjusttime = ntime.tv_sec + SAMPLEINTVL*2;
240 if (fromnet != slavenet)
242 if (seq == msg->tsp_seq)
246 /* adjust time for residence on the queue */
247 gettimeofday(&otime, 0);
248 adj_msg_time(msg,&otime);
251 * the following line is necessary due to syslog
252 * calling ctime() which clobbers the static buffer
254 strlcpy(olddate, date(), sizeof(olddate));
255 tsp_time_sec = msg->tsp_time.tv_sec;
256 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
258 if (!good_host_name(msg->tsp_name)) {
260 "attempted time setting by untrusted %s to %s",
261 msg->tsp_name, newdate);
262 suppress(&from, msg->tsp_name, fromnet);
267 timevalsub(&ntime, &msg->tsp_time, &otime);
268 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
270 * do not change the clock if we can adjust it
272 synch(tvtomsround(ntime));
274 logwtmp("|", "date", "");
275 settimeofday(&msg->tsp_time, 0);
276 logwtmp("{", "date", "");
278 "date changed by %s from %s",
279 msg->tsp_name, olddate);
283 gettimeofday(&ntime, 0);
284 electiontime = ntime.tv_sec + delay2;
285 fastelection = ntime.tv_sec + FASTTOUT;
287 /* This patches a bad protocol bug. Imagine a system with several networks,
288 * where there are a pair of redundant gateways between a pair of networks,
289 * each running timed. Assume that we start with a third machine mastering
290 * one of the networks, and one of the gateways mastering the other.
291 * Imagine that the third machine goes away and the non-master gateway
292 * decides to replace it. If things are timed just 'right,' we will have
293 * each gateway mastering one network for a little while. If a SETTIME
294 * message gets into the network at that time, perhaps from the newly
295 * masterful gateway as it was taking control, the SETTIME will loop
296 * forever. Each time a gateway receives it on its slave side, it will
297 * call spreadtime to forward it on its mastered network. We are now in
298 * a permanent loop, since the SETTIME msgs will keep any clock
299 * in the network from advancing. Normally, the 'LOOP' stuff will detect
300 * and correct the situation. However, with the clocks stopped, the
301 * 'looptime' timer cannot expire. While they are in this state, the
302 * masters will try to saturate the network with SETTIME packets.
304 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
308 if (slavenet && fromnet != slavenet)
310 if (!good_host_name(msg->tsp_name)) {
311 suppress(&from, msg->tsp_name, fromnet);
312 if (electiontime > fastelection)
313 electiontime = fastelection;
320 xmit(TSP_SLAVEUP, 0, &from);
321 gettimeofday(&ntime, 0);
322 electiontime = ntime.tv_sec + delay2;
323 fastelection = ntime.tv_sec + FASTTOUT;
328 if (fromnet->status != SLAVE)
330 gettimeofday(&ntime, 0);
331 electiontime = ntime.tv_sec + delay2;
335 tsp_time_sec = msg->tsp_time.tv_sec;
336 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
337 schgdate(msg, newdate);
341 if (fromnet->status != MASTER)
343 tsp_time_sec = msg->tsp_time.tv_sec;
344 strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
345 htp = findhost(msg->tsp_name);
348 "DATEREQ from uncontrolled machine");
353 "attempted date change by untrusted %s to %s",
358 schgdate(msg, newdate);
366 traceoff("Tracing ended at %s\n");
374 if (fromnet->status == SLAVE) {
375 gettimeofday(&ntime, 0);
376 electiontime = ntime.tv_sec + delay2;
377 fastelection = ntime.tv_sec + FASTTOUT;
379 if (!good_host_name(msg->tsp_name)) {
381 "suppress election of %s",
383 to.tsp_type = TSP_QUIT;
384 electiontime = fastelection;
385 } else if (cadr.s_addr != from.sin_addr.s_addr
386 && ntime.tv_sec < refusetime) {
387 /* if the candidate has to repeat itself, the old code would refuse it
388 * the second time. That would prevent elections.
390 to.tsp_type = TSP_REFUSE;
392 cadr.s_addr = from.sin_addr.s_addr;
393 to.tsp_type = TSP_ACCEPT;
394 refusetime = ntime.tv_sec + 30;
397 strlcpy(tname, msg->tsp_name, sizeof(tname));
398 strlcpy(to.tsp_name, hostname,
399 sizeof(to.tsp_name));
401 if (!acksend(&to, &taddr, tname,
404 "no answer from candidate %s\n",
407 } else { /* fromnet->status == MASTER */
408 htp = addmach(msg->tsp_name, &from,fromnet);
409 to.tsp_type = TSP_QUIT;
410 strlcpy(to.tsp_name, hostname,
411 sizeof(to.tsp_name));
412 if (!acksend(&to, &htp->addr, htp->name,
413 TSP_ACK, 0, htp->noanswer)) {
415 "no reply from %s to ELECTION-QUIT",
423 if (fromnet->status != MASTER)
426 * After a network partition, there can be
427 * more than one master: the first slave to
428 * come up will notify here the situation.
430 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
432 /* The other master often gets into the same state,
433 * with boring results.
435 ntp = fromnet; /* (acksend() can leave fromnet=0 */
436 for (tries = 0; tries < 3; tries++) {
437 to.tsp_type = TSP_RESOLVE;
438 answer = acksend(&to, &ntp->dest_addr,
439 ANYADDR, TSP_MASTERACK,
443 htp = addmach(answer->tsp_name,&from,ntp);
444 to.tsp_type = TSP_QUIT;
445 answer = acksend(&to, &htp->addr, htp->name,
446 TSP_ACK, 0, htp->noanswer);
449 "conflict error: no reply from %s to QUIT",
461 to.tsp_type = TSP_MSITEREQ;
462 to.tsp_vers = TSPVERSION;
464 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
465 answer = acksend(&to, &slavenet->dest_addr,
469 && good_host_name(answer->tsp_name)) {
471 to.tsp_type = TSP_ACK;
472 strlcpy(to.tsp_name, answer->tsp_name,
473 sizeof(to.tsp_name));
475 if (sendto(sock, (char *)&to,
476 sizeof(struct tsp), 0,
477 (struct sockaddr*)&taddr,
478 sizeof(taddr)) < 0) {
479 trace_sendto_err(taddr.sin_addr);
493 doquit(msg); /* become a slave */
501 /* looking for loops of masters */
502 if (!(status & MASTER))
504 if (fromnet->status == SLAVE) {
505 if (!strcmp(msg->tsp_name, hostname)) {
507 * Someone forwarded our message back to
508 * us. There must be a loop. Tell the
509 * master of this network to quit.
511 * The other master often gets into
512 * the same state, with boring results.
515 for (tries = 0; tries < 3; tries++) {
516 to.tsp_type = TSP_RESOLVE;
517 answer = acksend(&to, &ntp->dest_addr,
518 ANYADDR, TSP_MASTERACK,
523 strlcpy(tname, answer->tsp_name,
525 to.tsp_type = TSP_QUIT;
526 strlcpy(to.tsp_name, hostname,
527 sizeof(to.tsp_name));
528 if (!acksend(&to, &taddr, tname,
531 "no reply from %s to slave LOOP-QUIT",
537 gettimeofday(&ntime, 0);
538 looptime = ntime.tv_sec + FASTTOUT;
540 if (msg->tsp_hopcnt-- < 1)
543 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
544 if (ntp->status == MASTER
545 && 0 > sendto(sock, (char *)msg,
546 sizeof(struct tsp), 0,
547 (struct sockaddr*)&ntp->dest_addr,
548 sizeof(ntp->dest_addr)))
549 trace_sendto_err(ntp->dest_addr.sin_addr);
552 } else { /* fromnet->status == MASTER */
554 * We should not have received this from a net
555 * we are master on. There must be two masters,
556 * unless the packet was really from us.
558 if (from.sin_addr.s_addr
559 == fromnet->my_addr.s_addr) {
561 fprintf(fd,"discarding forwarded LOOP\n");
566 * The other master often gets into the same
567 * state, with boring results.
570 for (tries = 0; tries < 3; tries++) {
571 to.tsp_type = TSP_RESOLVE;
572 answer = acksend(&to, &ntp->dest_addr,
573 ANYADDR, TSP_MASTERACK,
577 htp = addmach(answer->tsp_name,
579 to.tsp_type = TSP_QUIT;
580 strlcpy(to.tsp_name, hostname,
581 sizeof(to.tsp_name));
582 if (!acksend(&to,&htp->addr,htp->name,
583 TSP_ACK, 0, htp->noanswer)) {
585 "no reply from %s to master LOOP-QUIT",
590 gettimeofday(&ntime, 0);
591 looptime = ntime.tv_sec + FASTTOUT;
596 fprintf(fd, "garbage message: ");
607 * tell the world who our master is
610 setmaster(struct tsp *msg)
614 && (slavenet != old_slavenet
615 || strcmp(msg->tsp_name, master_name)
616 || old_status != status)) {
617 strlcpy(master_name, msg->tsp_name, sizeof(master_name));
618 old_slavenet = slavenet;
621 if (status & MASTER) {
622 syslog(LOG_NOTICE, "submaster to %s", master_name);
624 fprintf(fd, "submaster to %s\n", master_name);
627 syslog(LOG_NOTICE, "slave to %s", master_name);
629 fprintf(fd, "slave to %s\n", master_name);
637 * handle date change request on a slave
640 schgdate(struct tsp *msg, char *newdate)
644 struct sockaddr_in taddr;
645 struct timeval otime;
648 return; /* no where to forward */
654 "forwarding date change by %s to %s",
655 msg->tsp_name, newdate);
657 /* adjust time for residence on the queue */
658 gettimeofday(&otime, 0);
659 adj_msg_time(msg, &otime);
661 to.tsp_type = TSP_SETDATEREQ;
662 to.tsp_time = msg->tsp_time;
663 strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
664 if (!acksend(&to, &slavenet->dest_addr,
665 ANYADDR, TSP_DATEACK,
667 return; /* no answer */
669 xmit(TSP_DATEACK, seq, &taddr);
674 * Used before answering a broadcast message to avoid network
675 * contention and likely collisions.
681 struct timeval timeout;
684 timeout.tv_usec = delay1;
686 select(0, NULL, NULL, NULL, &timeout);