1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)candidate.c	2.7 (Berkeley) 03/02/91";
10 #endif /* not lint */
11 
12 #include "globals.h"
13 #include <protocols/timed.h>
14 
15 #define ELECTIONWAIT	3	/* seconds */
16 
17 /*
18  * `election' candidates a host as master: it is called by a slave
19  * which runs with the -M option set when its election timeout expires.
20  * Note the conservative approach: if a new timed comes up, or another
21  * candidate sends an election request, the candidature is withdrawn.
22  */
23 
24 election(net)
25 struct netinfo *net;
26 {
27 	int ret;
28 	struct tsp *resp, msg, *readmsg();
29 	struct timeval wait;
30 	struct tsp *answer, *acksend();
31 	long casual();
32 	struct sockaddr_in server;
33 
34 	syslog(LOG_INFO, "THIS MACHINE IS A CANDIDATE");
35 	if (trace) {
36 		fprintf(fd, "THIS MACHINE IS A CANDIDATE\n");
37 	}
38 
39 	ret = MASTER;
40 	slvcount = 1;
41 
42 	msg.tsp_type = TSP_ELECTION;
43 	msg.tsp_vers = TSPVERSION;
44 	(void)strcpy(msg.tsp_name, hostname);
45 	bytenetorder(&msg);
46 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
47 		(struct sockaddr *)&net->dest_addr,
48 		sizeof(struct sockaddr_in)) < 0) {
49 		syslog(LOG_ERR, "sendto: %m");
50 		exit(1);
51 	}
52 
53 	do {
54 		wait.tv_sec = ELECTIONWAIT;
55 		wait.tv_usec = 0;
56 		resp = readmsg(TSP_ANY, (char *)ANYADDR, &wait, net);
57 		if (resp != NULL) {
58 			switch (resp->tsp_type) {
59 
60 			case TSP_ACCEPT:
61 				(void) addmach(resp->tsp_name, &from);
62 				break;
63 
64 			case TSP_MASTERUP:
65 			case TSP_MASTERREQ:
66 				/*
67 				 * If a timedaemon is coming up at the same time,
68 				 * give up the candidature: it will be the master.
69 				 */
70 				ret = SLAVE;
71 				break;
72 
73 			case TSP_QUIT:
74 			case TSP_REFUSE:
75 				/*
76 				 * Collision: change value of election timer
77 				 * using exponential backoff.
78 				 * The value of timer will be recomputed (in slave.c)
79 				 * using the original interval when election will
80 				 * be successfully completed.
81 				 */
82 				backoff *= 2;
83 				delay2 = casual((long)MINTOUT,
84 							(long)(MAXTOUT * backoff));
85 				ret = SLAVE;
86 				break;
87 
88 			case TSP_ELECTION:
89 				/* no master for another round */
90 				msg.tsp_type = TSP_REFUSE;
91 				(void)strcpy(msg.tsp_name, hostname);
92 				server = from;
93 				answer = acksend(&msg, &server, resp->tsp_name,
94 				    TSP_ACK, (struct netinfo *)NULL);
95 				if (answer == NULL) {
96 					syslog(LOG_ERR, "error in election");
97 				} else {
98 					(void) addmach(resp->tsp_name, &from);
99 				}
100 				break;
101 
102 			case TSP_SLAVEUP:
103 				(void) addmach(resp->tsp_name, &from);
104 				break;
105 
106 			case TSP_SETDATE:
107 			case TSP_SETDATEREQ:
108 				break;
109 
110 			default:
111 				if (trace) {
112 					fprintf(fd, "candidate: ");
113 					print(resp, &from);
114 				}
115 				break;
116 			}
117 		} else {
118 			break;
119 		}
120 	} while (ret == MASTER);
121 	return(ret);
122 }
123