1251af36eSbostic /*-
2*24002341Sbostic  * Copyright (c) 1985, 1993
3*24002341Sbostic  *	The Regents of the University of California.  All rights reserved.
4b0eb8cefSbostic  *
5e1a0b129Sbostic  * %sccs.include.redist.c%
66ac1478eSgusella  */
76ac1478eSgusella 
86ac1478eSgusella #ifndef lint
9*24002341Sbostic static char sccsid[] = "@(#)candidate.c	8.1 (Berkeley) 06/06/93";
10b0eb8cefSbostic #endif /* not lint */
116ac1478eSgusella 
12251af36eSbostic #ifdef sgi
13251af36eSbostic #ident "$Revision: 1.9 $"
14251af36eSbostic #endif
156ac1478eSgusella 
16251af36eSbostic #include "globals.h"
176ac1478eSgusella 
186ac1478eSgusella /*
196ac1478eSgusella  * `election' candidates a host as master: it is called by a slave
206ac1478eSgusella  * which runs with the -M option set when its election timeout expires.
216ac1478eSgusella  * Note the conservative approach: if a new timed comes up, or another
226ac1478eSgusella  * candidate sends an election request, the candidature is withdrawn.
236ac1478eSgusella  */
24251af36eSbostic int
election(net)25ec142418Sbloom election(net)
26ec142418Sbloom 	struct netinfo *net;
276ac1478eSgusella {
28251af36eSbostic 	struct tsp *resp, msg;
29251af36eSbostic 	struct timeval then, wait;
30251af36eSbostic 	struct tsp *answer;
31251af36eSbostic 	struct hosttbl *htp;
32251af36eSbostic 	char loop_lim = 0;
336ac1478eSgusella 
34251af36eSbostic /* This code can get totally confused if it gets slightly behind.  For
35251af36eSbostic  *	example, if readmsg() has some QUIT messages waiting from the last
36251af36eSbostic  *	round, we would send an ELECTION message, get the stale QUIT,
37251af36eSbostic  *	and give up.  This results in network storms when several machines
38251af36eSbostic  *	do it at once.
39251af36eSbostic  */
40251af36eSbostic 	wait.tv_sec = 0;
41251af36eSbostic 	wait.tv_usec = 0;
42251af36eSbostic 	while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
43251af36eSbostic 		if (trace)
44251af36eSbostic 			fprintf(fd, "election: discarded stale REFUSE\n");
45251af36eSbostic 	}
46251af36eSbostic 	while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
47251af36eSbostic 		if (trace)
48251af36eSbostic 			fprintf(fd, "election: discarded stale QUIT\n");
496ac1478eSgusella 	}
506ac1478eSgusella 
51251af36eSbostic again:
52251af36eSbostic 	syslog(LOG_INFO, "This machine is a candidate time master");
53251af36eSbostic 	if (trace)
54251af36eSbostic 		fprintf(fd, "This machine is a candidate time master\n");
556ac1478eSgusella 	msg.tsp_type = TSP_ELECTION;
56ec142418Sbloom 	msg.tsp_vers = TSPVERSION;
576ac1478eSgusella 	(void)strcpy(msg.tsp_name, hostname);
583e31f030Sbloom 	bytenetorder(&msg);
598ad07651Sbostic 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
608ad07651Sbostic 		   (struct sockaddr*)&net->dest_addr,
61251af36eSbostic 		   sizeof(struct sockaddr)) < 0) {
62251af36eSbostic 		trace_sendto_err(net->dest_addr.sin_addr);
63251af36eSbostic 		return(SLAVE);
64ec142418Sbloom 	}
656ac1478eSgusella 
66251af36eSbostic 	(void)gettimeofday(&then, 0);
67251af36eSbostic 	then.tv_sec += 3;
68251af36eSbostic 	for (;;) {
69251af36eSbostic 		(void)gettimeofday(&wait, 0);
70251af36eSbostic 		timevalsub(&wait,&then,&wait);
71251af36eSbostic 		resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
72251af36eSbostic 		if (!resp)
73251af36eSbostic 			return(MASTER);
74251af36eSbostic 
756ac1478eSgusella 		switch (resp->tsp_type) {
766ac1478eSgusella 
776ac1478eSgusella 		case TSP_ACCEPT:
78251af36eSbostic 			(void)addmach(resp->tsp_name, &from,fromnet);
796ac1478eSgusella 			break;
8072b368c2Sbloom 
816ac1478eSgusella 		case TSP_MASTERUP:
826ac1478eSgusella 		case TSP_MASTERREQ:
836ac1478eSgusella 			/*
84251af36eSbostic 			 * If another timedaemon is coming up at the same
85251af36eSbostic 			 * time, give up, and let it be the master.
866ac1478eSgusella 			 */
87251af36eSbostic 			if (++loop_lim < 5
88251af36eSbostic 			    && !good_host_name(resp->tsp_name)) {
89251af36eSbostic 				(void)addmach(resp->tsp_name, &from,fromnet);
90251af36eSbostic 				suppress(&from, resp->tsp_name, net);
91251af36eSbostic 				goto again;
92251af36eSbostic 			}
93251af36eSbostic 			rmnetmachs(net);
94251af36eSbostic 			return(SLAVE);
9572b368c2Sbloom 
966ac1478eSgusella 		case TSP_QUIT:
976ac1478eSgusella 		case TSP_REFUSE:
986ac1478eSgusella 			/*
996ac1478eSgusella 			 * Collision: change value of election timer
1006ac1478eSgusella 			 * using exponential backoff.
101251af36eSbostic 			 *
102251af36eSbostic 			 *  Fooey.
103251af36eSbostic 			 * An exponential backoff on a delay starting at
104251af36eSbostic 			 * 6 to 15 minutes for a process that takes
105251af36eSbostic 			 * milliseconds is silly.  It is particularly
106251af36eSbostic 			 * strange that the original code would increase
107251af36eSbostic 			 * the backoff without bound.
1086ac1478eSgusella 			 */
109251af36eSbostic 			rmnetmachs(net);
110251af36eSbostic 			return(SLAVE);
11172b368c2Sbloom 
1126ac1478eSgusella 		case TSP_ELECTION:
1136ac1478eSgusella 			/* no master for another round */
114251af36eSbostic 			htp = addmach(resp->tsp_name,&from,fromnet);
1156ac1478eSgusella 			msg.tsp_type = TSP_REFUSE;
1166ac1478eSgusella 			(void)strcpy(msg.tsp_name, hostname);
117251af36eSbostic 			answer = acksend(&msg, &htp->addr, htp->name,
118251af36eSbostic 					 TSP_ACK, 0, htp->noanswer);
119251af36eSbostic 			if (!answer) {
120251af36eSbostic 				syslog(LOG_ERR, "error in election from %s",
121251af36eSbostic 				       htp->name);
1226ac1478eSgusella 			}
1236ac1478eSgusella 			break;
12472b368c2Sbloom 
1256ac1478eSgusella 		case TSP_SLAVEUP:
126251af36eSbostic 			(void)addmach(resp->tsp_name, &from,fromnet);
1276ac1478eSgusella 			break;
12872b368c2Sbloom 
12956ffd31bSbloom 		case TSP_SETDATE:
13056ffd31bSbloom 		case TSP_SETDATEREQ:
1316ac1478eSgusella 			break;
13272b368c2Sbloom 
1336ac1478eSgusella 		default:
1346ac1478eSgusella 			if (trace) {
1356ac1478eSgusella 				fprintf(fd, "candidate: ");
1368f3fa542Sbloom 				print(resp, &from);
1376ac1478eSgusella 			}
1386ac1478eSgusella 			break;
1396ac1478eSgusella 		}
1406ac1478eSgusella 	}
1416ac1478eSgusella }
142