1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)candidate.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #ifdef sgi
13 #ident "$Revision: 1.9 $"
14 #endif
15
16 #include "globals.h"
17
18 /*
19 * `election' candidates a host as master: it is called by a slave
20 * which runs with the -M option set when its election timeout expires.
21 * Note the conservative approach: if a new timed comes up, or another
22 * candidate sends an election request, the candidature is withdrawn.
23 */
24 int
election(net)25 election(net)
26 struct netinfo *net;
27 {
28 struct tsp *resp, msg;
29 struct timeval then, wait;
30 struct tsp *answer;
31 struct hosttbl *htp;
32 char loop_lim = 0;
33
34 /* This code can get totally confused if it gets slightly behind. For
35 * example, if readmsg() has some QUIT messages waiting from the last
36 * round, we would send an ELECTION message, get the stale QUIT,
37 * and give up. This results in network storms when several machines
38 * do it at once.
39 */
40 wait.tv_sec = 0;
41 wait.tv_usec = 0;
42 while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
43 if (trace)
44 fprintf(fd, "election: discarded stale REFUSE\n");
45 }
46 while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
47 if (trace)
48 fprintf(fd, "election: discarded stale QUIT\n");
49 }
50
51 again:
52 syslog(LOG_INFO, "This machine is a candidate time master");
53 if (trace)
54 fprintf(fd, "This machine is a candidate time master\n");
55 msg.tsp_type = TSP_ELECTION;
56 msg.tsp_vers = TSPVERSION;
57 (void)strcpy(msg.tsp_name, hostname);
58 bytenetorder(&msg);
59 if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
60 (struct sockaddr*)&net->dest_addr,
61 sizeof(struct sockaddr)) < 0) {
62 trace_sendto_err(net->dest_addr.sin_addr);
63 return(SLAVE);
64 }
65
66 (void)gettimeofday(&then, 0);
67 then.tv_sec += 3;
68 for (;;) {
69 (void)gettimeofday(&wait, 0);
70 timevalsub(&wait,&then,&wait);
71 resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
72 if (!resp)
73 return(MASTER);
74
75 switch (resp->tsp_type) {
76
77 case TSP_ACCEPT:
78 (void)addmach(resp->tsp_name, &from,fromnet);
79 break;
80
81 case TSP_MASTERUP:
82 case TSP_MASTERREQ:
83 /*
84 * If another timedaemon is coming up at the same
85 * time, give up, and let it be the master.
86 */
87 if (++loop_lim < 5
88 && !good_host_name(resp->tsp_name)) {
89 (void)addmach(resp->tsp_name, &from,fromnet);
90 suppress(&from, resp->tsp_name, net);
91 goto again;
92 }
93 rmnetmachs(net);
94 return(SLAVE);
95
96 case TSP_QUIT:
97 case TSP_REFUSE:
98 /*
99 * Collision: change value of election timer
100 * using exponential backoff.
101 *
102 * Fooey.
103 * An exponential backoff on a delay starting at
104 * 6 to 15 minutes for a process that takes
105 * milliseconds is silly. It is particularly
106 * strange that the original code would increase
107 * the backoff without bound.
108 */
109 rmnetmachs(net);
110 return(SLAVE);
111
112 case TSP_ELECTION:
113 /* no master for another round */
114 htp = addmach(resp->tsp_name,&from,fromnet);
115 msg.tsp_type = TSP_REFUSE;
116 (void)strcpy(msg.tsp_name, hostname);
117 answer = acksend(&msg, &htp->addr, htp->name,
118 TSP_ACK, 0, htp->noanswer);
119 if (!answer) {
120 syslog(LOG_ERR, "error in election from %s",
121 htp->name);
122 }
123 break;
124
125 case TSP_SLAVEUP:
126 (void)addmach(resp->tsp_name, &from,fromnet);
127 break;
128
129 case TSP_SETDATE:
130 case TSP_SETDATEREQ:
131 break;
132
133 default:
134 if (trace) {
135 fprintf(fd, "candidate: ");
136 print(resp, &from);
137 }
138 break;
139 }
140 }
141 }
142