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