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