1281681Srpaulo/*-
2281681Srpaulo * Copyright (c) 1985, 1993
3281681Srpaulo *	The Regents of the University of California.  All rights reserved.
4281681Srpaulo *
5281681Srpaulo * Redistribution and use in source and binary forms, with or without
6281681Srpaulo * modification, are permitted provided that the following conditions
7281681Srpaulo * are met:
8281681Srpaulo * 1. Redistributions of source code must retain the above copyright
9281681Srpaulo *    notice, this list of conditions and the following disclaimer.
10281681Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11281681Srpaulo *    notice, this list of conditions and the following disclaimer in the
12281681Srpaulo *    documentation and/or other materials provided with the distribution.
13281681Srpaulo * 4. Neither the name of the University nor the names of its contributors
14281681Srpaulo *    may be used to endorse or promote products derived from this software
15281681Srpaulo *    without specific prior written permission.
16281681Srpaulo *
17281681Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18281681Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19281681Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20281681Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21281681Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22281681Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23281681Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24281681Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25281681Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26281681Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27281681Srpaulo * SUCH DAMAGE.
28281681Srpaulo */
29281681Srpaulo
30281681Srpaulo#ifndef lint
31281681Srpaulo#if 0
32281681Srpaulostatic char sccsid[] = "@(#)candidate.c	8.1 (Berkeley) 6/6/93";
33281681Srpaulo#endif
34281681Srpaulostatic const char rcsid[] =
35281681Srpaulo  "$FreeBSD$";
36281681Srpaulo#endif /* not lint */
37281681Srpaulo
38281681Srpaulo#include "globals.h"
39281681Srpaulo
40281681Srpaulo/*
41281681Srpaulo * `election' candidates a host as master: it is called by a slave
42281681Srpaulo * which runs with the -M option set when its election timeout expires.
43281681Srpaulo * Note the conservative approach: if a new timed comes up, or another
44281681Srpaulo * candidate sends an election request, the candidature is withdrawn.
45281681Srpaulo */
46281681Srpauloint
47281681Srpauloelection(net)
48281681Srpaulo	struct netinfo *net;
49281681Srpaulo{
50281681Srpaulo	struct tsp *resp, msg;
51281681Srpaulo	struct timeval then, wait;
52281681Srpaulo	struct tsp *answer;
53281681Srpaulo	struct hosttbl *htp;
54281681Srpaulo	char loop_lim = 0;
55281681Srpaulo
56281681Srpaulo/* This code can get totally confused if it gets slightly behind.  For
57281681Srpaulo *	example, if readmsg() has some QUIT messages waiting from the last
58281681Srpaulo *	round, we would send an ELECTION message, get the stale QUIT,
59281681Srpaulo *	and give up.  This results in network storms when several machines
60281681Srpaulo *	do it at once.
61281681Srpaulo */
62281681Srpaulo	wait.tv_sec = 0;
63281681Srpaulo	wait.tv_usec = 0;
64281681Srpaulo	while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
65281681Srpaulo		if (trace)
66281681Srpaulo			fprintf(fd, "election: discarded stale REFUSE\n");
67281681Srpaulo	}
68281681Srpaulo	while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
69281681Srpaulo		if (trace)
70281681Srpaulo			fprintf(fd, "election: discarded stale QUIT\n");
71281681Srpaulo	}
72281681Srpaulo
73281681Srpauloagain:
74281681Srpaulo	syslog(LOG_INFO, "This machine is a candidate time master");
75281681Srpaulo	if (trace)
76281681Srpaulo		fprintf(fd, "This machine is a candidate time master\n");
77281681Srpaulo	msg.tsp_type = TSP_ELECTION;
78281681Srpaulo	msg.tsp_vers = TSPVERSION;
79281681Srpaulo	(void)strcpy(msg.tsp_name, hostname);
80281681Srpaulo	bytenetorder(&msg);
81281681Srpaulo	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
82281681Srpaulo		   (struct sockaddr*)&net->dest_addr,
83281681Srpaulo		   sizeof(struct sockaddr)) < 0) {
84281681Srpaulo		trace_sendto_err(net->dest_addr.sin_addr);
85281681Srpaulo		return(SLAVE);
86281681Srpaulo	}
87281681Srpaulo
88281681Srpaulo	(void)gettimeofday(&then, 0);
89281681Srpaulo	then.tv_sec += 3;
90281681Srpaulo	for (;;) {
91281681Srpaulo		(void)gettimeofday(&wait, 0);
92281681Srpaulo		timevalsub(&wait,&then,&wait);
93281681Srpaulo		resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
94281681Srpaulo		if (!resp)
95281681Srpaulo			return(MASTER);
96281681Srpaulo
97281681Srpaulo		switch (resp->tsp_type) {
98281681Srpaulo
99281681Srpaulo		case TSP_ACCEPT:
100281681Srpaulo			(void)addmach(resp->tsp_name, &from,fromnet);
101281681Srpaulo			break;
102281681Srpaulo
103281681Srpaulo		case TSP_MASTERUP:
104281681Srpaulo		case TSP_MASTERREQ:
105281681Srpaulo			/*
106281681Srpaulo			 * If another timedaemon is coming up at the same
107281681Srpaulo			 * time, give up, and let it be the master.
108281681Srpaulo			 */
109281681Srpaulo			if (++loop_lim < 5
110281681Srpaulo			    && !good_host_name(resp->tsp_name)) {
111281681Srpaulo				(void)addmach(resp->tsp_name, &from,fromnet);
112281681Srpaulo				suppress(&from, resp->tsp_name, net);
113281681Srpaulo				goto again;
114281681Srpaulo			}
115281681Srpaulo			rmnetmachs(net);
116281681Srpaulo			return(SLAVE);
117281681Srpaulo
118281681Srpaulo		case TSP_QUIT:
119281681Srpaulo		case TSP_REFUSE:
120281681Srpaulo			/*
121281681Srpaulo			 * Collision: change value of election timer
122281681Srpaulo			 * using exponential backoff.
123281681Srpaulo			 *
124281681Srpaulo			 *  Fooey.
125281681Srpaulo			 * An exponential backoff on a delay starting at
126281681Srpaulo			 * 6 to 15 minutes for a process that takes
127281681Srpaulo			 * milliseconds is silly.  It is particularly
128281681Srpaulo			 * strange that the original code would increase
129281681Srpaulo			 * the backoff without bound.
130281681Srpaulo			 */
131281681Srpaulo			rmnetmachs(net);
132281681Srpaulo			return(SLAVE);
133281681Srpaulo
134281681Srpaulo		case TSP_ELECTION:
135281681Srpaulo			/* no master for another round */
136281681Srpaulo			htp = addmach(resp->tsp_name,&from,fromnet);
137281681Srpaulo			msg.tsp_type = TSP_REFUSE;
138281681Srpaulo			(void)strcpy(msg.tsp_name, hostname);
139281681Srpaulo			answer = acksend(&msg, &htp->addr, htp->name,
140281681Srpaulo					 TSP_ACK, 0, htp->noanswer);
141281681Srpaulo			if (!answer) {
142281681Srpaulo				syslog(LOG_ERR, "error in election from %s",
143281681Srpaulo				       htp->name);
144281681Srpaulo			}
145281681Srpaulo			break;
146281681Srpaulo
147281681Srpaulo		case TSP_SLAVEUP:
148281681Srpaulo			(void)addmach(resp->tsp_name, &from,fromnet);
149281681Srpaulo			break;
150281681Srpaulo
151281681Srpaulo		case TSP_SETDATE:
152281681Srpaulo		case TSP_SETDATEREQ:
153281681Srpaulo			break;
154281681Srpaulo
155281681Srpaulo		default:
156281681Srpaulo			if (trace) {
157281681Srpaulo				fprintf(fd, "candidate: ");
158281681Srpaulo				print(resp, &from);
159281681Srpaulo			}
160281681Srpaulo			break;
161281681Srpaulo		}
162281681Srpaulo	}
163281681Srpaulo}
164281681Srpaulo