add MAXADJ, and some comments
[unix-history] / usr / src / usr.sbin / timed / timed / master.c
CommitLineData
dc32c900
RG
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
e81c670f 8static char sccsid[] = "@(#)master.c 2.7 (Berkeley) %G%";
dc32c900
RG
9#endif not lint
10
11#include "globals.h"
12#include <protocols/timed.h>
e81c670f 13#include <sys/file.h>
dc32c900 14#include <setjmp.h>
e81c670f 15#include <utmp.h>
dc32c900 16
dc32c900 17extern int machup;
dc32c900 18extern int measure_delta;
75d5ce8a 19extern jmp_buf jmpenv;
dc32c900 20
e472b464
JB
21extern short sequence;
22
dc32c900
RG
23#ifdef MEASURE
24int header;
25char *fi;
26FILE *fp;
27#endif
28
29/*
30 * The main function of `master' is to periodically compute the differences
31 * (deltas) between its clock and the clocks of the slaves, to compute the
32 * network average delta, and to send to the slaves the differences between
33 * their individual deltas and the network delta.
34 * While waiting, it receives messages from the slaves (i.e. requests for
35 * master's name, remote requests to set the network time, ...), and
36 * takes the appropriate action.
37 */
38
39master()
40{
41 int ind;
dc32c900
RG
42 long pollingtime;
43 struct timeval wait;
44 struct timeval time;
e81c670f 45 struct timeval otime;
dc32c900 46 struct timezone tzone;
dc32c900
RG
47 struct tsp *msg, to;
48 struct sockaddr_in saveaddr;
dc32c900
RG
49 int findhost();
50 char *date();
dc32c900
RG
51 struct tsp *readmsg();
52 struct tsp *answer, *acksend();
65215728 53 char olddate[32];
75d5ce8a
JB
54 struct sockaddr_in server;
55 register struct netinfo *ntp;
dc32c900
RG
56
57#ifdef MEASURE
58 fi = "/usr/adm/timed.masterlog";
59 fp = fopen(fi, "w");
9799484a 60 setlinebuf(fp);
dc32c900
RG
61#endif
62
f99c5f73 63 syslog(LOG_INFO, "THIS MACHINE IS MASTER");
dc32c900
RG
64 if (trace)
65 fprintf(fd, "THIS MACHINE IS MASTER\n");
66
75d5ce8a
JB
67 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
68 if (ntp->status == MASTER)
69 masterup(ntp);
dc32c900
RG
70 pollingtime = 0;
71
72loop:
73 (void)gettimeofday(&time, (struct timezone *)0);
74 if (time.tv_sec >= pollingtime) {
75 pollingtime = time.tv_sec + SAMPLEINTVL;
75d5ce8a 76 synch(0L);
e472b464
JB
77
78 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
79 to.tsp_type = TSP_LOOP;
80 to.tsp_vers = TSPVERSION;
81 to.tsp_seq = sequence;
82 to.tsp_hopcnt = 10;
83 (void)strcpy(to.tsp_name, hostname);
84 bytenetorder(&to);
85 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
86 &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
87 syslog(LOG_ERR, "sendto: %m");
88 exit(1);
89 if (++sequence > MAXSEQ)
90 sequence = 1;
91 }
92 }
dc32c900
RG
93 }
94
95 wait.tv_sec = pollingtime - time.tv_sec;
96 wait.tv_usec = 0;
75d5ce8a 97 msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
dc32c900
RG
98 if (msg != NULL) {
99 switch (msg->tsp_type) {
100
101 case TSP_MASTERREQ:
dc32c900
RG
102 break;
103 case TSP_SLAVEUP:
9a957f87
JB
104 ind = addmach(msg->tsp_name, &from);
105 newslave(ind, msg->tsp_seq);
dc32c900 106 break;
5807ba7f 107 case TSP_SETDATE:
dc32c900
RG
108 saveaddr = from;
109 msg->tsp_time.tv_usec = 0;
65215728
JB
110 /*
111 * the following line is necessary due to syslog
112 * calling ctime() which clobbers the static buffer
113 */
114 (void)strcpy(olddate, date());
dc32c900 115 (void)gettimeofday(&time, &tzone);
e81c670f 116 otime = time;
5807ba7f
JB
117 time.tv_sec = msg->tsp_time.tv_sec;
118 time.tv_usec = msg->tsp_time.tv_usec;
dc32c900
RG
119 time.tv_sec++;
120 (void)settimeofday(&time, &tzone);
f99c5f73 121 syslog(LOG_NOTICE, "date changed from: %s", olddate);
e81c670f 122 logwtmp(otime, time);
dc32c900
RG
123 msg->tsp_type = TSP_DATEACK;
124 msg->tsp_vers = TSPVERSION;
125 (void)strcpy(msg->tsp_name, hostname);
126 bytenetorder(msg);
dc32c900 127 if (sendto(sock, (char *)msg, sizeof(struct tsp), 0,
75d5ce8a 128 &saveaddr, sizeof(struct sockaddr_in)) < 0) {
f99c5f73 129 syslog(LOG_ERR, "sendto: %m");
dc32c900
RG
130 exit(1);
131 }
132 spreadtime();
133 pollingtime = 0;
134 break;
5807ba7f 135 case TSP_SETDATEREQ:
dc32c900
RG
136 ind = findhost(msg->tsp_name);
137 if (ind < 0) {
f99c5f73
JB
138 syslog(LOG_ERR,
139 "DATEREQ from uncontrolled machine");
140 break;
dc32c900
RG
141 }
142 if (hp[ind].seq != msg->tsp_seq) {
143 hp[ind].seq = msg->tsp_seq;
144 msg->tsp_time.tv_usec = 0;
65215728
JB
145 /*
146 * the following line is necessary due to syslog
147 * calling ctime() which clobbers the static buffer
148 */
149 (void)strcpy(olddate, date());
dc32c900 150 (void)gettimeofday(&time, &tzone);
e81c670f 151 otime = time;
5807ba7f
JB
152 time.tv_sec = msg->tsp_time.tv_sec;
153 time.tv_usec = msg->tsp_time.tv_usec;
dc32c900
RG
154 time.tv_sec++;
155 (void)settimeofday(&time, &tzone);
f99c5f73
JB
156 syslog(LOG_NOTICE,
157 "date changed by %s from: %s",
158 msg->tsp_name, olddate);
e81c670f 159 logwtmp(otime, time);
dc32c900
RG
160 spreadtime();
161 pollingtime = 0;
162 }
163 break;
164 case TSP_MSITE:
dc32c900
RG
165 case TSP_MSITEREQ:
166 break;
167 case TSP_TRACEON:
168 if (!(trace)) {
75d5ce8a 169 fd = fopen(tracefile, "w");
9799484a 170 setlinebuf(fd);
dc32c900
RG
171 fprintf(fd, "Tracing started on: %s\n\n",
172 date());
dc32c900
RG
173 }
174 trace = ON;
175 break;
176 case TSP_TRACEOFF:
177 if (trace) {
178 fprintf(fd, "Tracing ended on: %s\n", date());
f99c5f73 179 (void)fclose(fd);
dc32c900 180 }
75d5ce8a
JB
181#ifdef GPROF
182 moncontrol(0);
183 _mcleanup();
184 moncontrol(1);
185#endif
dc32c900
RG
186 trace = OFF;
187 break;
188 case TSP_ELECTION:
189 to.tsp_type = TSP_QUIT;
190 (void)strcpy(to.tsp_name, hostname);
191 server = from;
75d5ce8a
JB
192 answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
193 (struct netinfo *)NULL);
dc32c900 194 if (answer == NULL) {
f99c5f73 195 syslog(LOG_ERR, "election error");
dc32c900 196 } else {
75d5ce8a 197 (void) addmach(msg->tsp_name, &from);
dc32c900
RG
198 }
199 pollingtime = 0;
200 break;
201 case TSP_CONFLICT:
202 /*
203 * After a network partition, there can be
204 * more than one master: the first slave to
205 * come up will notify here the situation.
206 */
207
208 (void)strcpy(to.tsp_name, hostname);
209
9a957f87 210 if (fromnet == NULL)
75d5ce8a 211 break;
dc32c900
RG
212 for(;;) {
213 to.tsp_type = TSP_RESOLVE;
9a957f87
JB
214 answer = acksend(&to, &fromnet->dest_addr,
215 (char *)ANYADDR, TSP_MASTERACK, fromnet);
dc32c900
RG
216 if (answer == NULL)
217 break;
dc32c900
RG
218 to.tsp_type = TSP_QUIT;
219 server = from;
b6cf6f3e
JB
220 msg = acksend(&to, &server, answer->tsp_name,
221 TSP_ACK, (struct netinfo *)NULL);
dc32c900 222 if (msg == NULL) {
f99c5f73
JB
223 syslog(LOG_ERR, "error on sending QUIT");
224 } else {
75d5ce8a 225 (void) addmach(answer->tsp_name, &from);
dc32c900
RG
226 }
227 }
9a957f87 228 masterup(fromnet);
dc32c900
RG
229 pollingtime = 0;
230 break;
231 case TSP_RESOLVE:
232 /*
233 * do not want to call synch() while waiting
234 * to be killed!
235 */
236 (void)gettimeofday(&time, (struct timezone *)0);
237 pollingtime = time.tv_sec + SAMPLEINTVL;
238 break;
239 case TSP_QUIT:
240 /* become slave */
241#ifdef MEASURE
f99c5f73 242 (void)fclose(fp);
dc32c900
RG
243#endif
244 longjmp(jmpenv, 2);
245 break;
e472b464
JB
246 case TSP_LOOP:
247 /*
248 * We should not have received this from a net
249 * we are master on. There must be two masters
250 * in this case.
251 */
252 to.tsp_type = TSP_QUIT;
253 (void)strcpy(to.tsp_name, hostname);
254 server = from;
255 answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
256 (struct netinfo *)NULL);
257 if (answer == NULL) {
258 syslog(LOG_ERR, "election error");
259 } else {
260 (void)addmach(msg->tsp_name, &from);
261 }
dc32c900
RG
262 default:
263 if (trace) {
264 fprintf(fd, "garbage: ");
9a957f87 265 print(msg, &from);
dc32c900
RG
266 }
267 break;
268 }
269 }
270 goto loop;
271}
272
273/*
274 * `synch' synchronizes all the slaves by calling measure,
275 * networkdelta and correct
276 */
277
75d5ce8a
JB
278synch(mydelta)
279long mydelta;
dc32c900
RG
280{
281 int i;
282 int measure_status;
283 long netdelta;
284 struct timeval tack;
285#ifdef MEASURE
286#define MAXLINES 8
f99c5f73 287 static int lines = 1;
dc32c900
RG
288 struct timeval start, end;
289#endif
290 int measure();
291 int correct();
292 long networkdelta();
293 char *date();
294
295 if (slvcount > 1) {
296#ifdef MEASURE
297 (void)gettimeofday(&start, (struct timezone *)0);
298 if (header == ON || --lines == 0) {
299 fprintf(fp, "%s\n", date());
300 for (i=0; i<slvcount; i++)
301 fprintf(fp, "%.7s\t", hp[i].name);
302 fprintf(fp, "\n");
303 lines = MAXLINES;
304 header = OFF;
305 }
306#endif
307 machup = 1;
308 hp[0].delta = 0;
309 for(i=1; i<slvcount; i++) {
dc32c900 310 tack.tv_sec = 0;
5807ba7f
JB
311 tack.tv_usec = 500000;
312 if ((measure_status = measure(&tack, &hp[i].addr)) <0) {
f99c5f73 313 syslog(LOG_ERR, "measure: %m");
dc32c900
RG
314 exit(1);
315 }
316 hp[i].delta = measure_delta;
317 if (measure_status == GOOD)
318 machup++;
319 }
75d5ce8a
JB
320 if (status & SLAVE) {
321 /* called by a submaster */
322 if (trace)
323 fprintf(fd, "submaster correct: %d ms.\n",
324 mydelta);
325 correct(mydelta);
326 } else {
327 if (machup > 1) {
328 netdelta = networkdelta();
329 if (trace)
330 fprintf(fd,
331 "master correct: %d ms.\n",
332 mydelta);
333 correct(netdelta);
334 }
dc32c900
RG
335 }
336#ifdef MEASURE
337 gettimeofday(&end, 0);
338 end.tv_sec -= start.tv_sec;
339 end.tv_usec -= start.tv_usec;
340 if (end.tv_usec < 0) {
341 end.tv_sec -= 1;
342 end.tv_usec += 1000000;
343 }
344 fprintf(fp, "%d ms.\n", (end.tv_sec*1000+end.tv_usec/1000));
dc32c900
RG
345#endif
346 for(i=1; i<slvcount; i++) {
347 if (hp[i].delta == HOSTDOWN) {
9a957f87 348 rmmach(i);
dc32c900
RG
349#ifdef MEASURE
350 header = ON;
351#endif
352 }
353 }
75d5ce8a
JB
354 } else {
355 if (status & SLAVE) {
356 correct(mydelta);
357 }
dc32c900
RG
358 }
359}
360
361/*
362 * 'spreadtime' sends the time to each slave after the master
363 * has received the command to set the network time
364 */
365
366spreadtime()
367{
368 int i;
dc32c900
RG
369 struct tsp to;
370 struct tsp *answer, *acksend();
371
372 for(i=1; i<slvcount; i++) {
dc32c900 373 to.tsp_type = TSP_SETTIME;
dc32c900 374 (void)strcpy(to.tsp_name, hostname);
f99c5f73 375 (void)gettimeofday(&to.tsp_time, (struct timezone *)0);
75d5ce8a
JB
376 answer = acksend(&to, &hp[i].addr, hp[i].name, TSP_ACK,
377 (struct netinfo *)NULL);
dc32c900 378 if (answer == NULL) {
f99c5f73 379 syslog(LOG_ERR, "ERROR ON SETTIME machine: %s", hp[i].name);
dc32c900
RG
380 }
381 }
382}
383
384findhost(name)
385char *name;
386{
387 int i;
388 int ind;
389
390 ind = -1;
391 for (i=1; i<slvcount; i++) {
392 if (strcmp(name, hp[i].name) == 0) {
393 ind = i;
394 break;
395 }
396 }
397 return(ind);
398}
399
400/*
401 * 'addmach' adds a host to the list of controlled machines
402 * if not already there
403 */
404
75d5ce8a 405addmach(name, addr)
dc32c900 406char *name;
75d5ce8a 407struct sockaddr_in *addr;
dc32c900
RG
408{
409 int ret;
410 int findhost();
dc32c900
RG
411
412 ret = findhost(name);
413 if (ret < 0) {
75d5ce8a 414 hp[slvcount].addr = *addr;
f99c5f73
JB
415 hp[slvcount].name = (char *)malloc(MAXHOSTNAMELEN);
416 (void)strcpy(hp[slvcount].name, name);
dc32c900
RG
417 hp[slvcount].seq = 0;
418 ret = slvcount;
419 if (slvcount < NHOSTS)
420 slvcount++;
421 else {
f99c5f73 422 syslog(LOG_ALERT, "no more slots in host table");
dc32c900
RG
423 }
424 } else {
425 /* need to clear sequence number anyhow */
426 hp[ret].seq = 0;
427 }
428#ifdef MEASURE
429 header = ON;
430#endif
431 return(ret);
432}
433
4b50a4be
JB
434/*
435 * Remove all the machines from the host table that exist on the given
436 * network. This is called when a master transitions to a slave on a
437 * given network.
438 */
439
440rmnetmachs(ntp)
441 register struct netinfo *ntp;
442{
443 int i;
444
445 if (trace)
446 prthp();
447 for (i = 1; i < slvcount; i++)
448 if ((hp[i].addr.sin_addr.s_addr & ntp->mask) == ntp->net)
449 rmmach(i--);
450 if (trace)
451 prthp();
452}
453
454/*
455 * remove the machine with the given index in the host table.
456 */
457rmmach(ind)
458 int ind;
459{
460 if (trace)
461 fprintf(fd, "rmmach: %s\n", hp[ind].name);
9a957f87
JB
462 free(hp[ind].name);
463 hp[ind] = hp[--slvcount];
4b50a4be
JB
464}
465
dc32c900
RG
466prthp()
467{
468 int i;
469
470 fprintf(fd, "host table:");
471 for (i=1; i<slvcount; i++)
472 fprintf(fd, " %s", hp[i].name);
473 fprintf(fd, "\n");
474}
475
75d5ce8a
JB
476masterup(net)
477struct netinfo *net;
dc32c900
RG
478{
479 struct timeval wait;
dc32c900 480 struct tsp to, *msg, *readmsg();
9a957f87 481 int ind;
dc32c900
RG
482
483 to.tsp_type = TSP_MASTERUP;
75d5ce8a 484 to.tsp_vers = TSPVERSION;
dc32c900 485 (void)strcpy(to.tsp_name, hostname);
75d5ce8a
JB
486 bytenetorder(&to);
487 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, &net->dest_addr,
488 sizeof(struct sockaddr_in)) < 0) {
489 syslog(LOG_ERR, "sendto: %m");
490 exit(1);
491 }
dc32c900
RG
492
493 for (;;) {
494 wait.tv_sec = 1;
495 wait.tv_usec = 0;
75d5ce8a 496 msg = readmsg(TSP_SLAVEUP, (char *)ANYADDR, &wait, net);
dc32c900 497 if (msg != NULL) {
9a957f87 498 ind = addmach(msg->tsp_name, &from);
dc32c900
RG
499 } else
500 break;
501 }
502}
9a957f87
JB
503
504newslave(ind, seq)
505{
506 struct tsp to;
507 struct tsp *answer, *acksend();
508 struct timeval mytime;
509
510 if (trace)
511 prthp();
512 if (seq == 0 || hp[ind].seq != seq) {
513 hp[ind].seq = seq;
514 to.tsp_type = TSP_SETTIME;
515 (void)strcpy(to.tsp_name, hostname);
516 /*
517 * give the upcoming slave the time
518 * to check its input queue before
519 * setting the time
520 */
521 sleep(1);
522 to.tsp_time.tv_usec = 0;
523 (void) gettimeofday(&mytime,
524 (struct timezone *)0);
525 to.tsp_time.tv_sec = mytime.tv_sec;
526 answer = acksend(&to, &hp[ind].addr,
527 hp[ind].name, TSP_ACK,
528 (struct netinfo *)NULL);
529 if (answer == NULL) {
530 syslog(LOG_ERR,
531 "ERROR ON SETTIME machine: %s",
532 hp[ind].name);
533 rmmach(ind);
534 }
535 }
536}
e81c670f
JL
537
538char *wtmpfile = "/usr/adm/wtmp";
539struct utmp wtmp[2] = {
540 { "|", "", "", 0 },
541 { "{", "", "", 0 }
542};
543
544/*
545 * Rounding doesn't work well because new time is always
546 * truncated, but oldtime is normally distributed.
547 */
548logwtmp(otime, ntime)
549struct timeval otime, ntime;
550{
551 int f;
552
553 if (otime.tv_sec == ntime.tv_sec)
554 return;
555 wtmp[0].ut_time = otime.tv_sec; /* +(otime.tv_usec + 500000)/1000000;*/
556 wtmp[1].ut_time = ntime.tv_sec; /* +(ntime.tv_usec + 500000)/1000000;*/
557 if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) {
558 (void) write(f, (char *)wtmp, sizeof(wtmp));
559 (void) close(f);
560 }
561}