1251af36eSbostic /*-
2*24002341Sbostic * Copyright (c) 1985, 1993
3*24002341Sbostic * The Regents of the University of California. All rights reserved.
4b0eb8cefSbostic *
5e1a0b129Sbostic * %sccs.include.redist.c%
66ac1478eSgusella */
76ac1478eSgusella
86ac1478eSgusella #ifndef lint
9*24002341Sbostic static char sccsid[] = "@(#)candidate.c 8.1 (Berkeley) 06/06/93";
10b0eb8cefSbostic #endif /* not lint */
116ac1478eSgusella
12251af36eSbostic #ifdef sgi
13251af36eSbostic #ident "$Revision: 1.9 $"
14251af36eSbostic #endif
156ac1478eSgusella
16251af36eSbostic #include "globals.h"
176ac1478eSgusella
186ac1478eSgusella /*
196ac1478eSgusella * `election' candidates a host as master: it is called by a slave
206ac1478eSgusella * which runs with the -M option set when its election timeout expires.
216ac1478eSgusella * Note the conservative approach: if a new timed comes up, or another
226ac1478eSgusella * candidate sends an election request, the candidature is withdrawn.
236ac1478eSgusella */
24251af36eSbostic int
election(net)25ec142418Sbloom election(net)
26ec142418Sbloom struct netinfo *net;
276ac1478eSgusella {
28251af36eSbostic struct tsp *resp, msg;
29251af36eSbostic struct timeval then, wait;
30251af36eSbostic struct tsp *answer;
31251af36eSbostic struct hosttbl *htp;
32251af36eSbostic char loop_lim = 0;
336ac1478eSgusella
34251af36eSbostic /* This code can get totally confused if it gets slightly behind. For
35251af36eSbostic * example, if readmsg() has some QUIT messages waiting from the last
36251af36eSbostic * round, we would send an ELECTION message, get the stale QUIT,
37251af36eSbostic * and give up. This results in network storms when several machines
38251af36eSbostic * do it at once.
39251af36eSbostic */
40251af36eSbostic wait.tv_sec = 0;
41251af36eSbostic wait.tv_usec = 0;
42251af36eSbostic while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
43251af36eSbostic if (trace)
44251af36eSbostic fprintf(fd, "election: discarded stale REFUSE\n");
45251af36eSbostic }
46251af36eSbostic while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
47251af36eSbostic if (trace)
48251af36eSbostic fprintf(fd, "election: discarded stale QUIT\n");
496ac1478eSgusella }
506ac1478eSgusella
51251af36eSbostic again:
52251af36eSbostic syslog(LOG_INFO, "This machine is a candidate time master");
53251af36eSbostic if (trace)
54251af36eSbostic fprintf(fd, "This machine is a candidate time master\n");
556ac1478eSgusella msg.tsp_type = TSP_ELECTION;
56ec142418Sbloom msg.tsp_vers = TSPVERSION;
576ac1478eSgusella (void)strcpy(msg.tsp_name, hostname);
583e31f030Sbloom bytenetorder(&msg);
598ad07651Sbostic if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
608ad07651Sbostic (struct sockaddr*)&net->dest_addr,
61251af36eSbostic sizeof(struct sockaddr)) < 0) {
62251af36eSbostic trace_sendto_err(net->dest_addr.sin_addr);
63251af36eSbostic return(SLAVE);
64ec142418Sbloom }
656ac1478eSgusella
66251af36eSbostic (void)gettimeofday(&then, 0);
67251af36eSbostic then.tv_sec += 3;
68251af36eSbostic for (;;) {
69251af36eSbostic (void)gettimeofday(&wait, 0);
70251af36eSbostic timevalsub(&wait,&then,&wait);
71251af36eSbostic resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
72251af36eSbostic if (!resp)
73251af36eSbostic return(MASTER);
74251af36eSbostic
756ac1478eSgusella switch (resp->tsp_type) {
766ac1478eSgusella
776ac1478eSgusella case TSP_ACCEPT:
78251af36eSbostic (void)addmach(resp->tsp_name, &from,fromnet);
796ac1478eSgusella break;
8072b368c2Sbloom
816ac1478eSgusella case TSP_MASTERUP:
826ac1478eSgusella case TSP_MASTERREQ:
836ac1478eSgusella /*
84251af36eSbostic * If another timedaemon is coming up at the same
85251af36eSbostic * time, give up, and let it be the master.
866ac1478eSgusella */
87251af36eSbostic if (++loop_lim < 5
88251af36eSbostic && !good_host_name(resp->tsp_name)) {
89251af36eSbostic (void)addmach(resp->tsp_name, &from,fromnet);
90251af36eSbostic suppress(&from, resp->tsp_name, net);
91251af36eSbostic goto again;
92251af36eSbostic }
93251af36eSbostic rmnetmachs(net);
94251af36eSbostic return(SLAVE);
9572b368c2Sbloom
966ac1478eSgusella case TSP_QUIT:
976ac1478eSgusella case TSP_REFUSE:
986ac1478eSgusella /*
996ac1478eSgusella * Collision: change value of election timer
1006ac1478eSgusella * using exponential backoff.
101251af36eSbostic *
102251af36eSbostic * Fooey.
103251af36eSbostic * An exponential backoff on a delay starting at
104251af36eSbostic * 6 to 15 minutes for a process that takes
105251af36eSbostic * milliseconds is silly. It is particularly
106251af36eSbostic * strange that the original code would increase
107251af36eSbostic * the backoff without bound.
1086ac1478eSgusella */
109251af36eSbostic rmnetmachs(net);
110251af36eSbostic return(SLAVE);
11172b368c2Sbloom
1126ac1478eSgusella case TSP_ELECTION:
1136ac1478eSgusella /* no master for another round */
114251af36eSbostic htp = addmach(resp->tsp_name,&from,fromnet);
1156ac1478eSgusella msg.tsp_type = TSP_REFUSE;
1166ac1478eSgusella (void)strcpy(msg.tsp_name, hostname);
117251af36eSbostic answer = acksend(&msg, &htp->addr, htp->name,
118251af36eSbostic TSP_ACK, 0, htp->noanswer);
119251af36eSbostic if (!answer) {
120251af36eSbostic syslog(LOG_ERR, "error in election from %s",
121251af36eSbostic htp->name);
1226ac1478eSgusella }
1236ac1478eSgusella break;
12472b368c2Sbloom
1256ac1478eSgusella case TSP_SLAVEUP:
126251af36eSbostic (void)addmach(resp->tsp_name, &from,fromnet);
1276ac1478eSgusella break;
12872b368c2Sbloom
12956ffd31bSbloom case TSP_SETDATE:
13056ffd31bSbloom case TSP_SETDATEREQ:
1316ac1478eSgusella break;
13272b368c2Sbloom
1336ac1478eSgusella default:
1346ac1478eSgusella if (trace) {
1356ac1478eSgusella fprintf(fd, "candidate: ");
1368f3fa542Sbloom print(resp, &from);
1376ac1478eSgusella }
1386ac1478eSgusella break;
1396ac1478eSgusella }
1406ac1478eSgusella }
1416ac1478eSgusella }
142