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