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