1 /* $NetBSD: master.c,v 1.11 2002/08/02 02:13:46 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1985, 1993 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)master.c 8.1 (Berkeley) 6/6/93"; 40 #else 41 __RCSID("$NetBSD: master.c,v 1.11 2002/08/02 02:13:46 christos Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include "globals.h" 46 #include <sys/file.h> 47 #include <sys/types.h> 48 #include <sys/times.h> 49 #include <setjmp.h> 50 51 #include "pathnames.h" 52 53 extern int measure_delta; 54 extern jmp_buf jmpenv; 55 extern int Mflag; 56 extern int justquit; 57 58 static int dictate; 59 static int slvcount; /* slaves listening to our clock */ 60 61 static void mchgdate(struct tsp*); 62 63 extern void logwtmp(char *, char *, char *); 64 65 66 67 /* 68 * The main function of `master' is to periodically compute the differences 69 * (deltas) between its clock and the clocks of the slaves, to compute the 70 * network average delta, and to send to the slaves the differences between 71 * their individual deltas and the network delta. 72 * While waiting, it receives messages from the slaves (i.e. requests for 73 * master's name, remote requests to set the network time, ...), and 74 * takes the appropriate action. 75 */ 76 int 77 master(void) 78 { 79 struct hosttbl *htp; 80 long pollingtime; 81 #define POLLRATE 4 82 int polls; 83 struct timeval wait, ntime; 84 time_t tmpt; 85 struct tsp *msg, *answer, to; 86 char newdate[32]; 87 struct sockaddr_in taddr; 88 char tname[MAXHOSTNAMELEN]; 89 struct netinfo *ntp; 90 int i; 91 92 syslog(LOG_NOTICE, "This machine is master"); 93 if (trace) 94 fprintf(fd, "This machine is master\n"); 95 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 96 if (ntp->status == MASTER) 97 masterup(ntp); 98 } 99 (void)gettimeofday(&ntime, 0); 100 pollingtime = ntime.tv_sec+3; 101 if (justquit) 102 polls = 0; 103 else 104 polls = POLLRATE-1; 105 106 /* Process all outstanding messages before spending the long time necessary 107 * to update all timers. 108 */ 109 loop: 110 (void)gettimeofday(&ntime, 0); 111 wait.tv_sec = pollingtime - ntime.tv_sec; 112 if (wait.tv_sec < 0) 113 wait.tv_sec = 0; 114 wait.tv_usec = 0; 115 msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 116 if (!msg) { 117 (void)gettimeofday(&ntime, 0); 118 if (ntime.tv_sec >= pollingtime) { 119 pollingtime = ntime.tv_sec + SAMPLEINTVL; 120 get_goodgroup(0); 121 122 /* If a bogus master told us to quit, we can have decided to ignore a 123 * network. Therefore, periodically try to take over everything. 124 */ 125 polls = (polls + 1) % POLLRATE; 126 if (0 == polls && nignorednets > 0) { 127 trace_msg("Looking for nets to re-master\n"); 128 for (ntp = nettab; ntp; ntp = ntp->next) { 129 if (ntp->status == IGNORE 130 || ntp->status == NOMASTER) { 131 lookformaster(ntp); 132 if (ntp->status == MASTER) { 133 masterup(ntp); 134 polls = POLLRATE-1; 135 } 136 } 137 if (ntp->status == MASTER 138 && --ntp->quit_count < 0) 139 ntp->quit_count = 0; 140 } 141 if (polls != 0) 142 setstatus(); 143 } 144 145 synch(0L); 146 147 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 148 to.tsp_type = TSP_LOOP; 149 to.tsp_vers = TSPVERSION; 150 to.tsp_seq = sequence++; 151 to.tsp_hopcnt = MAX_HOPCNT; 152 (void)strcpy(to.tsp_name, hostname); 153 bytenetorder(&to); 154 if (sendto(sock, (char *)&to, 155 sizeof(struct tsp), 0, 156 (struct sockaddr*)&ntp->dest_addr, 157 sizeof(ntp->dest_addr)) < 0) { 158 trace_sendto_err(ntp->dest_addr.sin_addr); 159 } 160 } 161 } 162 163 164 } else { 165 switch (msg->tsp_type) { 166 167 case TSP_MASTERREQ: 168 break; 169 170 case TSP_SLAVEUP: 171 newslave(msg); 172 break; 173 174 case TSP_SETDATE: 175 /* 176 * XXX check to see it is from ourself 177 */ 178 tmpt = msg->tsp_time.tv_sec; 179 (void)strcpy(newdate, ctime(&tmpt)); 180 if (!good_host_name(msg->tsp_name)) { 181 syslog(LOG_NOTICE, 182 "attempted date change by %s to %s", 183 msg->tsp_name, newdate); 184 spreadtime(); 185 break; 186 } 187 188 mchgdate(msg); 189 (void)gettimeofday(&ntime, 0); 190 pollingtime = ntime.tv_sec + SAMPLEINTVL; 191 break; 192 193 case TSP_SETDATEREQ: 194 if (!fromnet || fromnet->status != MASTER) 195 break; 196 tmpt = msg->tsp_time.tv_sec; 197 (void)strcpy(newdate, ctime(&tmpt)); 198 199 htp = findhost(msg->tsp_name); 200 if (htp == 0) { 201 syslog(LOG_ERR, 202 "attempted SET DATEREQ by uncontrolled %s to %s", 203 msg->tsp_name, newdate); 204 break; 205 } 206 if (htp->seq == msg->tsp_seq) 207 break; 208 htp->seq = msg->tsp_seq; 209 if (!htp->good) { 210 syslog(LOG_NOTICE, 211 "attempted SET DATEREQ by untrusted %s to %s", 212 msg->tsp_name, newdate); 213 spreadtime(); 214 break; 215 } 216 217 mchgdate(msg); 218 (void)gettimeofday(&ntime, 0); 219 pollingtime = ntime.tv_sec + SAMPLEINTVL; 220 break; 221 222 case TSP_MSITE: 223 xmit(TSP_ACK, msg->tsp_seq, &from); 224 break; 225 226 case TSP_MSITEREQ: 227 break; 228 229 case TSP_TRACEON: 230 traceon(); 231 break; 232 233 case TSP_TRACEOFF: 234 traceoff("Tracing ended at %s\n"); 235 break; 236 237 case TSP_ELECTION: 238 if (!fromnet) 239 break; 240 if (fromnet->status == MASTER) { 241 pollingtime = 0; 242 (void)addmach(msg->tsp_name, &from,fromnet); 243 } 244 taddr = from; 245 (void)strcpy(tname, msg->tsp_name); 246 to.tsp_type = TSP_QUIT; 247 (void)strcpy(to.tsp_name, hostname); 248 answer = acksend(&to, &taddr, tname, 249 TSP_ACK, 0, 1); 250 if (answer == NULL) { 251 syslog(LOG_ERR, "election error by %s", 252 tname); 253 } 254 break; 255 256 case TSP_CONFLICT: 257 /* 258 * After a network partition, there can be 259 * more than one master: the first slave to 260 * come up will notify here the situation. 261 */ 262 if (!fromnet || fromnet->status != MASTER) 263 break; 264 (void)strcpy(to.tsp_name, hostname); 265 266 /* The other master often gets into the same state, 267 * with boring results if we stay at it forever. 268 */ 269 ntp = fromnet; /* (acksend() can leave fromnet=0 */ 270 for (i = 0; i < 3; i++) { 271 to.tsp_type = TSP_RESOLVE; 272 (void)strcpy(to.tsp_name, hostname); 273 answer = acksend(&to, &ntp->dest_addr, 274 ANYADDR, TSP_MASTERACK, 275 ntp, 0); 276 if (!answer) 277 break; 278 htp = addmach(answer->tsp_name,&from,ntp); 279 to.tsp_type = TSP_QUIT; 280 msg = acksend(&to, &htp->addr, htp->name, 281 TSP_ACK, 0, htp->noanswer); 282 if (msg == NULL) { 283 syslog(LOG_ERR, 284 "no response from %s to CONFLICT-QUIT", 285 htp->name); 286 } 287 } 288 masterup(ntp); 289 pollingtime = 0; 290 break; 291 292 case TSP_RESOLVE: 293 if (!fromnet || fromnet->status != MASTER) 294 break; 295 /* 296 * do not want to call synch() while waiting 297 * to be killed! 298 */ 299 (void)gettimeofday(&ntime, (struct timezone *)0); 300 pollingtime = ntime.tv_sec + SAMPLEINTVL; 301 break; 302 303 case TSP_QUIT: 304 doquit(msg); /* become a slave */ 305 break; 306 307 case TSP_LOOP: 308 if (!fromnet || fromnet->status != MASTER 309 || !strcmp(msg->tsp_name, hostname)) 310 break; 311 /* 312 * We should not have received this from a net 313 * we are master on. There must be two masters. 314 */ 315 htp = addmach(msg->tsp_name, &from,fromnet); 316 to.tsp_type = TSP_QUIT; 317 (void)strcpy(to.tsp_name, hostname); 318 answer = acksend(&to, &htp->addr, htp->name, 319 TSP_ACK, 0, 1); 320 if (!answer) { 321 syslog(LOG_WARNING, 322 "loop breakage: no reply from %s=%s to QUIT", 323 htp->name, inet_ntoa(htp->addr.sin_addr)); 324 (void)remmach(htp); 325 } 326 327 case TSP_TEST: 328 if (trace) { 329 fprintf(fd, 330 "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", 331 nnets, nmasternets, nslavenets, nignorednets); 332 setstatus(); 333 } 334 pollingtime = 0; 335 polls = POLLRATE-1; 336 break; 337 338 default: 339 if (trace) { 340 fprintf(fd, "garbage message: "); 341 print(msg, &from); 342 } 343 break; 344 } 345 } 346 goto loop; 347 } 348 349 350 /* 351 * change the system date on the master 352 */ 353 static void 354 mchgdate(struct tsp *msg) 355 { 356 char tname[MAXHOSTNAMELEN]; 357 char olddate[32]; 358 struct timeval otime, ntime, tmptv; 359 360 (void)strcpy(tname, msg->tsp_name); 361 362 xmit(TSP_DATEACK, msg->tsp_seq, &from); 363 364 (void)strcpy(olddate, date()); 365 366 /* adjust time for residence on the queue */ 367 (void)gettimeofday(&otime, 0); 368 adj_msg_time(msg,&otime); 369 370 timersub(&msg->tsp_time, &otime, &ntime); 371 if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 372 /* 373 * do not change the clock if we can adjust it 374 */ 375 dictate = 3; 376 synch(tvtomsround(ntime)); 377 } else { 378 logwtmp("|", "date", ""); 379 tmptv.tv_sec = msg->tsp_time.tv_sec; 380 tmptv.tv_usec = msg->tsp_time.tv_usec; 381 (void)settimeofday(&tmptv, 0); 382 logwtmp("}", "date", ""); 383 spreadtime(); 384 } 385 386 syslog(LOG_NOTICE, "date changed by %s from %s", 387 tname, olddate); 388 } 389 390 391 /* 392 * synchronize all of the slaves 393 */ 394 void 395 synch(long mydelta) 396 { 397 struct hosttbl *htp; 398 int measure_status; 399 struct timeval check, stop, wait; 400 401 if (slvcount > 0) { 402 if (trace) 403 fprintf(fd, "measurements starting at %s\n", date()); 404 (void)gettimeofday(&check, 0); 405 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 406 if (htp->noanswer != 0) { 407 measure_status = measure(500, 100, 408 htp->name, 409 &htp->addr,0); 410 } else { 411 measure_status = measure(3000, 100, 412 htp->name, 413 &htp->addr,0); 414 } 415 if (measure_status != GOOD) { 416 /* The slave did not respond. We have 417 * just wasted lots of time on it. 418 */ 419 htp->delta = HOSTDOWN; 420 if (++htp->noanswer >= LOSTHOST) { 421 if (trace) { 422 fprintf(fd, 423 "purging %s for not answering ICMP\n", 424 htp->name); 425 (void)fflush(fd); 426 } 427 htp = remmach(htp); 428 } 429 } else { 430 htp->delta = measure_delta; 431 } 432 (void)gettimeofday(&stop, 0); 433 timersub(&stop, &check, &stop); 434 if (stop.tv_sec >= 1) { 435 if (trace) 436 (void)fflush(fd); 437 /* 438 * ack messages periodically 439 */ 440 wait.tv_sec = 0; 441 wait.tv_usec = 0; 442 if (0 != readmsg(TSP_TRACEON,ANYADDR, 443 &wait,0)) 444 traceon(); 445 (void)gettimeofday(&check, 0); 446 } 447 } 448 if (trace) 449 fprintf(fd, "measurements finished at %s\n", date()); 450 } 451 if (!(status & SLAVE)) { 452 if (!dictate) { 453 mydelta = networkdelta(); 454 } else { 455 dictate--; 456 } 457 } 458 if (trace && (mydelta != 0 || (status & SLAVE))) 459 fprintf(fd,"local correction of %ld ms.\n", mydelta); 460 correct(mydelta); 461 } 462 463 /* 464 * sends the time to each slave after the master 465 * has received the command to set the network time 466 */ 467 void 468 spreadtime(void) 469 { 470 struct hosttbl *htp; 471 struct tsp to; 472 struct tsp *answer; 473 struct timeval tmptv; 474 475 /* Do not listen to the consensus after forcing the time. This is because 476 * the consensus takes a while to reach the time we are dictating. 477 */ 478 dictate = 2; 479 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 480 to.tsp_type = TSP_SETTIME; 481 (void)strcpy(to.tsp_name, hostname); 482 (void)gettimeofday(&tmptv, 0); 483 to.tsp_time.tv_sec = tmptv.tv_sec; 484 to.tsp_time.tv_usec = tmptv.tv_usec; 485 answer = acksend(&to, &htp->addr, htp->name, 486 TSP_ACK, 0, htp->noanswer); 487 if (answer == 0) { 488 /* We client does not respond, then we have 489 * just wasted lots of time on it. 490 */ 491 syslog(LOG_WARNING, 492 "no reply to SETTIME from %s", htp->name); 493 if (++htp->noanswer >= LOSTHOST) { 494 if (trace) { 495 fprintf(fd, 496 "purging %s for not answering", 497 htp->name); 498 (void)fflush(fd); 499 } 500 htp = remmach(htp); 501 } 502 } 503 } 504 } 505 506 507 void 508 prthp(clock_t delta) 509 { 510 static time_t next_time; 511 time_t this_time; 512 struct tms tm; 513 struct hosttbl *htp; 514 int length, l; 515 int i; 516 517 if (!fd) /* quit if tracing already off */ 518 return; 519 520 this_time = times(&tm); 521 if (this_time + delta < next_time) 522 return; 523 next_time = this_time + CLK_TCK; 524 525 fprintf(fd, "host table: %d entries at %s\n", slvcount, date()); 526 htp = self.l_fwd; 527 length = 1; 528 for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) { 529 l = strlen(htp->name) + 1; 530 if (length+l >= 80) { 531 fprintf(fd, "\n"); 532 length = 0; 533 } 534 length += l; 535 fprintf(fd, " %s", htp->name); 536 } 537 fprintf(fd, "\n"); 538 } 539 540 541 static struct hosttbl *newhost_hash; 542 static struct hosttbl *lasthfree = &hosttbl[0]; 543 544 545 struct hosttbl * /* answer or 0 */ 546 findhost(char *name) 547 { 548 int i, j; 549 struct hosttbl *htp; 550 char *p; 551 552 j= 0; 553 for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++) 554 j = (j << 2) ^ *p; 555 newhost_hash = &hosttbl[j % NHOSTS]; 556 557 htp = newhost_hash; 558 if (htp->name[0] == '\0') 559 return(0); 560 do { 561 if (!strcmp(name, htp->name)) 562 return(htp); 563 htp = htp->h_fwd; 564 } while (htp != newhost_hash); 565 return(0); 566 } 567 568 /* 569 * add a host to the list of controlled machines if not already there 570 */ 571 struct hosttbl * 572 addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp) 573 { 574 struct hosttbl *ret, *p, *b, *f; 575 576 ret = findhost(name); 577 if (ret == 0) { 578 if (slvcount >= NHOSTS) { 579 if (trace) { 580 fprintf(fd, "no more slots in host table\n"); 581 prthp(CLK_TCK); 582 } 583 syslog(LOG_ERR, "no more slots in host table"); 584 Mflag = 0; 585 longjmp(jmpenv, 2); /* give up and be a slave */ 586 } 587 588 /* if our home hash slot is occupied, find a free entry 589 * in the hash table 590 */ 591 if (newhost_hash->name[0] != '\0') { 592 do { 593 ret = lasthfree; 594 if (++lasthfree > &hosttbl[NHOSTS]) 595 lasthfree = &hosttbl[1]; 596 } while (ret->name[0] != '\0'); 597 598 if (!newhost_hash->head) { 599 /* Move an interloper using our home. Use 600 * scratch pointers in case the new head is 601 * pointing to itself. 602 */ 603 f = newhost_hash->h_fwd; 604 b = newhost_hash->h_bak; 605 f->h_bak = ret; 606 b->h_fwd = ret; 607 f = newhost_hash->l_fwd; 608 b = newhost_hash->l_bak; 609 f->l_bak = ret; 610 b->l_fwd = ret; 611 bcopy(newhost_hash,ret,sizeof(*ret)); 612 ret = newhost_hash; 613 ret->head = 1; 614 ret->h_fwd = ret; 615 ret->h_bak = ret; 616 } else { 617 /* link to an existing chain in our home 618 */ 619 ret->head = 0; 620 p = newhost_hash->h_bak; 621 ret->h_fwd = newhost_hash; 622 ret->h_bak = p; 623 p->h_fwd = ret; 624 newhost_hash->h_bak = ret; 625 } 626 } else { 627 ret = newhost_hash; 628 ret->head = 1; 629 ret->h_fwd = ret; 630 ret->h_bak = ret; 631 } 632 ret->addr = *addr; 633 ret->ntp = ntp; 634 (void)strncpy(ret->name, name, sizeof(ret->name)); 635 ret->good = good_host_name(name); 636 ret->l_fwd = &self; 637 ret->l_bak = self.l_bak; 638 self.l_bak->l_fwd = ret; 639 self.l_bak = ret; 640 slvcount++; 641 642 ret->noanswer = 0; 643 ret->need_set = 1; 644 645 } else { 646 ret->noanswer = (ret->noanswer != 0); 647 } 648 649 /* need to clear sequence number anyhow */ 650 ret->seq = 0; 651 return(ret); 652 } 653 654 /* 655 * remove the machine with the given index in the host table. 656 */ 657 struct hosttbl * 658 remmach(struct hosttbl *htp) 659 { 660 struct hosttbl *lprv, *hnxt, *f, *b; 661 662 if (trace) 663 fprintf(fd, "remove %s\n", htp->name); 664 665 /* get out of the lists */ 666 htp->l_fwd->l_bak = lprv = htp->l_bak; 667 htp->l_bak->l_fwd = htp->l_fwd; 668 htp->h_fwd->h_bak = htp->h_bak; 669 htp->h_bak->h_fwd = hnxt = htp->h_fwd; 670 671 /* If we are in the home slot, pull up the chain */ 672 if (htp->head && hnxt != htp) { 673 if (lprv == hnxt) 674 lprv = htp; 675 676 /* Use scratch pointers in case the new head is pointing to 677 * itself. 678 */ 679 f = hnxt->h_fwd; 680 b = hnxt->h_bak; 681 f->h_bak = htp; 682 b->h_fwd = htp; 683 f = hnxt->l_fwd; 684 b = hnxt->l_bak; 685 f->l_bak = htp; 686 b->l_fwd = htp; 687 hnxt->head = 1; 688 bcopy(hnxt, htp, sizeof(*htp)); 689 lasthfree = hnxt; 690 } else { 691 lasthfree = htp; 692 } 693 694 lasthfree->name[0] = '\0'; 695 lasthfree->h_fwd = 0; 696 lasthfree->l_fwd = 0; 697 slvcount--; 698 699 return lprv; 700 } 701 702 703 /* 704 * Remove all the machines from the host table that exist on the given 705 * network. This is called when a master transitions to a slave on a 706 * given network. 707 */ 708 void 709 rmnetmachs(struct netinfo *ntp) 710 { 711 struct hosttbl *htp; 712 713 if (trace) 714 prthp(CLK_TCK); 715 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 716 if (ntp == htp->ntp) 717 htp = remmach(htp); 718 } 719 if (trace) 720 prthp(CLK_TCK); 721 } 722 723 724 void 725 masterup(struct netinfo *net) 726 { 727 xmit(TSP_MASTERUP, 0, &net->dest_addr); 728 729 /* 730 * Do not tell new slaves our time for a while. This ensures 731 * we do not tell them to start using our time, before we have 732 * found a good master. 733 */ 734 (void)gettimeofday(&net->slvwait, 0); 735 } 736 737 void 738 newslave(struct tsp *msg) 739 { 740 struct hosttbl *htp; 741 struct tsp *answer, to; 742 struct timeval now, tmptv; 743 744 if (!fromnet || fromnet->status != MASTER) 745 return; 746 747 htp = addmach(msg->tsp_name, &from,fromnet); 748 htp->seq = msg->tsp_seq; 749 if (trace) 750 prthp(0); 751 752 /* 753 * If we are stable, send our time to the slave. 754 * Do not go crazy if the date has been changed. 755 */ 756 (void)gettimeofday(&now, 0); 757 if (now.tv_sec >= fromnet->slvwait.tv_sec+3 758 || now.tv_sec < fromnet->slvwait.tv_sec) { 759 to.tsp_type = TSP_SETTIME; 760 (void)strcpy(to.tsp_name, hostname); 761 (void)gettimeofday(&tmptv, 0); 762 to.tsp_time.tv_sec = tmptv.tv_sec; 763 to.tsp_time.tv_usec = tmptv.tv_usec; 764 answer = acksend(&to, &htp->addr, 765 htp->name, TSP_ACK, 766 0, htp->noanswer); 767 if (answer) { 768 htp->need_set = 0; 769 } else { 770 syslog(LOG_WARNING, 771 "no reply to initial SETTIME from %s", 772 htp->name); 773 htp->noanswer = LOSTHOST; 774 } 775 } 776 } 777 778 779 /* 780 * react to a TSP_QUIT: 781 */ 782 void 783 doquit(struct tsp *msg) 784 { 785 if (fromnet->status == MASTER) { 786 if (!good_host_name(msg->tsp_name)) { 787 if (fromnet->quit_count <= 0) { 788 syslog(LOG_NOTICE,"untrusted %s told us QUIT", 789 msg->tsp_name); 790 suppress(&from, msg->tsp_name, fromnet); 791 fromnet->quit_count = 1; 792 return; 793 } 794 syslog(LOG_NOTICE, "untrusted %s told us QUIT twice", 795 msg->tsp_name); 796 fromnet->quit_count = 2; 797 fromnet->status = NOMASTER; 798 } else { 799 fromnet->status = SLAVE; 800 } 801 rmnetmachs(fromnet); 802 longjmp(jmpenv, 2); /* give up and be a slave */ 803 804 } else { 805 if (!good_host_name(msg->tsp_name)) { 806 syslog(LOG_NOTICE, "untrusted %s told us QUIT", 807 msg->tsp_name); 808 fromnet->quit_count = 2; 809 } 810 } 811 } 812 813 void 814 traceon(void) 815 { 816 if (!fd) { 817 fd = fopen(_PATH_TIMEDLOG, "w"); 818 if (!fd) { 819 trace = 0; 820 return; 821 } 822 fprintf(fd,"Tracing started at %s\n", date()); 823 } 824 trace = 1; 825 get_goodgroup(1); 826 setstatus(); 827 prthp(CLK_TCK); 828 } 829 830 831 void 832 traceoff(char *msg) 833 { 834 get_goodgroup(1); 835 setstatus(); 836 prthp(CLK_TCK); 837 if (trace) { 838 fprintf(fd, msg, date()); 839 (void)fclose(fd); 840 fd = 0; 841 } 842 #ifdef GPROF 843 moncontrol(0); 844 _mcleanup(); 845 moncontrol(1); 846 #endif 847 trace = OFF; 848 } 849 850