|
|
1.1 root 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: char copyright[] =
9: "@(#) Copyright (c) 1985 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)timed.c 2.10 (Berkeley) 6/2/86";
15: #endif not lint
16:
17: #include "globals.h"
18: #define TSPTYPES
19: #include <protocols/timed.h>
20: #include <net/if.h>
21: #include <sys/file.h>
22: #include <sys/ioctl.h>
23: #include <setjmp.h>
24:
25: int id;
26: int trace;
27: int sock, sock_raw;
28: int status = 0;
29: int backoff;
30: int slvcount; /* no. of slaves controlled by master */
31: int machup;
32: u_short sequence; /* sequence number */
33: long delay1;
34: long delay2;
35: long random();
36: char hostname[MAXHOSTNAMELEN];
37: struct host hp[NHOSTS];
38: char tracefile[] = "/usr/adm/timed.log";
39: FILE *fd;
40: jmp_buf jmpenv;
41: struct netinfo *nettab = NULL;
42: int nslavenets; /* Number of networks were I could be a slave */
43: int nmasternets; /* Number of networks were I could be a master */
44: int nignorednets; /* Number of ignored networks */
45: int nnets; /* Number of networks I am connected to */
46: struct netinfo *slavenet;
47: struct netinfo *firstslavenet();
48: int Mflag;
49: int justquit = 0;
50:
51: struct nets {
52: char *name;
53: long net;
54: struct nets *next;
55: } *nets = (struct nets *)0;
56:
57: /*
58: * The timedaemons synchronize the clocks of hosts in a local area network.
59: * One daemon runs as master, all the others as slaves. The master
60: * performs the task of computing clock differences and sends correction
61: * values to the slaves.
62: * Slaves start an election to choose a new master when the latter disappears
63: * because of a machine crash, network partition, or when killed.
64: * A resolution protocol is used to kill all but one of the masters
65: * that happen to exist in segments of a partitioned network when the
66: * network partition is fixed.
67: *
68: * Authors: Riccardo Gusella & Stefano Zatti
69: */
70:
71: main(argc, argv)
72: int argc;
73: char **argv;
74: {
75: int on;
76: int ret;
77: long seed;
78: int nflag, iflag;
79: struct timeval time;
80: struct servent *srvp;
81: long casual();
82: char *date();
83: int n;
84: int flag;
85: char buf[BUFSIZ];
86: struct ifconf ifc;
87: struct ifreq ifreq, *ifr;
88: register struct netinfo *ntp;
89: struct netinfo *ntip;
90: struct netinfo *savefromnet;
91: struct sockaddr_in server;
92: u_short port;
93: uid_t getuid();
94:
95: #ifdef lint
96: ntip = NULL;
97: #endif
98:
99: Mflag = 0;
100: on = 1;
101: backoff = 1;
102: trace = OFF;
103: nflag = OFF;
104: iflag = OFF;
105: openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
106:
107: if (getuid() != 0) {
108: fprintf(stderr, "Timed: not superuser\n");
109: exit(1);
110: }
111:
112: while (--argc > 0 && **++argv == '-') {
113: (*argv)++;
114: do {
115: switch (**argv) {
116:
117: case 'M':
118: Mflag = 1;
119: break;
120: case 't':
121: trace = ON;
122: break;
123: case 'n':
124: argc--, argv++;
125: if (iflag) {
126: fprintf(stderr,
127: "timed: -i and -n make no sense together\n");
128: } else {
129: nflag = ON;
130: addnetname(*argv);
131: }
132: while (*(++(*argv)+1)) ;
133: break;
134: case 'i':
135: argc--, argv++;
136: if (nflag) {
137: fprintf(stderr,
138: "timed: -i and -n make no sense together\n");
139: } else {
140: iflag = ON;
141: addnetname(*argv);
142: }
143: while (*(++(*argv)+1)) ;
144: break;
145: default:
146: fprintf(stderr, "timed: -%c: unknown option\n",
147: **argv);
148: break;
149: }
150: } while (*++(*argv));
151: }
152:
153: #ifndef DEBUG
154: if (fork())
155: exit(0);
156: { int s;
157: for (s = getdtablesize(); s >= 0; --s)
158: (void) close(s);
159: (void) open("/dev/null", 0);
160: (void) dup2(0, 1);
161: (void) dup2(0, 2);
162: s = open("/dev/tty", 2);
163: if (s >= 0) {
164: (void) ioctl(s, TIOCNOTTY, (char *)0);
165: (void) close(s);
166: }
167: }
168: #endif
169:
170: if (trace == ON) {
171: fd = fopen(tracefile, "w");
172: setlinebuf(fd);
173: fprintf(fd, "Tracing started on: %s\n\n",
174: date());
175: }
176:
177: srvp = getservbyname("timed", "udp");
178: if (srvp == 0) {
179: syslog(LOG_CRIT, "unknown service 'timed/udp'");
180: exit(1);
181: }
182: port = srvp->s_port;
183: server.sin_port = srvp->s_port;
184: server.sin_family = AF_INET;
185: sock = socket(AF_INET, SOCK_DGRAM, 0);
186: if (sock < 0) {
187: syslog(LOG_ERR, "socket: %m");
188: exit(1);
189: }
190: if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
191: sizeof(on)) < 0) {
192: syslog(LOG_ERR, "setsockopt: %m");
193: exit(1);
194: }
195: if (bind(sock, &server, sizeof(server))) {
196: if (errno == EADDRINUSE)
197: syslog(LOG_ERR, "server already running");
198: else
199: syslog(LOG_ERR, "bind: %m");
200: exit(1);
201: }
202:
203: /* choose a unique seed for random number generation */
204: (void)gettimeofday(&time, (struct timezone *)0);
205: seed = time.tv_sec + time.tv_usec;
206: srandom(seed);
207:
208: sequence = random(); /* initial seq number */
209:
210: /* rounds kernel variable time to multiple of 5 ms. */
211: time.tv_sec = 0;
212: time.tv_usec = -((time.tv_usec/1000) % 5) * 1000;
213: (void)adjtime(&time, (struct timeval *)0);
214:
215: id = getpid();
216:
217: if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
218: syslog(LOG_ERR, "gethostname: %m");
219: exit(1);
220: }
221: hp[0].name = hostname;
222:
223: if (nflag || iflag) {
224: struct netent *getnetent();
225: struct netent *n;
226: struct nets *np;
227: for ( np = nets ; np ; np = np->next) {
228: n = getnetbyname(np->name);
229: if (n == NULL) {
230: syslog(LOG_ERR, "getnetbyname: unknown net %s",
231: np->name);
232: exit(1);
233: }
234: np->net = n->n_net;
235: }
236: }
237: ifc.ifc_len = sizeof(buf);
238: ifc.ifc_buf = buf;
239: if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
240: syslog(LOG_ERR, "get interface configuration: %m");
241: exit(1);
242: }
243: n = ifc.ifc_len/sizeof(struct ifreq);
244: ntp = NULL;
245: for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
246: if (ifr->ifr_addr.sa_family != AF_INET)
247: continue;
248: ifreq = *ifr;
249: if (ntp == NULL)
250: ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
251: ntp->my_addr =
252: ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
253: if (ioctl(sock, SIOCGIFFLAGS,
254: (char *)&ifreq) < 0) {
255: syslog(LOG_ERR, "get interface flags: %m");
256: continue;
257: }
258: if ((ifreq.ifr_flags & IFF_UP) == 0 ||
259: ((ifreq.ifr_flags & IFF_BROADCAST) == 0 &&
260: (ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) {
261: continue;
262: }
263: if (ifreq.ifr_flags & IFF_BROADCAST)
264: flag = 1;
265: else
266: flag = 0;
267: if (ioctl(sock, SIOCGIFNETMASK,
268: (char *)&ifreq) < 0) {
269: syslog(LOG_ERR, "get netmask: %m");
270: continue;
271: }
272: ntp->mask = ((struct sockaddr_in *)
273: &ifreq.ifr_addr)->sin_addr.s_addr;
274: if (flag) {
275: if (ioctl(sock, SIOCGIFBRDADDR,
276: (char *)&ifreq) < 0) {
277: syslog(LOG_ERR, "get broadaddr: %m");
278: continue;
279: }
280: ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
281: } else {
282: if (ioctl(sock, SIOCGIFDSTADDR,
283: (char *)&ifreq) < 0) {
284: syslog(LOG_ERR, "get destaddr: %m");
285: continue;
286: }
287: ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
288: }
289: ntp->dest_addr.sin_port = port;
290: if (nflag || iflag) {
291: u_long addr, mask;
292: struct nets *n;
293:
294: addr = ntohl(ntp->dest_addr.sin_addr.s_addr);
295: mask = ntohl(ntp->mask);
296: while ((mask & 1) == 0) {
297: addr >>= 1;
298: mask >>= 1;
299: }
300: for (n = nets ; n ; n = n->next)
301: if (addr == n->net)
302: break;
303: if (nflag && !n || iflag && n)
304: continue;
305: }
306: ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr;
307: ntp->next = NULL;
308: if (nettab == NULL) {
309: nettab = ntp;
310: } else {
311: ntip->next = ntp;
312: }
313: ntip = ntp;
314: ntp = NULL;
315: }
316: if (ntp)
317: (void) free((char *)ntp);
318: if (nettab == NULL) {
319: syslog(LOG_ERR, "No network usable");
320: exit(1);
321: }
322:
323: for (ntp = nettab; ntp != NULL; ntp = ntp->next)
324: lookformaster(ntp);
325: setstatus();
326: /*
327: * Take care of some basic initialization.
328: */
329: /* us. delay to be used in response to broadcast */
330: delay1 = casual((long)10000, 200000);
331:
332: /* election timer delay in secs. */
333: delay2 = casual((long)MINTOUT, (long)MAXTOUT);
334:
335: if (Mflag) {
336: /* open raw socket used to measure time differences */
337: sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
338: if (sock_raw < 0) {
339: syslog(LOG_ERR, "opening raw socket: %m");
340: exit (1);
341: }
342:
343: /*
344: * number (increased by 1) of slaves controlled by master:
345: * used in master.c, candidate.c, networkdelta.c, and
346: * correct.c
347: */
348: slvcount = 1;
349: ret = setjmp(jmpenv);
350:
351: switch (ret) {
352:
353: case 0:
354: makeslave(firstslavenet());
355: setstatus();
356: break;
357: case 1:
358: /* Just lost our master */
359: setstatus();
360: slavenet->status = election(slavenet);
361: checkignorednets();
362: setstatus();
363: if (slavenet->status == MASTER)
364: makeslave(firstslavenet());
365: else
366: makeslave(slavenet);
367: setstatus();
368: break;
369: case 2:
370: /* Just been told to quit */
371: fromnet->status = SLAVE;
372: setstatus();
373: savefromnet = fromnet;
374: rmnetmachs(fromnet);
375: checkignorednets();
376: if (slavenet)
377: makeslave(slavenet);
378: else
379: makeslave(savefromnet);
380: setstatus();
381: justquit = 1;
382: break;
383:
384: default:
385: /* this should not happen */
386: syslog(LOG_ERR, "Attempt to enter invalid state");
387: break;
388: }
389:
390: if (status == MASTER)
391: master();
392: else
393: slave();
394: } else {
395: /* if Mflag is not set timedaemon is forced to act as a slave */
396: status = SLAVE;
397: if (setjmp(jmpenv)) {
398: setstatus();
399: checkignorednets();
400: }
401: makeslave(firstslavenet());
402: for (ntp = nettab; ntp != NULL; ntp = ntp->next)
403: if (ntp->status == MASTER)
404: ntp->status = IGNORE;
405: setstatus();
406: slave();
407: }
408: }
409:
410: /*
411: * Try to become master over ignored nets..
412: */
413: checkignorednets()
414: {
415: register struct netinfo *ntp;
416: for (ntp = nettab; ntp != NULL; ntp = ntp->next)
417: if (ntp->status == IGNORE)
418: lookformaster(ntp);
419: }
420:
421: lookformaster(ntp)
422: register struct netinfo *ntp;
423: {
424: struct tsp resp, conflict, *answer, *readmsg(), *acksend();
425: struct timeval time;
426: char mastername[MAXHOSTNAMELEN];
427: struct sockaddr_in masteraddr;
428:
429: ntp->status = SLAVE;
430: /* look for master */
431: resp.tsp_type = TSP_MASTERREQ;
432: (void)strcpy(resp.tsp_name, hostname);
433: answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR,
434: TSP_MASTERACK, ntp);
435: if (answer == NULL) {
436: /*
437: * Various conditions can cause conflict: race between
438: * two just started timedaemons when no master is
439: * present, or timedaemon started during an election.
440: * Conservative approach is taken: give up and became a
441: * slave postponing election of a master until first
442: * timer expires.
443: */
444: time.tv_sec = time.tv_usec = 0;
445: answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR,
446: &time, ntp);
447: if (answer != NULL) {
448: ntp->status = SLAVE;
449: return;
450: }
451:
452: time.tv_sec = time.tv_usec = 0;
453: answer = readmsg(TSP_MASTERUP, (char *)ANYADDR,
454: &time, ntp);
455: if (answer != NULL) {
456: ntp->status = SLAVE;
457: return;
458: }
459:
460: time.tv_sec = time.tv_usec = 0;
461: answer = readmsg(TSP_ELECTION, (char *)ANYADDR,
462: &time, ntp);
463: if (answer != NULL) {
464: ntp->status = SLAVE;
465: return;
466: }
467: ntp->status = MASTER;
468: } else {
469: (void)strcpy(mastername, answer->tsp_name);
470: masteraddr = from;
471:
472: /*
473: * If network has been partitioned, there might be other
474: * masters; tell the one we have just acknowledged that
475: * it has to gain control over the others.
476: */
477: time.tv_sec = 0;
478: time.tv_usec = 300000;
479: answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time,
480: ntp);
481: /*
482: * checking also not to send CONFLICT to ack'ed master
483: * due to duplicated MASTERACKs
484: */
485: if (answer != NULL &&
486: strcmp(answer->tsp_name, mastername) != 0) {
487: conflict.tsp_type = TSP_CONFLICT;
488: (void)strcpy(conflict.tsp_name, hostname);
489: if (acksend(&conflict, &masteraddr, mastername,
490: TSP_ACK, (struct netinfo *)NULL) == NULL) {
491: syslog(LOG_ERR,
492: "error on sending TSP_CONFLICT");
493: exit(1);
494: }
495: }
496: }
497: }
498: /*
499: * based on the current network configuration, set the status, and count
500: * networks;
501: */
502: setstatus()
503: {
504: register struct netinfo *ntp;
505:
506: status = 0;
507: nmasternets = nslavenets = nnets = nignorednets = 0;
508: if (trace)
509: fprintf(fd, "Net status:\n");
510: for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
511: switch ((int)ntp->status) {
512: case MASTER:
513: nmasternets++;
514: break;
515: case SLAVE:
516: nslavenets++;
517: break;
518: case IGNORE:
519: nignorednets++;
520: break;
521: }
522: if (trace) {
523: fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
524: switch ((int)ntp->status) {
525: case MASTER:
526: fprintf(fd, "MASTER\n");
527: break;
528: case SLAVE:
529: fprintf(fd, "SLAVE\n");
530: break;
531: case IGNORE:
532: fprintf(fd, "IGNORE\n");
533: break;
534: default:
535: fprintf(fd, "invalid state %d\n");
536: break;
537: }
538: }
539: nnets++;
540: status |= ntp->status;
541: }
542: status &= ~IGNORE;
543: if (trace)
544: fprintf(fd,
545: "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
546: nnets, nmasternets, nslavenets, nignorednets);
547: }
548:
549: makeslave(net)
550: struct netinfo *net;
551: {
552: register struct netinfo *ntp;
553:
554: for (ntp = nettab; ntp != NULL; ntp = ntp->next)
555: if (ntp->status == SLAVE && ntp != net)
556: ntp->status = IGNORE;
557: slavenet = net;
558: }
559:
560: struct netinfo *
561: firstslavenet()
562: {
563: register struct netinfo *ntp;
564:
565: for (ntp = nettab; ntp != NULL; ntp = ntp->next)
566: if (ntp->status == SLAVE)
567: return (ntp);
568: return ((struct netinfo *)0);
569: }
570:
571: /*
572: * `casual' returns a random number in the range [inf, sup]
573: */
574:
575: long
576: casual(inf, sup)
577: long inf;
578: long sup;
579: {
580: float value;
581:
582: value = (float)(random() & 0x7fffffff) / 0x7fffffff;
583: return(inf + (sup - inf) * value);
584: }
585:
586: char *
587: date()
588: {
589: char *ctime();
590: struct timeval tv;
591:
592: (void)gettimeofday(&tv, (struct timezone *)0);
593: return (ctime(&tv.tv_sec));
594: }
595:
596: addnetname(name)
597: char *name;
598: {
599: register struct nets **netlist = &nets;
600:
601: while (*netlist)
602: netlist = &((*netlist)->next);
603: *netlist = (struct nets *)malloc(sizeof **netlist);
604: if (*netlist == (struct nets *)0) {
605: syslog(LOG_ERR, "malloc failed");
606: exit(1);
607: }
608: bzero((char *)*netlist, sizeof(**netlist));
609: (*netlist)->name = name;
610: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.