1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #ifdef sgi
13 #ident "$Revision: 1.20 $"
14 #endif
15
16 #include "globals.h"
17 #include <setjmp.h>
18 #include "pathnames.h"
19
20 extern jmp_buf jmpenv;
21 extern int Mflag;
22 extern int justquit;
23
24 extern u_short sequence;
25
26 static char master_name[MAXHOSTNAMELEN+1];
27 static struct netinfo *old_slavenet;
28 static int old_status;
29
30 static void schgdate __P((struct tsp *, char *));
31 static void setmaster __P((struct tsp *));
32 static void answerdelay __P((void));
33
34 #ifdef sgi
35 extern void logwtmp __P((struct timeval *, struct timeval *));
36 #else
37 extern void logwtmp __P((char *, char *, char *));
38 #endif /* sgi */
39
40 int
slave()41 slave()
42 {
43 int tries;
44 long electiontime, refusetime, looktime, looptime, adjtime;
45 u_short seq;
46 long fastelection;
47 #define FASTTOUT 3
48 struct in_addr cadr;
49 struct timeval otime;
50 struct sockaddr_in taddr;
51 char tname[MAXHOSTNAMELEN];
52 struct tsp *msg, to;
53 struct timeval ntime, wait;
54 struct tsp *answer;
55 int timeout();
56 char olddate[32];
57 char newdate[32];
58 struct netinfo *ntp;
59 struct hosttbl *htp;
60
61
62 old_slavenet = 0;
63 seq = 0;
64 refusetime = 0;
65 adjtime = 0;
66
67 (void)gettimeofday(&ntime, 0);
68 electiontime = ntime.tv_sec + delay2;
69 fastelection = ntime.tv_sec + FASTTOUT;
70 if (justquit)
71 looktime = electiontime;
72 else
73 looktime = fastelection;
74 looptime = fastelection;
75
76 if (slavenet)
77 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
78 if (status & MASTER) {
79 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
80 if (ntp->status == MASTER)
81 masterup(ntp);
82 }
83 }
84
85 loop:
86 get_goodgroup(0);
87 (void)gettimeofday(&ntime, (struct timezone *)0);
88 if (ntime.tv_sec > electiontime) {
89 if (trace)
90 fprintf(fd, "election timer expired\n");
91 longjmp(jmpenv, 1);
92 }
93
94 if (ntime.tv_sec >= looktime) {
95 if (trace)
96 fprintf(fd, "Looking for nets to master\n");
97
98 if (Mflag && nignorednets > 0) {
99 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
100 if (ntp->status == IGNORE
101 || ntp->status == NOMASTER) {
102 lookformaster(ntp);
103 if (ntp->status == MASTER) {
104 masterup(ntp);
105 } else if (ntp->status == MASTER) {
106 ntp->status = NOMASTER;
107 }
108 }
109 if (ntp->status == MASTER
110 && --ntp->quit_count < 0)
111 ntp->quit_count = 0;
112 }
113 makeslave(slavenet); /* prune extras */
114 setstatus();
115 }
116 (void)gettimeofday(&ntime, 0);
117 looktime = ntime.tv_sec + delay2;
118 }
119 if (ntime.tv_sec >= looptime) {
120 if (trace)
121 fprintf(fd, "Looking for loops\n");
122 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
123 if (ntp->status == MASTER) {
124 to.tsp_type = TSP_LOOP;
125 to.tsp_vers = TSPVERSION;
126 to.tsp_seq = sequence++;
127 to.tsp_hopcnt = MAX_HOPCNT;
128 (void)strcpy(to.tsp_name, hostname);
129 bytenetorder(&to);
130 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
131 (struct sockaddr*)&ntp->dest_addr,
132 sizeof(ntp->dest_addr)) < 0) {
133 trace_sendto_err(ntp->dest_addr.sin_addr);
134 }
135 }
136 }
137 (void)gettimeofday(&ntime, 0);
138 looptime = ntime.tv_sec + delay2;
139 }
140
141 wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
142 if (wait.tv_sec < 0)
143 wait.tv_sec = 0;
144 wait.tv_sec += FASTTOUT;
145 wait.tv_usec = 0;
146 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
147
148 if (msg != NULL) {
149 /*
150 * filter stuff not for us
151 */
152 switch (msg->tsp_type) {
153 case TSP_SETDATE:
154 case TSP_TRACEOFF:
155 case TSP_TRACEON:
156 /*
157 * XXX check to see they are from ourself
158 */
159 break;
160
161 case TSP_TEST:
162 case TSP_MSITE:
163 break;
164
165 case TSP_MASTERUP:
166 if (!fromnet) {
167 if (trace) {
168 fprintf(fd, "slave ignored: ");
169 print(msg, &from);
170 }
171 goto loop;
172 }
173 break;
174
175 default:
176 if (!fromnet
177 || fromnet->status == IGNORE
178 || fromnet->status == NOMASTER) {
179 if (trace) {
180 fprintf(fd, "slave ignored: ");
181 print(msg, &from);
182 }
183 goto loop;
184 }
185 break;
186 }
187
188
189 /*
190 * now process the message
191 */
192 switch (msg->tsp_type) {
193
194 case TSP_ADJTIME:
195 if (fromnet != slavenet)
196 break;
197 if (!good_host_name(msg->tsp_name)) {
198 syslog(LOG_NOTICE,
199 "attempted time adjustment by %s",
200 msg->tsp_name);
201 suppress(&from, msg->tsp_name, fromnet);
202 break;
203 }
204 /*
205 * Speed up loop detection in case we have a loop.
206 * Otherwise the clocks can race until the loop
207 * is found.
208 */
209 (void)gettimeofday(&otime, 0);
210 if (adjtime < otime.tv_sec)
211 looptime -= (looptime-otime.tv_sec)/2 + 1;
212
213 setmaster(msg);
214 if (seq != msg->tsp_seq) {
215 seq = msg->tsp_seq;
216 synch(tvtomsround(msg->tsp_time));
217 }
218 (void)gettimeofday(&ntime, 0);
219 electiontime = ntime.tv_sec + delay2;
220 fastelection = ntime.tv_sec + FASTTOUT;
221 adjtime = ntime.tv_sec + SAMPLEINTVL*2;
222 break;
223
224 case TSP_SETTIME:
225 if (fromnet != slavenet)
226 break;
227 if (seq == msg->tsp_seq)
228 break;
229 seq = msg->tsp_seq;
230
231 /* adjust time for residence on the queue */
232 (void)gettimeofday(&otime, 0);
233 adj_msg_time(msg,&otime);
234 #ifdef sgi
235 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
236 (void)cftime(olddate, "%D %T", &otime.tv_sec);
237 #else
238 /*
239 * the following line is necessary due to syslog
240 * calling ctime() which clobbers the static buffer
241 */
242 (void)strcpy(olddate, date());
243 (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
244 #endif /* sgi */
245
246 if (!good_host_name(msg->tsp_name)) {
247 syslog(LOG_NOTICE,
248 "attempted time setting by untrusted %s to %s",
249 msg->tsp_name, newdate);
250 suppress(&from, msg->tsp_name, fromnet);
251 break;
252 }
253
254 setmaster(msg);
255 timevalsub(&ntime, &msg->tsp_time, &otime);
256 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
257 /*
258 * do not change the clock if we can adjust it
259 */
260 synch(tvtomsround(ntime));
261 } else {
262 #ifdef sgi
263 if (0 > settimeofday(&msg->tsp_time, 0)) {
264 syslog(LOG_ERR,"settimeofdate(): %m");
265 break;
266 }
267 logwtmp(&otime, &msg->tsp_time);
268 #else
269 logwtmp("|", "date", "");
270 (void)settimeofday(&msg->tsp_time, 0);
271 logwtmp("}", "date", "");
272 #endif /* sgi */
273 syslog(LOG_NOTICE,
274 "date changed by %s from %s",
275 msg->tsp_name, olddate);
276 if (status & MASTER)
277 spreadtime();
278 }
279 (void)gettimeofday(&ntime, 0);
280 electiontime = ntime.tv_sec + delay2;
281 fastelection = ntime.tv_sec + FASTTOUT;
282
283 /* This patches a bad protocol bug. Imagine a system with several networks,
284 * where there are a pair of redundant gateways between a pair of networks,
285 * each running timed. Assume that we start with a third machine mastering
286 * one of the networks, and one of the gateways mastering the other.
287 * Imagine that the third machine goes away and the non-master gateway
288 * decides to replace it. If things are timed just 'right,' we will have
289 * each gateway mastering one network for a little while. If a SETTIME
290 * message gets into the network at that time, perhaps from the newly
291 * masterful gateway as it was taking control, the SETTIME will loop
292 * forever. Each time a gateway receives it on its slave side, it will
293 * call spreadtime to forward it on its mastered network. We are now in
294 * a permanent loop, since the SETTIME msgs will keep any clock
295 * in the network from advancing. Normally, the 'LOOP' stuff will detect
296 * and correct the situation. However, with the clocks stopped, the
297 * 'looptime' timer cannot expire. While they are in this state, the
298 * masters will try to saturate the network with SETTIME packets.
299 */
300 looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
301 break;
302
303 case TSP_MASTERUP:
304 if (slavenet && fromnet != slavenet)
305 break;
306 if (!good_host_name(msg->tsp_name)) {
307 suppress(&from, msg->tsp_name, fromnet);
308 if (electiontime > fastelection)
309 electiontime = fastelection;
310 break;
311 }
312 makeslave(fromnet);
313 setmaster(msg);
314 setstatus();
315 answerdelay();
316 xmit(TSP_SLAVEUP, 0, &from);
317 (void)gettimeofday(&ntime, 0);
318 electiontime = ntime.tv_sec + delay2;
319 fastelection = ntime.tv_sec + FASTTOUT;
320 refusetime = 0;
321 break;
322
323 case TSP_MASTERREQ:
324 if (fromnet->status != SLAVE)
325 break;
326 (void)gettimeofday(&ntime, 0);
327 electiontime = ntime.tv_sec + delay2;
328 break;
329
330 case TSP_SETDATE:
331 #ifdef sgi
332 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
333 #else
334 (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
335 #endif /* sgi */
336 schgdate(msg, newdate);
337 break;
338
339 case TSP_SETDATEREQ:
340 if (fromnet->status != MASTER)
341 break;
342 #ifdef sgi
343 (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
344 #else
345 (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
346 #endif /* sgi */
347 htp = findhost(msg->tsp_name);
348 if (0 == htp) {
349 syslog(LOG_WARNING,
350 "DATEREQ from uncontrolled machine");
351 break;
352 }
353 if (!htp->good) {
354 syslog(LOG_WARNING,
355 "attempted date change by untrusted %s to %s",
356 htp->name, newdate);
357 spreadtime();
358 break;
359 }
360 schgdate(msg, newdate);
361 break;
362
363 case TSP_TRACEON:
364 traceon();
365 break;
366
367 case TSP_TRACEOFF:
368 traceoff("Tracing ended at %s\n");
369 break;
370
371 case TSP_SLAVEUP:
372 newslave(msg);
373 break;
374
375 case TSP_ELECTION:
376 if (fromnet->status == SLAVE) {
377 (void)gettimeofday(&ntime, 0);
378 electiontime = ntime.tv_sec + delay2;
379 fastelection = ntime.tv_sec + FASTTOUT;
380 seq = 0;
381 if (!good_host_name(msg->tsp_name)) {
382 syslog(LOG_NOTICE,
383 "suppress election of %s",
384 msg->tsp_name);
385 to.tsp_type = TSP_QUIT;
386 electiontime = fastelection;
387 } else if (cadr.s_addr != from.sin_addr.s_addr
388 && ntime.tv_sec < refusetime) {
389 /* if the candidate has to repeat itself, the old code would refuse it
390 * the second time. That would prevent elections.
391 */
392 to.tsp_type = TSP_REFUSE;
393 } else {
394 cadr.s_addr = from.sin_addr.s_addr;
395 to.tsp_type = TSP_ACCEPT;
396 refusetime = ntime.tv_sec + 30;
397 }
398 taddr = from;
399 (void)strcpy(tname, msg->tsp_name);
400 (void)strcpy(to.tsp_name, hostname);
401 answerdelay();
402 if (!acksend(&to, &taddr, tname,
403 TSP_ACK, 0, 0))
404 syslog(LOG_WARNING,
405 "no answer from candidate %s\n",
406 tname);
407
408 } else { /* fromnet->status == MASTER */
409 htp = addmach(msg->tsp_name, &from,fromnet);
410 to.tsp_type = TSP_QUIT;
411 (void)strcpy(to.tsp_name, hostname);
412 if (!acksend(&to, &htp->addr, htp->name,
413 TSP_ACK, 0, htp->noanswer)) {
414 syslog(LOG_ERR,
415 "no reply from %s to ELECTION-QUIT",
416 htp->name);
417 (void)remmach(htp);
418 }
419 }
420 break;
421
422 case TSP_CONFLICT:
423 if (fromnet->status != MASTER)
424 break;
425 /*
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.
429 */
430 (void)strcpy(to.tsp_name, hostname);
431
432 /* The other master often gets into the same state,
433 * with boring results.
434 */
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,
440 ntp, 0);
441 if (answer == NULL)
442 break;
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);
447 if (!answer) {
448 syslog(LOG_WARNING,
449 "conflict error: no reply from %s to QUIT",
450 htp->name);
451 (void)remmach(htp);
452 }
453 }
454 masterup(ntp);
455 break;
456
457 case TSP_MSITE:
458 if (!slavenet)
459 break;
460 taddr = from;
461 to.tsp_type = TSP_MSITEREQ;
462 to.tsp_vers = TSPVERSION;
463 to.tsp_seq = 0;
464 (void)strcpy(to.tsp_name, hostname);
465 answer = acksend(&to, &slavenet->dest_addr,
466 ANYADDR, TSP_ACK,
467 slavenet, 0);
468 if (answer != NULL
469 && good_host_name(answer->tsp_name)) {
470 setmaster(answer);
471 to.tsp_type = TSP_ACK;
472 (void)strcpy(to.tsp_name, answer->tsp_name);
473 bytenetorder(&to);
474 if (sendto(sock, (char *)&to,
475 sizeof(struct tsp), 0,
476 (struct sockaddr*)&taddr, sizeof(taddr)) < 0) {
477 trace_sendto_err(taddr.sin_addr);
478 }
479 }
480 break;
481
482 case TSP_MSITEREQ:
483 break;
484
485 case TSP_ACCEPT:
486 case TSP_REFUSE:
487 case TSP_RESOLVE:
488 break;
489
490 case TSP_QUIT:
491 doquit(msg); /* become a slave */
492 break;
493
494 case TSP_TEST:
495 electiontime = 0;
496 break;
497
498 case TSP_LOOP:
499 /* looking for loops of masters */
500 if (!(status & MASTER))
501 break;
502 if (fromnet->status == SLAVE) {
503 if (!strcmp(msg->tsp_name, hostname)) {
504 /*
505 * Someone forwarded our message back to
506 * us. There must be a loop. Tell the
507 * master of this network to quit.
508 *
509 * The other master often gets into
510 * the same state, with boring results.
511 */
512 ntp = fromnet;
513 for (tries = 0; tries < 3; tries++) {
514 to.tsp_type = TSP_RESOLVE;
515 answer = acksend(&to, &ntp->dest_addr,
516 ANYADDR, TSP_MASTERACK,
517 ntp,0);
518 if (answer == NULL)
519 break;
520 taddr = from;
521 (void)strcpy(tname, answer->tsp_name);
522 to.tsp_type = TSP_QUIT;
523 (void)strcpy(to.tsp_name, hostname);
524 if (!acksend(&to, &taddr, tname,
525 TSP_ACK, 0, 1)) {
526 syslog(LOG_ERR,
527 "no reply from %s to slave LOOP-QUIT",
528 tname);
529 } else {
530 electiontime = 0;
531 }
532 }
533 (void)gettimeofday(&ntime, 0);
534 looptime = ntime.tv_sec + FASTTOUT;
535 } else {
536 if (msg->tsp_hopcnt-- < 1)
537 break;
538 bytenetorder(msg);
539 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
540 if (ntp->status == MASTER
541 && 0 > sendto(sock, (char *)msg,
542 sizeof(struct tsp), 0,
543 (struct sockaddr*)&ntp->dest_addr,
544 sizeof(ntp->dest_addr)))
545 trace_sendto_err(ntp->dest_addr.sin_addr);
546 }
547 }
548 } else { /* fromnet->status == MASTER */
549 /*
550 * We should not have received this from a net
551 * we are master on. There must be two masters,
552 * unless the packet was really from us.
553 */
554 if (from.sin_addr.s_addr
555 == fromnet->my_addr.s_addr) {
556 if (trace)
557 fprintf(fd,"discarding forwarded LOOP\n");
558 break;
559 }
560
561 /*
562 * The other master often gets into the same
563 * state, with boring results.
564 */
565 ntp = fromnet;
566 for (tries = 0; tries < 3; tries++) {
567 to.tsp_type = TSP_RESOLVE;
568 answer = acksend(&to, &ntp->dest_addr,
569 ANYADDR, TSP_MASTERACK,
570 ntp,0);
571 if (!answer)
572 break;
573 htp = addmach(answer->tsp_name,
574 &from,ntp);
575 to.tsp_type = TSP_QUIT;
576 (void)strcpy(to.tsp_name, hostname);
577 if (!acksend(&to,&htp->addr,htp->name,
578 TSP_ACK, 0, htp->noanswer)) {
579 syslog(LOG_ERR,
580 "no reply from %s to master LOOP-QUIT",
581 htp->name);
582 (void)remmach(htp);
583 }
584 }
585 (void)gettimeofday(&ntime, 0);
586 looptime = ntime.tv_sec + FASTTOUT;
587 }
588 break;
589 default:
590 if (trace) {
591 fprintf(fd, "garbage message: ");
592 print(msg, &from);
593 }
594 break;
595 }
596 }
597 goto loop;
598 }
599
600
601 /*
602 * tell the world who our master is
603 */
604 static void
setmaster(msg)605 setmaster(msg)
606 struct tsp *msg;
607 {
608 if (slavenet
609 && (slavenet != old_slavenet
610 || strcmp(msg->tsp_name, master_name)
611 || old_status != status)) {
612 (void)strcpy(master_name, msg->tsp_name);
613 old_slavenet = slavenet;
614 old_status = status;
615
616 if (status & MASTER) {
617 syslog(LOG_NOTICE, "submaster to %s", master_name);
618 if (trace)
619 fprintf(fd, "submaster to %s\n", master_name);
620
621 } else {
622 syslog(LOG_NOTICE, "slave to %s", master_name);
623 if (trace)
624 fprintf(fd, "slave to %s\n", master_name);
625 }
626 }
627 }
628
629
630
631 /*
632 * handle date change request on a slave
633 */
634 static void
schgdate(msg,newdate)635 schgdate(msg, newdate)
636 struct tsp *msg;
637 char *newdate;
638 {
639 struct tsp to;
640 u_short seq;
641 struct sockaddr_in taddr;
642 struct timeval otime;
643
644 if (!slavenet)
645 return; /* no where to forward */
646
647 taddr = from;
648 seq = msg->tsp_seq;
649
650 syslog(LOG_INFO,
651 "forwarding date change by %s to %s",
652 msg->tsp_name, newdate);
653
654 /* adjust time for residence on the queue */
655 (void)gettimeofday(&otime, 0);
656 adj_msg_time(msg, &otime);
657
658 to.tsp_type = TSP_SETDATEREQ;
659 to.tsp_time = msg->tsp_time;
660 (void)strcpy(to.tsp_name, hostname);
661 if (!acksend(&to, &slavenet->dest_addr,
662 ANYADDR, TSP_DATEACK,
663 slavenet, 0))
664 return; /* no answer */
665
666 xmit(TSP_DATEACK, seq, &taddr);
667 }
668
669
670 /*
671 * Used before answering a broadcast message to avoid network
672 * contention and likely collisions.
673 */
674 static void
answerdelay()675 answerdelay()
676 {
677 #ifdef sgi
678 sginap(delay1);
679 #else
680 struct timeval timeout;
681
682 timeout.tv_sec = 0;
683 timeout.tv_usec = delay1;
684
685 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
686 &timeout);
687 return;
688 #endif /* sgi */
689 }
690