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