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