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