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 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