]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/timed/timed/slave.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 #if 0
32 static char sccsid[] = "@(#)slave.c     8.1 (Berkeley) 6/6/93";
33 #endif
34 static const char rcsid[] =
35   "$FreeBSD$";
36 #endif /* not lint */
37
38 #include "globals.h"
39 #include <setjmp.h>
40 #include <utmpx.h>
41 #include "pathnames.h"
42
43 extern jmp_buf jmpenv;
44 extern int Mflag;
45 extern int justquit;
46
47 extern u_short sequence;
48
49 static char master_name[MAXHOSTNAMELEN];
50 static struct netinfo *old_slavenet;
51 static int old_status;
52
53 static void schgdate(struct tsp *, char *);
54 static void setmaster(struct tsp *);
55 static void answerdelay(void);
56
57 int
58 slave()
59 {
60         int tries;
61         long electiontime, refusetime, looktime, looptime, adjtime;
62         u_short seq;
63         long fastelection;
64 #define FASTTOUT 3
65         struct in_addr cadr;
66         struct timeval otime;
67         struct sockaddr_in taddr;
68         char tname[MAXHOSTNAMELEN];
69         struct tsp *msg, to;
70         struct timeval ntime, wait, tmptv;
71         time_t tsp_time_sec;
72         struct tsp *answer;
73         int timeout();
74         char olddate[32];
75         char newdate[32];
76         struct netinfo *ntp;
77         struct hosttbl *htp;
78         struct utmpx utx;
79
80
81         old_slavenet = 0;
82         seq = 0;
83         refusetime = 0;
84         adjtime = 0;
85
86         (void)gettimeofday(&ntime, 0);
87         electiontime = ntime.tv_sec + delay2;
88         fastelection = ntime.tv_sec + FASTTOUT;
89         if (justquit)
90                 looktime = electiontime;
91         else
92                 looktime = fastelection;
93         looptime = fastelection;
94
95         if (slavenet)
96                 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
97         if (status & MASTER) {
98                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
99                         if (ntp->status == MASTER)
100                                 masterup(ntp);
101                 }
102         }
103
104 loop:
105         get_goodgroup(0);
106         (void)gettimeofday(&ntime, (struct timezone *)0);
107         if (ntime.tv_sec > electiontime) {
108                 if (trace)
109                         fprintf(fd, "election timer expired\n");
110                 longjmp(jmpenv, 1);
111         }
112
113         if (ntime.tv_sec >= looktime) {
114                 if (trace)
115                         fprintf(fd, "Looking for nets to master\n");
116
117                 if (Mflag && nignorednets > 0) {
118                         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
119                                 if (ntp->status == IGNORE
120                                     || ntp->status == NOMASTER) {
121                                         lookformaster(ntp);
122                                         if (ntp->status == MASTER) {
123                                                 masterup(ntp);
124                                         } else if (ntp->status == MASTER) {
125                                                 ntp->status = NOMASTER;
126                                         }
127                                 }
128                                 if (ntp->status == MASTER
129                                     && --ntp->quit_count < 0)
130                                         ntp->quit_count = 0;
131                         }
132                         makeslave(slavenet);    /* prune extras */
133                         setstatus();
134                 }
135                 (void)gettimeofday(&ntime, 0);
136                 looktime = ntime.tv_sec + delay2;
137         }
138         if (ntime.tv_sec >= looptime) {
139                 if (trace)
140                         fprintf(fd, "Looking for loops\n");
141                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
142                     if (ntp->status == MASTER) {
143                         to.tsp_type = TSP_LOOP;
144                         to.tsp_vers = TSPVERSION;
145                         to.tsp_seq = sequence++;
146                         to.tsp_hopcnt = MAX_HOPCNT;
147                         (void)strcpy(to.tsp_name, hostname);
148                         bytenetorder(&to);
149                         if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
150                                    (struct sockaddr*)&ntp->dest_addr,
151                                    sizeof(ntp->dest_addr)) < 0) {
152                                 trace_sendto_err(ntp->dest_addr.sin_addr);
153                         }
154                     }
155                 }
156                 (void)gettimeofday(&ntime, 0);
157                 looptime = ntime.tv_sec + delay2;
158         }
159
160         wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
161         if (wait.tv_sec < 0)
162                 wait.tv_sec = 0;
163         wait.tv_sec += FASTTOUT;
164         wait.tv_usec = 0;
165         msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
166
167         if (msg != NULL) {
168                 /*
169                  * filter stuff not for us
170                  */
171                 switch (msg->tsp_type) {
172                 case TSP_SETDATE:
173                 case TSP_TRACEOFF:
174                 case TSP_TRACEON:
175                         /*
176                          * XXX check to see they are from ourself
177                          */
178                         break;
179
180                 case TSP_TEST:
181                 case TSP_MSITE:
182                         break;
183
184                 case TSP_MASTERUP:
185                         if (!fromnet) {
186                                 if (trace) {
187                                         fprintf(fd, "slave ignored: ");
188                                         print(msg, &from);
189                                 }
190                                 goto loop;
191                         }
192                         break;
193
194                 default:
195                         if (!fromnet
196                             || fromnet->status == IGNORE
197                             || fromnet->status == NOMASTER) {
198                                 if (trace) {
199                                         fprintf(fd, "slave ignored: ");
200                                         print(msg, &from);
201                                 }
202                                 goto loop;
203                         }
204                         break;
205                 }
206
207
208                 /*
209                  * now process the message
210                  */
211                 switch (msg->tsp_type) {
212
213                 case TSP_ADJTIME:
214                         if (fromnet != slavenet)
215                                 break;
216                         if (!good_host_name(msg->tsp_name)) {
217                                 syslog(LOG_NOTICE,
218                                    "attempted time adjustment by %s",
219                                        msg->tsp_name);
220                                 suppress(&from, msg->tsp_name, fromnet);
221                                 break;
222                         }
223                         /*
224                          * Speed up loop detection in case we have a loop.
225                          * Otherwise the clocks can race until the loop
226                          * is found.
227                          */
228                         (void)gettimeofday(&otime, 0);
229                         if (adjtime < otime.tv_sec)
230                                 looptime -= (looptime-otime.tv_sec)/2 + 1;
231
232                         setmaster(msg);
233                         if (seq != msg->tsp_seq) {
234                                 seq = msg->tsp_seq;
235                                 synch(tvtomsround(msg->tsp_time));
236                         }
237                         (void)gettimeofday(&ntime, 0);
238                         electiontime = ntime.tv_sec + delay2;
239                         fastelection = ntime.tv_sec + FASTTOUT;
240                         adjtime = ntime.tv_sec + SAMPLEINTVL*2;
241                         break;
242
243                 case TSP_SETTIME:
244                         if (fromnet != slavenet)
245                                 break;
246                         if (seq == msg->tsp_seq)
247                                 break;
248                         seq = msg->tsp_seq;
249
250                         /* adjust time for residence on the queue */
251                         (void)gettimeofday(&otime, 0);
252                         adj_msg_time(msg,&otime);
253                         /*
254                          * the following line is necessary due to syslog
255                          * calling ctime() which clobbers the static buffer
256                          */
257                         (void)strcpy(olddate, date());
258                         tsp_time_sec = msg->tsp_time.tv_sec;
259                         (void)strcpy(newdate, ctime(&tsp_time_sec));
260
261                         if (!good_host_name(msg->tsp_name)) {
262                                 syslog(LOG_NOTICE,
263                             "attempted time setting by untrusted %s to %s",
264                                        msg->tsp_name, newdate);
265                                 suppress(&from, msg->tsp_name, fromnet);
266                                 break;
267                         }
268
269                         setmaster(msg);
270                         tmptv.tv_sec = msg->tsp_time.tv_sec;
271                         tmptv.tv_usec = msg->tsp_time.tv_usec;
272                         timevalsub(&ntime, &tmptv, &otime);
273                         if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
274                                 /*
275                                  * do not change the clock if we can adjust it
276                                  */
277                                 synch(tvtomsround(ntime));
278                         } else {
279                                 utx.ut_type = OLD_TIME;
280                                 gettimeofday(&utx.ut_tv, NULL);
281                                 pututxline(&utx);
282                                 (void)settimeofday(&tmptv, 0);
283                                 utx.ut_type = NEW_TIME;
284                                 gettimeofday(&utx.ut_tv, NULL);
285                                 pututxline(&utx);
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 }