]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/timed/timed/master.c
MFV r338866: 9700 ZFS resilvered mirror does not balance reads
[FreeBSD/FreeBSD.git] / usr.sbin / timed / timed / master.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1985, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef lint
33 #if 0
34 static char sccsid[] = "@(#)master.c    8.1 (Berkeley) 6/6/93";
35 #endif
36 static const char rcsid[] =
37   "$FreeBSD$";
38 #endif /* not lint */
39
40 #include "globals.h"
41 #include <sys/file.h>
42 #include <sys/types.h>
43 #include <sys/times.h>
44 #include <setjmp.h>
45 #include <utmpx.h>
46 #include "pathnames.h"
47
48 extern int measure_delta;
49 extern jmp_buf jmpenv;
50 extern int Mflag;
51 extern int justquit;
52
53 static int dictate;
54 static int slvcount;                    /* slaves listening to our clock */
55
56 static void mchgdate(struct tsp *);
57
58 /*
59  * The main function of `master' is to periodically compute the differences
60  * (deltas) between its clock and the clocks of the slaves, to compute the
61  * network average delta, and to send to the slaves the differences between
62  * their individual deltas and the network delta.
63  * While waiting, it receives messages from the slaves (i.e. requests for
64  * master's name, remote requests to set the network time, ...), and
65  * takes the appropriate action.
66  */
67 int
68 master(void)
69 {
70         struct hosttbl *htp;
71         long pollingtime;
72 #define POLLRATE 4
73         int polls;
74         struct timeval wait, ntime;
75         time_t tsp_time_sec;
76         struct tsp *msg, *answer, to;
77         char newdate[32];
78         struct sockaddr_in taddr;
79         char tname[MAXHOSTNAMELEN];
80         struct netinfo *ntp;
81         int i;
82
83         syslog(LOG_NOTICE, "This machine is master");
84         if (trace)
85                 fprintf(fd, "This machine is master\n");
86         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
87                 if (ntp->status == MASTER)
88                         masterup(ntp);
89         }
90         (void)gettimeofday(&ntime, NULL);
91         pollingtime = ntime.tv_sec+3;
92         if (justquit)
93                 polls = 0;
94         else
95                 polls = POLLRATE-1;
96
97 /* Process all outstanding messages before spending the long time necessary
98  *      to update all timers.
99  */
100 loop:
101         (void)gettimeofday(&ntime, NULL);
102         wait.tv_sec = pollingtime - ntime.tv_sec;
103         if (wait.tv_sec < 0)
104                 wait.tv_sec = 0;
105         wait.tv_usec = 0;
106         msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
107         if (!msg) {
108                 (void)gettimeofday(&ntime, NULL);
109                 if (ntime.tv_sec >= pollingtime) {
110                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
111                         get_goodgroup(0);
112
113 /* If a bogus master told us to quit, we can have decided to ignore a
114  * network.  Therefore, periodically try to take over everything.
115  */
116                         polls = (polls + 1) % POLLRATE;
117                         if (0 == polls && nignorednets > 0) {
118                                 trace_msg("Looking for nets to re-master\n");
119                                 for (ntp = nettab; ntp; ntp = ntp->next) {
120                                         if (ntp->status == IGNORE
121                                             || ntp->status == NOMASTER) {
122                                                 lookformaster(ntp);
123                                                 if (ntp->status == MASTER) {
124                                                         masterup(ntp);
125                                                         polls = POLLRATE-1;
126                                                 }
127                                         }
128                                         if (ntp->status == MASTER
129                                             && --ntp->quit_count < 0)
130                                                 ntp->quit_count = 0;
131                                 }
132                                 if (polls != 0)
133                                         setstatus();
134                         }
135
136                         synch(0L);
137
138                         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
139                                 to.tsp_type = TSP_LOOP;
140                                 to.tsp_vers = TSPVERSION;
141                                 to.tsp_seq = sequence++;
142                                 to.tsp_hopcnt = MAX_HOPCNT;
143                                 (void)strcpy(to.tsp_name, hostname);
144                                 bytenetorder(&to);
145                                 if (sendto(sock, (char *)&to,
146                                            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
154
155         } else {
156                 switch (msg->tsp_type) {
157
158                 case TSP_MASTERREQ:
159                         break;
160
161                 case TSP_SLAVEUP:
162                         newslave(msg);
163                         break;
164
165                 case TSP_SETDATE:
166                         /*
167                          * XXX check to see it is from ourself
168                          */
169                         tsp_time_sec = msg->tsp_time.tv_sec;
170                         (void)strlcpy(newdate, ctime(&tsp_time_sec),
171                             sizeof(newdate));
172                         if (!good_host_name(msg->tsp_name)) {
173                                 syslog(LOG_NOTICE,
174                                        "attempted date change by %s to %s",
175                                        msg->tsp_name, newdate);
176                                 spreadtime();
177                                 break;
178                         }
179
180                         mchgdate(msg);
181                         (void)gettimeofday(&ntime, NULL);
182                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
183                         break;
184
185                 case TSP_SETDATEREQ:
186                         if (!fromnet || fromnet->status != MASTER)
187                                 break;
188                         tsp_time_sec = msg->tsp_time.tv_sec;
189                         (void)strlcpy(newdate, ctime(&tsp_time_sec),
190                             sizeof(newdate));
191                         htp = findhost(msg->tsp_name);
192                         if (htp == NULL) {
193                                 syslog(LOG_ERR,
194                                        "attempted SET DATEREQ by uncontrolled %s to %s",
195                                        msg->tsp_name, newdate);
196                                 break;
197                         }
198                         if (htp->seq == msg->tsp_seq)
199                                 break;
200                         htp->seq = msg->tsp_seq;
201                         if (!htp->good) {
202                                 syslog(LOG_NOTICE,
203                                 "attempted SET DATEREQ by untrusted %s to %s",
204                                        msg->tsp_name, newdate);
205                                 spreadtime();
206                                 break;
207                         }
208
209                         mchgdate(msg);
210                         (void)gettimeofday(&ntime, NULL);
211                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
212                         break;
213
214                 case TSP_MSITE:
215                         xmit(TSP_ACK, msg->tsp_seq, &from);
216                         break;
217
218                 case TSP_MSITEREQ:
219                         break;
220
221                 case TSP_TRACEON:
222                         traceon();
223                         break;
224
225                 case TSP_TRACEOFF:
226                         traceoff("Tracing ended at %s\n");
227                         break;
228
229                 case TSP_ELECTION:
230                         if (!fromnet)
231                                 break;
232                         if (fromnet->status == MASTER) {
233                                 pollingtime = 0;
234                                 (void)addmach(msg->tsp_name, &from,fromnet);
235                         }
236                         taddr = from;
237                         (void)strcpy(tname, msg->tsp_name);
238                         to.tsp_type = TSP_QUIT;
239                         (void)strcpy(to.tsp_name, hostname);
240                         answer = acksend(&to, &taddr, tname,
241                                          TSP_ACK, 0, 1);
242                         if (answer == NULL) {
243                                 syslog(LOG_ERR, "election error by %s",
244                                        tname);
245                         }
246                         break;
247
248                 case TSP_CONFLICT:
249                         /*
250                          * After a network partition, there can be
251                          * more than one master: the first slave to
252                          * come up will notify here the situation.
253                          */
254                         if (!fromnet || fromnet->status != MASTER)
255                                 break;
256                         (void)strcpy(to.tsp_name, hostname);
257
258                         /* The other master often gets into the same state,
259                          * with boring results if we stay at it forever.
260                          */
261                         ntp = fromnet;  /* (acksend() can leave fromnet=0 */
262                         for (i = 0; i < 3; i++) {
263                                 to.tsp_type = TSP_RESOLVE;
264                                 (void)strcpy(to.tsp_name, hostname);
265                                 answer = acksend(&to, &ntp->dest_addr,
266                                                  ANYADDR, TSP_MASTERACK,
267                                                  ntp, 0);
268                                 if (!answer)
269                                         break;
270                                 htp = addmach(answer->tsp_name,&from,ntp);
271                                 to.tsp_type = TSP_QUIT;
272                                 msg = acksend(&to, &htp->addr, htp->name,
273                                               TSP_ACK, 0, htp->noanswer);
274                                 if (msg == NULL) {
275                                         syslog(LOG_ERR,
276                                     "no response from %s to CONFLICT-QUIT",
277                                                htp->name);
278                                 }
279                         }
280                         masterup(ntp);
281                         pollingtime = 0;
282                         break;
283
284                 case TSP_RESOLVE:
285                         if (!fromnet || fromnet->status != MASTER)
286                                 break;
287                         /*
288                          * do not want to call synch() while waiting
289                          * to be killed!
290                          */
291                         (void)gettimeofday(&ntime, NULL);
292                         pollingtime = ntime.tv_sec + SAMPLEINTVL;
293                         break;
294
295                 case TSP_QUIT:
296                         doquit(msg);            /* become a slave */
297                         break;
298
299                 case TSP_LOOP:
300                         if (!fromnet || fromnet->status != MASTER
301                             || !strcmp(msg->tsp_name, hostname))
302                                 break;
303                         /*
304                          * We should not have received this from a net
305                          * we are master on.  There must be two masters.
306                          */
307                         htp = addmach(msg->tsp_name, &from,fromnet);
308                         to.tsp_type = TSP_QUIT;
309                         (void)strcpy(to.tsp_name, hostname);
310                         answer = acksend(&to, &htp->addr, htp->name,
311                                          TSP_ACK, 0, 1);
312                         if (!answer) {
313                                 syslog(LOG_WARNING,
314                                 "loop breakage: no reply from %s=%s to QUIT",
315                                     htp->name, inet_ntoa(htp->addr.sin_addr));
316                                 (void)remmach(htp);
317                         }
318
319                 case TSP_TEST:
320                         if (trace) {
321                                 fprintf(fd,
322                 "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
323                 nnets, nmasternets, nslavenets, nignorednets);
324                                 setstatus();
325                         }
326                         pollingtime = 0;
327                         polls = POLLRATE-1;
328                         break;
329
330                 default:
331                         if (trace) {
332                                 fprintf(fd, "garbage message: ");
333                                 print(msg, &from);
334                         }
335                         break;
336                 }
337         }
338         goto loop;
339 }
340
341
342 /*
343  * change the system date on the master
344  */
345 static void
346 mchgdate(struct tsp *msg)
347 {
348         char tname[MAXHOSTNAMELEN];
349         char olddate[32];
350         struct timeval otime, ntime, tmptv;
351         struct utmpx utx;
352
353         (void)strcpy(tname, msg->tsp_name);
354
355         xmit(TSP_DATEACK, msg->tsp_seq, &from);
356
357         (void)strlcpy(olddate, date(), sizeof(olddate));
358
359         /* adjust time for residence on the queue */
360         (void)gettimeofday(&otime, NULL);
361         adj_msg_time(msg,&otime);
362
363         tmptv.tv_sec = msg->tsp_time.tv_sec;
364         tmptv.tv_usec = msg->tsp_time.tv_usec;
365         timevalsub(&ntime, &tmptv, &otime);
366         if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
367                 /*
368                  * do not change the clock if we can adjust it
369                  */
370                 dictate = 3;
371                 synch(tvtomsround(ntime));
372         } else {
373                 utx.ut_type = OLD_TIME;
374                 (void)gettimeofday(&utx.ut_tv, NULL);
375                 pututxline(&utx);
376                 (void)settimeofday(&tmptv, 0);
377                 utx.ut_type = NEW_TIME;
378                 (void)gettimeofday(&utx.ut_tv, NULL);
379                 pututxline(&utx);
380                 spreadtime();
381         }
382
383         syslog(LOG_NOTICE, "date changed by %s from %s",
384                tname, olddate);
385 }
386
387
388 /*
389  * synchronize all of the slaves
390  */
391 void
392 synch(long mydelta)
393 {
394         struct hosttbl *htp;
395         int measure_status;
396         struct timeval check, stop, wait;
397
398         if (slvcount > 0) {
399                 if (trace)
400                         fprintf(fd, "measurements starting at %s\n", date());
401                 (void)gettimeofday(&check, NULL);
402                 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
403                         if (htp->noanswer != 0) {
404                                 measure_status = measure(500, 100,
405                                                          htp->name,
406                                                          &htp->addr,0);
407                         } else {
408                                 measure_status = measure(3000, 100,
409                                                          htp->name,
410                                                          &htp->addr,0);
411                         }
412                         if (measure_status != GOOD) {
413                                 /* The slave did not respond.  We have
414                                  * just wasted lots of time on it.
415                                  */
416                                 htp->delta = HOSTDOWN;
417                                 if (++htp->noanswer >= LOSTHOST) {
418                                         if (trace) {
419                                                 fprintf(fd,
420                                         "purging %s for not answering ICMP\n",
421                                                         htp->name);
422                                                 (void)fflush(fd);
423                                         }
424                                         htp = remmach(htp);
425                                 }
426                         } else {
427                                 htp->delta = measure_delta;
428                         }
429                         (void)gettimeofday(&stop, NULL);
430                         timevalsub(&stop, &stop, &check);
431                         if (stop.tv_sec >= 1) {
432                                 if (trace)
433                                         (void)fflush(fd);
434                                 /*
435                                  * ack messages periodically
436                                  */
437                                 wait.tv_sec = 0;
438                                 wait.tv_usec = 0;
439                                 if (0 != readmsg(TSP_TRACEON,ANYADDR,
440                                                  &wait,0))
441                                         traceon();
442                                 (void)gettimeofday(&check, NULL);
443                         }
444                 }
445                 if (trace)
446                         fprintf(fd, "measurements finished at %s\n", date());
447         }
448         if (!(status & SLAVE)) {
449                 if (!dictate) {
450                         mydelta = networkdelta();
451                 } else {
452                         dictate--;
453                 }
454         }
455         if (trace && (mydelta != 0 || (status & SLAVE)))
456                 fprintf(fd,"local correction of %ld ms.\n", mydelta);
457         correct(mydelta);
458 }
459
460 /*
461  * sends the time to each slave after the master
462  * has received the command to set the network time
463  */
464 void
465 spreadtime(void)
466 {
467         struct hosttbl *htp;
468         struct tsp to;
469         struct tsp *answer;
470         struct timeval tmptv;
471
472 /* Do not listen to the consensus after forcing the time.  This is because
473  *      the consensus takes a while to reach the time we are dictating.
474  */
475         dictate = 2;
476         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
477                 to.tsp_type = TSP_SETTIME;
478                 (void)strcpy(to.tsp_name, hostname);
479                 (void)gettimeofday(&tmptv, NULL);
480                 to.tsp_time.tv_sec = tmptv.tv_sec;
481                 to.tsp_time.tv_usec = tmptv.tv_usec;
482                 answer = acksend(&to, &htp->addr, htp->name,
483                                  TSP_ACK, 0, htp->noanswer);
484                 if (answer == NULL) {
485                         /* We client does not respond, then we have
486                          * just wasted lots of time on it.
487                          */
488                         syslog(LOG_WARNING,
489                                "no reply to SETTIME from %s", htp->name);
490                         if (++htp->noanswer >= LOSTHOST) {
491                                 if (trace) {
492                                         fprintf(fd,
493                                              "purging %s for not answering",
494                                                 htp->name);
495                                         (void)fflush(fd);
496                                 }
497                                 htp = remmach(htp);
498                         }
499                 }
500         }
501 }
502
503 void
504 prthp(clock_t delta)
505 {
506         static time_t next_time;
507         time_t this_time;
508         struct tms tm;
509         struct hosttbl *htp;
510         int length, l;
511         int i;
512
513         if (!fd)                        /* quit if tracing already off */
514                 return;
515
516         this_time = times(&tm);
517         if ((time_t)(this_time + delta) < next_time)
518                 return;
519         next_time = this_time + CLK_TCK;
520
521         fprintf(fd, "host table: %d entries at %s\n", slvcount, date());
522         htp = self.l_fwd;
523         length = 1;
524         for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) {
525                 l = strlen(htp->name) + 1;
526                 if (length+l >= 80) {
527                         fprintf(fd, "\n");
528                         length = 0;
529                 }
530                 length += l;
531                 fprintf(fd, " %s", htp->name);
532         }
533         fprintf(fd, "\n");
534 }
535
536
537 static struct hosttbl *newhost_hash;
538 static struct hosttbl *lasthfree = &hosttbl[0];
539
540
541 struct hosttbl *                        /* answer or 0 */
542 findhost(char *name)
543 {
544         int i, j;
545         struct hosttbl *htp;
546         char *p;
547
548         j= 0;
549         for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++)
550                 j = (j << 2) ^ *p;
551         newhost_hash = &hosttbl[j % NHOSTS];
552
553         htp = newhost_hash;
554         if (htp->name[0] == '\0')
555                 return(0);
556         do {
557                 if (!strcmp(name, htp->name))
558                         return(htp);
559                 htp = htp->h_fwd;
560         } while (htp != newhost_hash);
561         return(0);
562 }
563
564 /*
565  * add a host to the list of controlled machines if not already there
566  */
567 struct hosttbl *
568 addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp)
569 {
570         struct hosttbl *ret, *p, *b, *f;
571
572         ret = findhost(name);
573         if (ret == NULL) {
574                 if (slvcount >= NHOSTS) {
575                         if (trace) {
576                                 fprintf(fd, "no more slots in host table\n");
577                                 prthp(CLK_TCK);
578                         }
579                         syslog(LOG_ERR, "no more slots in host table");
580                         Mflag = 0;
581                         longjmp(jmpenv, 2); /* give up and be a slave */
582                 }
583
584                 /* if our home hash slot is occupied, find a free entry
585                  * in the hash table
586                  */
587                 if (newhost_hash->name[0] != '\0') {
588                         do {
589                                 ret = lasthfree;
590                                 if (++lasthfree > &hosttbl[NHOSTS])
591                                         lasthfree = &hosttbl[1];
592                         } while (ret->name[0] != '\0');
593
594                         if (!newhost_hash->head) {
595                                 /* Move an interloper using our home.  Use
596                                  * scratch pointers in case the new head is
597                                  * pointing to itself.
598                                  */
599                                 f = newhost_hash->h_fwd;
600                                 b = newhost_hash->h_bak;
601                                 f->h_bak = ret;
602                                 b->h_fwd = ret;
603                                 f = newhost_hash->l_fwd;
604                                 b = newhost_hash->l_bak;
605                                 f->l_bak = ret;
606                                 b->l_fwd = ret;
607                                 bcopy(newhost_hash,ret,sizeof(*ret));
608                                 ret = newhost_hash;
609                                 ret->head = 1;
610                                 ret->h_fwd = ret;
611                                 ret->h_bak = ret;
612                         } else {
613                                 /* link to an existing chain in our home
614                                  */
615                                 ret->head = 0;
616                                 p = newhost_hash->h_bak;
617                                 ret->h_fwd = newhost_hash;
618                                 ret->h_bak = p;
619                                 p->h_fwd = ret;
620                                 newhost_hash->h_bak = ret;
621                         }
622                 } else {
623                         ret = newhost_hash;
624                         ret->head = 1;
625                         ret->h_fwd = ret;
626                         ret->h_bak = ret;
627                 }
628                 ret->addr = *addr;
629                 ret->ntp = ntp;
630                 (void)strlcpy(ret->name, name, sizeof(ret->name));
631                 ret->good = good_host_name(name);
632                 ret->l_fwd = &self;
633                 ret->l_bak = self.l_bak;
634                 self.l_bak->l_fwd = ret;
635                 self.l_bak = ret;
636                 slvcount++;
637
638                 ret->noanswer = 0;
639                 ret->need_set = 1;
640
641         } else {
642                 ret->noanswer = (ret->noanswer != 0);
643         }
644
645         /* need to clear sequence number anyhow */
646         ret->seq = 0;
647         return(ret);
648 }
649
650 /*
651  * remove the machine with the given index in the host table.
652  */
653 struct hosttbl *
654 remmach(struct hosttbl *htp)
655 {
656         struct hosttbl *lprv, *hnxt, *f, *b;
657
658         if (trace)
659                 fprintf(fd, "remove %s\n", htp->name);
660
661         /* get out of the lists */
662         htp->l_fwd->l_bak = lprv = htp->l_bak;
663         htp->l_bak->l_fwd = htp->l_fwd;
664         htp->h_fwd->h_bak = htp->h_bak;
665         htp->h_bak->h_fwd = hnxt = htp->h_fwd;
666
667         /* If we are in the home slot, pull up the chain */
668         if (htp->head && hnxt != htp) {
669                 if (lprv == hnxt)
670                         lprv = htp;
671
672                 /* Use scratch pointers in case the new head is pointing to
673                  * itself.
674                  */
675                 f = hnxt->h_fwd;
676                 b = hnxt->h_bak;
677                 f->h_bak = htp;
678                 b->h_fwd = htp;
679                 f = hnxt->l_fwd;
680                 b = hnxt->l_bak;
681                 f->l_bak = htp;
682                 b->l_fwd = htp;
683                 hnxt->head = 1;
684                 bcopy(hnxt, htp, sizeof(*htp));
685                 lasthfree = hnxt;
686         } else {
687                 lasthfree = htp;
688         }
689
690         lasthfree->name[0] = '\0';
691         lasthfree->h_fwd = NULL;
692         lasthfree->l_fwd = NULL;
693         slvcount--;
694
695         return lprv;
696 }
697
698
699 /*
700  * Remove all the machines from the host table that exist on the given
701  * network.  This is called when a master transitions to a slave on a
702  * given network.
703  */
704 void
705 rmnetmachs(struct netinfo *ntp)
706 {
707         struct hosttbl *htp;
708
709         if (trace)
710                 prthp(CLK_TCK);
711         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
712                 if (ntp == htp->ntp)
713                         htp = remmach(htp);
714         }
715         if (trace)
716                 prthp(CLK_TCK);
717 }
718
719 void
720 masterup(struct netinfo *net)
721 {
722         xmit(TSP_MASTERUP, 0, &net->dest_addr);
723
724         /*
725          * Do not tell new slaves our time for a while.  This ensures
726          * we do not tell them to start using our time, before we have
727          * found a good master.
728          */
729         (void)gettimeofday(&net->slvwait, NULL);
730 }
731
732 void
733 newslave(struct tsp *msg)
734 {
735         struct hosttbl *htp;
736         struct tsp *answer, to;
737         struct timeval now, tmptv;
738
739         if (!fromnet || fromnet->status != MASTER)
740                 return;
741
742         htp = addmach(msg->tsp_name, &from,fromnet);
743         htp->seq = msg->tsp_seq;
744         if (trace)
745                 prthp(0);
746
747         /*
748          * If we are stable, send our time to the slave.
749          * Do not go crazy if the date has been changed.
750          */
751         (void)gettimeofday(&now, NULL);
752         if (now.tv_sec >= fromnet->slvwait.tv_sec+3
753             || now.tv_sec < fromnet->slvwait.tv_sec) {
754                 to.tsp_type = TSP_SETTIME;
755                 (void)strcpy(to.tsp_name, hostname);
756                 (void)gettimeofday(&tmptv, NULL);
757                 to.tsp_time.tv_sec = tmptv.tv_sec;
758                 to.tsp_time.tv_usec = tmptv.tv_usec;
759                 answer = acksend(&to, &htp->addr,
760                                  htp->name, TSP_ACK,
761                                  0, htp->noanswer);
762                 if (answer) {
763                         htp->need_set = 0;
764                 } else {
765                         syslog(LOG_WARNING,
766                                "no reply to initial SETTIME from %s",
767                                htp->name);
768                         htp->noanswer = LOSTHOST;
769                 }
770         }
771 }
772
773
774 /*
775  * react to a TSP_QUIT:
776  */
777 void
778 doquit(struct tsp *msg)
779 {
780         if (fromnet->status == MASTER) {
781                 if (!good_host_name(msg->tsp_name)) {
782                         if (fromnet->quit_count <= 0) {
783                                 syslog(LOG_NOTICE,"untrusted %s told us QUIT",
784                                        msg->tsp_name);
785                                 suppress(&from, msg->tsp_name, fromnet);
786                                 fromnet->quit_count = 1;
787                                 return;
788                         }
789                         syslog(LOG_NOTICE, "untrusted %s told us QUIT twice",
790                                msg->tsp_name);
791                         fromnet->quit_count = 2;
792                         fromnet->status = NOMASTER;
793                 } else {
794                         fromnet->status = SLAVE;
795                 }
796                 rmnetmachs(fromnet);
797                 longjmp(jmpenv, 2);             /* give up and be a slave */
798
799         } else {
800                 if (!good_host_name(msg->tsp_name)) {
801                         syslog(LOG_NOTICE, "untrusted %s told us QUIT",
802                                msg->tsp_name);
803                         fromnet->quit_count = 2;
804                 }
805         }
806 }
807
808 void
809 traceon(void)
810 {
811         if (!fd) {
812                 fd = fopen(_PATH_TIMEDLOG, "w");
813                 if (!fd) {
814                         trace = 0;
815                         return;
816                 }
817                 fprintf(fd,"Tracing started at %s\n", date());
818         }
819         trace = 1;
820         get_goodgroup(1);
821         setstatus();
822         prthp(CLK_TCK);
823 }
824
825
826 void
827 traceoff(char *msg)
828 {
829         get_goodgroup(1);
830         setstatus();
831         prthp(CLK_TCK);
832         if (trace) {
833                 fprintf(fd, msg, date());
834                 (void)fclose(fd);
835                 fd = NULL;
836         }
837 #ifdef GPROF
838         moncontrol(0);
839         _mcleanup();
840         moncontrol(1);
841 #endif
842         trace = OFF;
843 }