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