Home | History | Annotate | Line # | Download | only in timed
      1 /*-
      2  * Copyright (c) 1985, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. Neither the name of the University nor the names of its contributors
     14  *    may be used to endorse or promote products derived from this software
     15  *    without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 #ifndef lint
     32 #if 0
     33 static char sccsid[] = "@(#)candidate.c	8.1 (Berkeley) 6/6/93";
     34 #else
     35 __RCSID("$NetBSD: candidate.c,v 1.12 2007/01/26 16:12:41 christos Exp $");
     36 #endif
     37 #endif /* not lint */
     38 
     39 #include "globals.h"
     40 
     41 /*
     42  * `election' candidates a host as master: it is called by a slave
     43  * which runs with the -M option set when its election timeout expires.
     44  * Note the conservative approach: if a new timed comes up, or another
     45  * candidate sends an election request, the candidature is withdrawn.
     46  */
     47 int
     48 election(struct netinfo *net)
     49 {
     50 	struct tsp *resp, msg;
     51 	struct timeval then, wait;
     52 	struct tsp *answer;
     53 	struct hosttbl *htp;
     54 	char loop_lim = 0;
     55 
     56 /* This code can get totally confused if it gets slightly behind.  For
     57  *	example, if readmsg() has some QUIT messages waiting from the last
     58  *	round, we would send an ELECTION message, get the stale QUIT,
     59  *	and give up.  This results in network storms when several machines
     60  *	do it at once.
     61  */
     62 	wait.tv_sec = 0;
     63 	wait.tv_usec = 0;
     64 	while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
     65 		if (trace)
     66 			fprintf(fd, "election: discarded stale REFUSE\n");
     67 	}
     68 	while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
     69 		if (trace)
     70 			fprintf(fd, "election: discarded stale QUIT\n");
     71 	}
     72 
     73 again:
     74 	syslog(LOG_INFO, "This machine is a candidate time master");
     75 	if (trace)
     76 		fprintf(fd, "This machine is a candidate time master\n");
     77 	msg.tsp_type = TSP_ELECTION;
     78 	msg.tsp_vers = TSPVERSION;
     79 	set_tsp_name(&msg, hostname);
     80 	bytenetorder(&msg);
     81 	if (sendtsp(sock, &msg, &net->dest_addr) == -1)
     82 		return(SLAVE);
     83 
     84 	(void)gettimeofday(&then, 0);
     85 	then.tv_sec += 3;
     86 	for (;;) {
     87 		(void)gettimeofday(&wait, 0);
     88 		timersub(&then, &wait, &wait);
     89 		resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
     90 		if (!resp)
     91 			return(MASTER);
     92 
     93 		switch (resp->tsp_type) {
     94 
     95 		case TSP_ACCEPT:
     96 			(void)addmach(resp->tsp_name, &from,fromnet);
     97 			break;
     98 
     99 		case TSP_MASTERUP:
    100 		case TSP_MASTERREQ:
    101 			/*
    102 			 * If another timedaemon is coming up at the same
    103 			 * time, give up, and let it be the master.
    104 			 */
    105 			if (++loop_lim < 5
    106 			    && !good_host_name(resp->tsp_name)) {
    107 				(void)addmach(resp->tsp_name, &from,fromnet);
    108 				suppress(&from, resp->tsp_name, net);
    109 				goto again;
    110 			}
    111 			rmnetmachs(net);
    112 			return(SLAVE);
    113 
    114 		case TSP_QUIT:
    115 		case TSP_REFUSE:
    116 			/*
    117 			 * Collision: change value of election timer
    118 			 * using exponential backoff.
    119 			 *
    120 			 *  Fooey.
    121 			 * An exponential backoff on a delay starting at
    122 			 * 6 to 15 minutes for a process that takes
    123 			 * milliseconds is silly.  It is particularly
    124 			 * strange that the original code would increase
    125 			 * the backoff without bound.
    126 			 */
    127 			rmnetmachs(net);
    128 			return(SLAVE);
    129 
    130 		case TSP_ELECTION:
    131 			/* no master for another round */
    132 			htp = addmach(resp->tsp_name,&from,fromnet);
    133 			msg.tsp_type = TSP_REFUSE;
    134 			set_tsp_name(&msg, hostname);
    135 			answer = acksend(&msg, &htp->addr, htp->name,
    136 					 TSP_ACK, 0, htp->noanswer);
    137 			if (!answer) {
    138 				syslog(LOG_ERR, "error in election from %s",
    139 				       htp->name);
    140 			}
    141 			break;
    142 
    143 		case TSP_SLAVEUP:
    144 			(void)addmach(resp->tsp_name, &from,fromnet);
    145 			break;
    146 
    147 		case TSP_SETDATE:
    148 		case TSP_SETDATEREQ:
    149 			break;
    150 
    151 		default:
    152 			if (trace) {
    153 				fprintf(fd, "candidate: ");
    154 				print(resp, &from);
    155 			}
    156 			break;
    157 		}
    158 	}
    159 }
    160