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