1 /*- 2 * Copyright (c) 1985, 1993 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)slave.c 5.1 (Berkeley) 05/11/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 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 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 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 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