candidate.c revision 1554
1327Sjkh/*-
2327Sjkh * Copyright (c) 1985, 1993
3327Sjkh *	The Regents of the University of California.  All rights reserved.
4327Sjkh *
5327Sjkh * Redistribution and use in source and binary forms, with or without
6327Sjkh * modification, are permitted provided that the following conditions
7327Sjkh * are met:
8327Sjkh * 1. Redistributions of source code must retain the above copyright
9327Sjkh *    notice, this list of conditions and the following disclaimer.
10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright
11327Sjkh *    notice, this list of conditions and the following disclaimer in the
12327Sjkh *    documentation and/or other materials provided with the distribution.
13327Sjkh * 3. All advertising materials mentioning features or use of this software
14327Sjkh *    must display the following acknowledgement:
15327Sjkh *	This product includes software developed by the University of
16327Sjkh *	California, Berkeley and its contributors.
17327Sjkh * 4. Neither the name of the University nor the names of its contributors
1831997Shoek *    may be used to endorse or promote products derived from this software
19327Sjkh *    without specific prior written permission.
20327Sjkh *
21327Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2293520Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2393520Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2493520Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25327Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26327Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2774699Ssobomax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28327Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29103149Ssobomax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055567Sphantom * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31327Sjkh * SUCH DAMAGE.
3272174Ssobomax */
33411Sjkh
3484745Ssobomax#ifndef lint
3511780Sjkhstatic char sccsid[] = "@(#)candidate.c	8.1 (Berkeley) 6/6/93";
36392Sjkh#endif /* not lint */
3796030Ssobomax
3874699Ssobomax#ifdef sgi
39327Sjkh#ident "$Revision: 1.9 $"
4030221Scharnier#endif
4130221Scharnier
42327Sjkh#include "globals.h"
43327Sjkh
44327Sjkh/*
45327Sjkh * `election' candidates a host as master: it is called by a slave
46327Sjkh * which runs with the -M option set when its election timeout expires.
4756001Sdan * Note the conservative approach: if a new timed comes up, or another
48327Sjkh * candidate sends an election request, the candidature is withdrawn.
4974699Ssobomax */
5074699Ssobomaxint
5174699Ssobomaxelection(net)
5274699Ssobomax	struct netinfo *net;
5374699Ssobomax{
54327Sjkh	struct tsp *resp, msg;
5546105Sjkh	struct timeval then, wait;
5672174Ssobomax	struct tsp *answer;
5746105Sjkh	struct hosttbl *htp;
5846105Sjkh	char loop_lim = 0;
5946105Sjkh
60327Sjkh/* This code can get totally confused if it gets slightly behind.  For
61327Sjkh *	example, if readmsg() has some QUIT messages waiting from the last
6272174Ssobomax *	round, we would send an ELECTION message, get the stale QUIT,
63327Sjkh *	and give up.  This results in network storms when several machines
64327Sjkh *	do it at once.
65327Sjkh */
66327Sjkh	wait.tv_sec = 0;
67327Sjkh	wait.tv_usec = 0;
68327Sjkh	while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
694996Sjkh		if (trace)
70327Sjkh			fprintf(fd, "election: discarded stale REFUSE\n");
71327Sjkh	}
72327Sjkh	while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
73327Sjkh		if (trace)
74327Sjkh			fprintf(fd, "election: discarded stale QUIT\n");
75327Sjkh	}
76327Sjkh
77327Sjkhagain:
78327Sjkh	syslog(LOG_INFO, "This machine is a candidate time master");
79327Sjkh	if (trace)
80327Sjkh		fprintf(fd, "This machine is a candidate time master\n");
81327Sjkh	msg.tsp_type = TSP_ELECTION;
82327Sjkh	msg.tsp_vers = TSPVERSION;
83327Sjkh	(void)strcpy(msg.tsp_name, hostname);
84327Sjkh	bytenetorder(&msg);
85327Sjkh	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
86327Sjkh		   (struct sockaddr*)&net->dest_addr,
87327Sjkh		   sizeof(struct sockaddr)) < 0) {
884996Sjkh		trace_sendto_err(net->dest_addr.sin_addr);
894996Sjkh		return(SLAVE);
904996Sjkh	}
914996Sjkh
92327Sjkh	(void)gettimeofday(&then, 0);
93327Sjkh	then.tv_sec += 3;
94327Sjkh	for (;;) {
95327Sjkh		(void)gettimeofday(&wait, 0);
9671965Sjkh		timevalsub(&wait,&then,&wait);
9771965Sjkh		resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
9871965Sjkh		if (!resp)
9971965Sjkh			return(MASTER);
10072174Ssobomax
10172174Ssobomax		switch (resp->tsp_type) {
10272174Ssobomax
10372174Ssobomax		case TSP_ACCEPT:
104327Sjkh			(void)addmach(resp->tsp_name, &from,fromnet);
105327Sjkh			break;
106327Sjkh
107327Sjkh		case TSP_MASTERUP:
108327Sjkh		case TSP_MASTERREQ:
109327Sjkh			/*
110327Sjkh			 * If another timedaemon is coming up at the same
111327Sjkh			 * time, give up, and let it be the master.
112327Sjkh			 */
113327Sjkh			if (++loop_lim < 5
114327Sjkh			    && !good_host_name(resp->tsp_name)) {
115327Sjkh				(void)addmach(resp->tsp_name, &from,fromnet);
1164996Sjkh				suppress(&from, resp->tsp_name, net);
1174996Sjkh				goto again;
1184996Sjkh			}
1194996Sjkh			rmnetmachs(net);
120411Sjkh			return(SLAVE);
121411Sjkh
122411Sjkh		case TSP_QUIT:
123411Sjkh		case TSP_REFUSE:
1244996Sjkh			/*
1254996Sjkh			 * Collision: change value of election timer
1264996Sjkh			 * using exponential backoff.
1274996Sjkh			 *
12872174Ssobomax			 *  Fooey.
12972174Ssobomax			 * An exponential backoff on a delay starting at
13072174Ssobomax			 * 6 to 15 minutes for a process that takes
13162775Ssobomax			 * milliseconds is silly.  It is particularly
13267454Ssobomax			 * strange that the original code would increase
13367454Ssobomax			 * the backoff without bound.
13467454Ssobomax			 */
13567454Ssobomax			rmnetmachs(net);
13696030Ssobomax			return(SLAVE);
13796030Ssobomax
13896030Ssobomax		case TSP_ELECTION:
13996030Ssobomax			/* no master for another round */
14096030Ssobomax			htp = addmach(resp->tsp_name,&from,fromnet);
14196030Ssobomax			msg.tsp_type = TSP_REFUSE;
14284750Ssobomax			(void)strcpy(msg.tsp_name, hostname);
14384750Ssobomax			answer = acksend(&msg, &htp->addr, htp->name,
14484750Ssobomax					 TSP_ACK, 0, htp->noanswer);
14584750Ssobomax			if (!answer) {
146379Sjkh				syslog(LOG_ERR, "error in election from %s",
147379Sjkh				       htp->name);
148379Sjkh			}
149379Sjkh			break;
150411Sjkh
151411Sjkh		case TSP_SLAVEUP:
152411Sjkh			(void)addmach(resp->tsp_name, &from,fromnet);
153411Sjkh			break;
154383Sjkh
15585019Ssobomax		case TSP_SETDATE:
156383Sjkh		case TSP_SETDATEREQ:
157383Sjkh			break;
15872174Ssobomax
15972174Ssobomax		default:
16072174Ssobomax			if (trace) {
16172174Ssobomax				fprintf(fd, "candidate: ");
162392Sjkh				print(resp, &from);
163392Sjkh			}
164392Sjkh			break;
165392Sjkh		}
16674699Ssobomax	}
16774699Ssobomax}
16874699Ssobomax