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.6 (Berkeley) 06/01/90";
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, &net->dest_addr,
47 	    sizeof(struct sockaddr_in)) < 0) {
48 		syslog(LOG_ERR, "sendto: %m");
49 		exit(1);
50 	}
51 
52 	do {
53 		wait.tv_sec = ELECTIONWAIT;
54 		wait.tv_usec = 0;
55 		resp = readmsg(TSP_ANY, (char *)ANYADDR, &wait, net);
56 		if (resp != NULL) {
57 			switch (resp->tsp_type) {
58 
59 			case TSP_ACCEPT:
60 				(void) addmach(resp->tsp_name, &from);
61 				break;
62 
63 			case TSP_MASTERUP:
64 			case TSP_MASTERREQ:
65 				/*
66 				 * If a timedaemon is coming up at the same time,
67 				 * give up the candidature: it will be the master.
68 				 */
69 				ret = SLAVE;
70 				break;
71 
72 			case TSP_QUIT:
73 			case TSP_REFUSE:
74 				/*
75 				 * Collision: change value of election timer
76 				 * using exponential backoff.
77 				 * The value of timer will be recomputed (in slave.c)
78 				 * using the original interval when election will
79 				 * be successfully completed.
80 				 */
81 				backoff *= 2;
82 				delay2 = casual((long)MINTOUT,
83 							(long)(MAXTOUT * backoff));
84 				ret = SLAVE;
85 				break;
86 
87 			case TSP_ELECTION:
88 				/* no master for another round */
89 				msg.tsp_type = TSP_REFUSE;
90 				(void)strcpy(msg.tsp_name, hostname);
91 				server = from;
92 				answer = acksend(&msg, &server, resp->tsp_name,
93 				    TSP_ACK, (struct netinfo *)NULL);
94 				if (answer == NULL) {
95 					syslog(LOG_ERR, "error in election");
96 				} else {
97 					(void) addmach(resp->tsp_name, &from);
98 				}
99 				break;
100 
101 			case TSP_SLAVEUP:
102 				(void) addmach(resp->tsp_name, &from);
103 				break;
104 
105 			case TSP_SETDATE:
106 			case TSP_SETDATEREQ:
107 				break;
108 
109 			default:
110 				if (trace) {
111 					fprintf(fd, "candidate: ");
112 					print(resp, &from);
113 				}
114 				break;
115 			}
116 		} else {
117 			break;
118 		}
119 	} while (ret == MASTER);
120 	return(ret);
121 }
122