candidate.c revision 50479
117683Spst/*-
275107Sfenner * Copyright (c) 1985, 1993
398530Sfenner *	The Regents of the University of California.  All rights reserved.
475107Sfenner *
575107Sfenner * Redistribution and use in source and binary forms, with or without
698530Sfenner * modification, are permitted provided that the following conditions
775107Sfenner * are met:
817683Spst * 1. Redistributions of source code must retain the above copyright
917683Spst *    notice, this list of conditions and the following disclaimer.
1026175Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1117683Spst *    notice, this list of conditions and the following disclaimer in the
1217683Spst *    documentation and/or other materials provided with the distribution.
1317683Spst * 3. All advertising materials mentioning features or use of this software
1417683Spst *    must display the following acknowledgement:
1517683Spst *	This product includes software developed by the University of
1617683Spst *	California, Berkeley and its contributors.
1717683Spst * 4. Neither the name of the University nor the names of its contributors
1817683Spst *    may be used to endorse or promote products derived from this software
1917683Spst *    without specific prior written permission.
2017683Spst *
2117683Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2217683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2317683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2417683Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2517683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2617683Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2717683Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2817683Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2917683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3017683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3117683Spst * SUCH DAMAGE.
3275107Sfenner */
3375107Sfenner
3417683Spst#ifndef lint
3517683Spst#if 0
3617683Spststatic char sccsid[] = "@(#)candidate.c	8.1 (Berkeley) 6/6/93";
3717683Spst#endif
3817683Spststatic const char rcsid[] =
3917683Spst  "$FreeBSD: head/usr.sbin/timed/timed/candidate.c 50479 1999-08-28 01:35:59Z peter $";
4017683Spst#endif /* not lint */
4117683Spst
4217683Spst#include "globals.h"
4317683Spst
4417683Spst/*
4517683Spst * `election' candidates a host as master: it is called by a slave
4617683Spst * which runs with the -M option set when its election timeout expires.
4717683Spst * Note the conservative approach: if a new timed comes up, or another
4817683Spst * candidate sends an election request, the candidature is withdrawn.
4917683Spst */
5026175Sfennerint
5126175Sfennerelection(net)
5217683Spst	struct netinfo *net;
5317683Spst{
5475107Sfenner	struct tsp *resp, msg;
5517683Spst	struct timeval then, wait;
5675107Sfenner	struct tsp *answer;
5775107Sfenner	struct hosttbl *htp;
5875107Sfenner	char loop_lim = 0;
5975107Sfenner
6075107Sfenner/* This code can get totally confused if it gets slightly behind.  For
6175107Sfenner *	example, if readmsg() has some QUIT messages waiting from the last
6275107Sfenner *	round, we would send an ELECTION message, get the stale QUIT,
6375107Sfenner *	and give up.  This results in network storms when several machines
6475107Sfenner *	do it at once.
6575107Sfenner */
6675107Sfenner	wait.tv_sec = 0;
6775107Sfenner	wait.tv_usec = 0;
6875107Sfenner	while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
6975107Sfenner		if (trace)
7075107Sfenner			fprintf(fd, "election: discarded stale REFUSE\n");
7175107Sfenner	}
7298530Sfenner	while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
7375107Sfenner		if (trace)
7475107Sfenner			fprintf(fd, "election: discarded stale QUIT\n");
7575107Sfenner	}
7675107Sfenner
7775107Sfenneragain:
7875107Sfenner	syslog(LOG_INFO, "This machine is a candidate time master");
7975107Sfenner	if (trace)
8075107Sfenner		fprintf(fd, "This machine is a candidate time master\n");
8175107Sfenner	msg.tsp_type = TSP_ELECTION;
8275107Sfenner	msg.tsp_vers = TSPVERSION;
8375107Sfenner	(void)strcpy(msg.tsp_name, hostname);
8475107Sfenner	bytenetorder(&msg);
8575107Sfenner	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
8675107Sfenner		   (struct sockaddr*)&net->dest_addr,
8775107Sfenner		   sizeof(struct sockaddr)) < 0) {
8875107Sfenner		trace_sendto_err(net->dest_addr.sin_addr);
8975107Sfenner		return(SLAVE);
9075107Sfenner	}
9175107Sfenner
9275107Sfenner	(void)gettimeofday(&then, 0);
9375107Sfenner	then.tv_sec += 3;
9475107Sfenner	for (;;) {
9575107Sfenner		(void)gettimeofday(&wait, 0);
9675107Sfenner		timevalsub(&wait,&then,&wait);
9775107Sfenner		resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
9875107Sfenner		if (!resp)
9975107Sfenner			return(MASTER);
10075107Sfenner
10175107Sfenner		switch (resp->tsp_type) {
10275107Sfenner
10375107Sfenner		case TSP_ACCEPT:
10475107Sfenner			(void)addmach(resp->tsp_name, &from,fromnet);
10575107Sfenner			break;
10675107Sfenner
10775107Sfenner		case TSP_MASTERUP:
10875107Sfenner		case TSP_MASTERREQ:
10975107Sfenner			/*
11075107Sfenner			 * If another timedaemon is coming up at the same
11175107Sfenner			 * time, give up, and let it be the master.
11275107Sfenner			 */
11375107Sfenner			if (++loop_lim < 5
11417683Spst			    && !good_host_name(resp->tsp_name)) {
11517683Spst				(void)addmach(resp->tsp_name, &from,fromnet);
11626175Sfenner				suppress(&from, resp->tsp_name, net);
11726175Sfenner				goto again;
11826175Sfenner			}
11926175Sfenner			rmnetmachs(net);
12098530Sfenner			return(SLAVE);
12126175Sfenner
12226175Sfenner		case TSP_QUIT:
12326175Sfenner		case TSP_REFUSE:
12426175Sfenner			/*
12526175Sfenner			 * Collision: change value of election timer
12626175Sfenner			 * using exponential backoff.
12726175Sfenner			 *
12826175Sfenner			 *  Fooey.
12926175Sfenner			 * An exponential backoff on a delay starting at
13026175Sfenner			 * 6 to 15 minutes for a process that takes
13117683Spst			 * milliseconds is silly.  It is particularly
13217683Spst			 * strange that the original code would increase
13317683Spst			 * the backoff without bound.
13417683Spst			 */
13517683Spst			rmnetmachs(net);
13617683Spst			return(SLAVE);
13717683Spst
13817683Spst		case TSP_ELECTION:
13917683Spst			/* no master for another round */
14017683Spst			htp = addmach(resp->tsp_name,&from,fromnet);
14117683Spst			msg.tsp_type = TSP_REFUSE;
14217683Spst			(void)strcpy(msg.tsp_name, hostname);
14317683Spst			answer = acksend(&msg, &htp->addr, htp->name,
14417683Spst					 TSP_ACK, 0, htp->noanswer);
14526175Sfenner			if (!answer) {
14675107Sfenner				syslog(LOG_ERR, "error in election from %s",
14717683Spst				       htp->name);
14817683Spst			}
14917683Spst			break;
15075107Sfenner
15175107Sfenner		case TSP_SLAVEUP:
15275107Sfenner			(void)addmach(resp->tsp_name, &from,fromnet);
15375107Sfenner			break;
15475107Sfenner
15575107Sfenner		case TSP_SETDATE:
15675107Sfenner		case TSP_SETDATEREQ:
15775107Sfenner			break;
15875107Sfenner
15975107Sfenner		default:
16017683Spst			if (trace) {
16117683Spst				fprintf(fd, "candidate: ");
16217683Spst				print(resp, &from);
16326175Sfenner			}
16475107Sfenner			break;
16526175Sfenner		}
16626175Sfenner	}
16717683Spst}
16817683Spst