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