1 /*
2 * Copyright (c) 1985 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)slave.c 2.22 (Berkeley) 3/2/91";
36 #endif /* not lint */
37
38 #include "globals.h"
39 #include <protocols/timed.h>
40 #include <setjmp.h>
41 #include "pathnames.h"
42
43 extern jmp_buf jmpenv;
44
45 extern u_short sequence;
46
slave()47 slave()
48 {
49 int length;
50 int senddateack;
51 long electiontime, refusetime, looktime;
52 u_short seq;
53 char candidate[MAXHOSTNAMELEN];
54 struct tsp *msg, to, *readmsg();
55 struct sockaddr_in saveaddr, msaveaddr;
56 struct timeval time, wait;
57 struct tsp *answer, *acksend();
58 int timeout();
59 char *date();
60 long casual();
61 int bytenetorder();
62 char olddate[32];
63 struct sockaddr_in server;
64 register struct netinfo *ntp;
65 int ind;
66 struct tsp resp;
67 extern int Mflag;
68 extern int justquit;
69 #ifdef MEASURE
70 extern FILE *fp;
71 #endif
72 if (slavenet) {
73 resp.tsp_type = TSP_SLAVEUP;
74 resp.tsp_vers = TSPVERSION;
75 (void)strcpy(resp.tsp_name, hostname);
76 bytenetorder(&resp);
77 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
78 (struct sockaddr *)&slavenet->dest_addr,
79 sizeof(struct sockaddr_in)) < 0) {
80 syslog(LOG_ERR, "sendto: %m");
81 exit(1);
82 }
83 }
84
85 if (status & MASTER) {
86 #ifdef MEASURE
87 if (fp == NULL) {
88 fp = fopen(_PATH_MASTERLOG, "w");
89 setlinebuf(fp);
90 }
91 #endif
92 syslog(LOG_INFO, "THIS MACHINE IS A SUBMASTER");
93 if (trace) {
94 fprintf(fd, "THIS MACHINE IS A SUBMASTER\n");
95 }
96 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
97 if (ntp->status == MASTER)
98 masterup(ntp);
99
100 } else {
101 syslog(LOG_INFO, "THIS MACHINE IS A SLAVE");
102 if (trace) {
103 fprintf(fd, "THIS MACHINE IS A SLAVE\n");
104 }
105 }
106
107 seq = 0;
108 senddateack = OFF;
109 refusetime = 0;
110
111 (void)gettimeofday(&time, (struct timezone *)0);
112 electiontime = time.tv_sec + delay2;
113 if (Mflag)
114 if (justquit)
115 looktime = time.tv_sec + delay2;
116 else
117 looktime = 1;
118 else
119 looktime = 0;
120
121 loop:
122 length = sizeof(struct sockaddr_in);
123 (void)gettimeofday(&time, (struct timezone *)0);
124 if (time.tv_sec > electiontime) {
125 if (trace)
126 fprintf(fd, "election timer expired\n");
127 longjmp(jmpenv, 1);
128 }
129 if (looktime && time.tv_sec > looktime) {
130 if (trace)
131 fprintf(fd, "Looking for nets to master and loops\n");
132
133 if (nignorednets > 0) {
134 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
135 if (ntp->status == IGNORE) {
136 lookformaster(ntp);
137 if (ntp->status == MASTER)
138 masterup(ntp);
139 else
140 ntp->status = IGNORE;
141 }
142 }
143 setstatus();
144 #ifdef MEASURE
145 /*
146 * Check to see if we just became master
147 * (file not open)
148 */
149 if (fp == NULL) {
150 fp = fopen(_PATH_MASTERLOG, "w");
151 setlinebuf(fp);
152 }
153 #endif
154 }
155
156 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
157 if (ntp->status == MASTER) {
158 to.tsp_type = TSP_LOOP;
159 to.tsp_vers = TSPVERSION;
160 to.tsp_seq = sequence++;
161 to.tsp_hopcnt = 10;
162 (void)strcpy(to.tsp_name, hostname);
163 bytenetorder(&to);
164 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
165 (struct sockaddr *)&ntp->dest_addr,
166 sizeof(struct sockaddr_in)) < 0) {
167 syslog(LOG_ERR, "sendto: %m");
168 exit(1);
169 }
170 }
171 }
172 (void)gettimeofday(&time, (struct timezone *)0);
173 looktime = time.tv_sec + delay2;
174 }
175 wait.tv_sec = electiontime - time.tv_sec + 10;
176 wait.tv_usec = 0;
177 msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
178 if (msg != NULL) {
179 switch (msg->tsp_type) {
180 case TSP_SETDATE:
181 #ifdef TESTING
182 case TSP_TEST:
183 #endif
184 case TSP_MSITE:
185 case TSP_TRACEOFF:
186 case TSP_TRACEON:
187 break;
188 case TSP_MASTERUP:
189 if (fromnet == NULL) {
190 if (trace) {
191 fprintf(fd, "slave ignored: ");
192 print(msg, &from);
193 }
194 goto loop;
195 }
196 break;
197 default:
198 if (fromnet == NULL || fromnet->status == IGNORE) {
199 if (trace) {
200 fprintf(fd, "slave ignored: ");
201 print(msg, &from);
202 }
203 goto loop;
204 }
205 break;
206 }
207
208 switch (msg->tsp_type) {
209
210 case TSP_ADJTIME:
211 if (fromnet->status != SLAVE)
212 break;
213 (void)gettimeofday(&time, (struct timezone *)0);
214 electiontime = time.tv_sec + delay2;
215 if (seq != msg->tsp_seq) {
216 seq = msg->tsp_seq;
217 if ((status & SUBMASTER) == SUBMASTER) {
218 synch((msg->tsp_time.tv_sec * 1000) +
219 (msg->tsp_time.tv_usec / 1000));
220 } else {
221 adjclock(&(msg->tsp_time));
222 }
223 }
224 break;
225 case TSP_SETTIME:
226 if (fromnet->status != SLAVE)
227 break;
228 if (seq == msg->tsp_seq)
229 break;
230
231 seq = msg->tsp_seq;
232
233 (void)strcpy(olddate, date());
234 logwtmp("|", "date", "");
235 (void)settimeofday(&msg->tsp_time,
236 (struct timezone *)0);
237 logwtmp("{", "date", "");
238 syslog(LOG_NOTICE, "date changed by %s from: %s",
239 msg->tsp_name, olddate);
240 if ((status & SUBMASTER) == SUBMASTER)
241 spreadtime();
242 (void)gettimeofday(&time, (struct timezone *)0);
243 electiontime = time.tv_sec + delay2;
244
245 if (senddateack == ON) {
246 senddateack = OFF;
247 msg->tsp_type = TSP_DATEACK;
248 (void)strcpy(msg->tsp_name, hostname);
249 bytenetorder(msg);
250 length = sizeof(struct sockaddr_in);
251 if (sendto(sock, (char *)msg,
252 sizeof(struct tsp), 0,
253 (struct sockaddr *)&saveaddr,
254 length) < 0) {
255 syslog(LOG_ERR, "sendto: %m");
256 exit(1);
257 }
258 }
259 break;
260 case TSP_MASTERUP:
261 if (slavenet && fromnet != slavenet)
262 break;
263 makeslave(fromnet);
264 setstatus();
265 msg->tsp_type = TSP_SLAVEUP;
266 msg->tsp_vers = TSPVERSION;
267 (void)strcpy(msg->tsp_name, hostname);
268 bytenetorder(msg);
269 answerdelay();
270 length = sizeof(struct sockaddr_in);
271 if (sendto(sock, (char *)msg, sizeof(struct tsp), 0,
272 (struct sockaddr *)&from, length) < 0) {
273 syslog(LOG_ERR, "sendto: %m");
274 exit(1);
275 }
276 backoff = 1;
277 delay2 = casual((long)MINTOUT, (long)MAXTOUT);
278 (void)gettimeofday(&time, (struct timezone *)0);
279 electiontime = time.tv_sec + delay2;
280 refusetime = 0;
281 break;
282 case TSP_MASTERREQ:
283 if (fromnet->status != SLAVE)
284 break;
285 (void)gettimeofday(&time, (struct timezone *)0);
286 electiontime = time.tv_sec + delay2;
287 break;
288 case TSP_SETDATE:
289 saveaddr = from;
290 msg->tsp_type = TSP_SETDATEREQ;
291 msg->tsp_vers = TSPVERSION;
292 (void)strcpy(msg->tsp_name, hostname);
293 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
294 if (ntp->status == SLAVE)
295 break;
296 }
297 if (ntp == NULL)
298 break;
299 answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
300 TSP_DATEACK, ntp);
301 if (answer != NULL) {
302 msg->tsp_type = TSP_ACK;
303 bytenetorder(msg);
304 length = sizeof(struct sockaddr_in);
305 if (sendto(sock, (char *)msg,
306 sizeof(struct tsp), 0,
307 (struct sockaddr *)&saveaddr,
308 length) < 0) {
309 syslog(LOG_ERR, "sendto: %m");
310 exit(1);
311 }
312 senddateack = ON;
313 }
314 break;
315 case TSP_SETDATEREQ:
316 saveaddr = from;
317 if (status != SUBMASTER || fromnet->status != MASTER)
318 break;
319 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
320 if (ntp->status == SLAVE)
321 break;
322 }
323 ind = findhost(msg->tsp_name);
324 if (ind < 0) {
325 syslog(LOG_WARNING,
326 "DATEREQ from uncontrolled machine");
327 break;
328 }
329 syslog(LOG_DEBUG,
330 "forwarding date change request for %s",
331 msg->tsp_name);
332 (void)strcpy(msg->tsp_name, hostname);
333 answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
334 TSP_DATEACK, ntp);
335 if (answer != NULL) {
336 msg->tsp_type = TSP_DATEACK;
337 bytenetorder(msg);
338 length = sizeof(struct sockaddr_in);
339 if (sendto(sock, (char *)msg,
340 sizeof(struct tsp), 0,
341 (struct sockaddr *)&saveaddr,
342 length) < 0) {
343 syslog(LOG_ERR, "sendto: %m");
344 exit(1);
345 }
346 }
347 break;
348 case TSP_TRACEON:
349 if (!(trace)) {
350 fd = fopen(tracefile, "w");
351 setlinebuf(fd);
352 fprintf(fd, "Tracing started on: %s\n\n",
353 date());
354 }
355 trace = ON;
356 break;
357 case TSP_TRACEOFF:
358 if (trace) {
359 fprintf(fd, "Tracing ended on: %s\n", date());
360 (void)fclose(fd);
361 }
362 #ifdef GPROF
363 moncontrol(0);
364 _mcleanup();
365 moncontrol(1);
366 #endif
367 trace = OFF;
368 break;
369 case TSP_SLAVEUP:
370 if ((status & MASTER) && fromnet->status == MASTER) {
371 ind = addmach(msg->tsp_name, &from);
372 newslave(ind, msg->tsp_seq);
373 }
374 break;
375 case TSP_ELECTION:
376 if (fromnet->status == SLAVE) {
377 (void)gettimeofday(&time, (struct timezone *)0);
378 electiontime = time.tv_sec + delay2;
379 seq = 0; /* reset sequence number */
380 if (time.tv_sec < refusetime)
381 msg->tsp_type = TSP_REFUSE;
382 else {
383 msg->tsp_type = TSP_ACCEPT;
384 refusetime = time.tv_sec + 30;
385 }
386 (void)strcpy(candidate, msg->tsp_name);
387 (void)strcpy(msg->tsp_name, hostname);
388 answerdelay();
389 server = from;
390 answer = acksend(msg, &server, candidate, TSP_ACK,
391 (struct netinfo *)NULL);
392 if (answer == NULL)
393 syslog(LOG_WARNING,
394 "no answer from master candidate\n");
395 } else { /* fromnet->status == MASTER */
396 to.tsp_type = TSP_QUIT;
397 (void)strcpy(to.tsp_name, hostname);
398 server = from;
399 answer = acksend(&to, &server, msg->tsp_name,
400 TSP_ACK, (struct netinfo *)NULL);
401 if (answer == NULL) {
402 syslog(LOG_WARNING,
403 "election error: no reply to QUIT");
404 } else {
405 (void) addmach(msg->tsp_name, &from);
406 }
407 }
408 break;
409 case TSP_CONFLICT:
410 if (fromnet->status != MASTER)
411 break;
412 /*
413 * After a network partition, there can be
414 * more than one master: the first slave to
415 * come up will notify here the situation.
416 */
417 (void)strcpy(to.tsp_name, hostname);
418
419 if (fromnet == NULL)
420 break;
421 for(;;) {
422 to.tsp_type = TSP_RESOLVE;
423 answer = acksend(&to, &fromnet->dest_addr,
424 (char *)ANYADDR, TSP_MASTERACK, fromnet);
425 if (answer == NULL)
426 break;
427 to.tsp_type = TSP_QUIT;
428 server = from;
429 msg = acksend(&to, &server, answer->tsp_name,
430 TSP_ACK, (struct netinfo *)NULL);
431 if (msg == NULL) {
432 syslog(LOG_WARNING,
433 "conflict error: no reply to QUIT");
434 } else {
435 (void) addmach(answer->tsp_name, &from);
436 }
437 }
438 masterup(fromnet);
439 break;
440 case TSP_MSITE:
441 if (!slavenet)
442 break;
443 msaveaddr = from;
444 msg->tsp_type = TSP_MSITEREQ;
445 msg->tsp_vers = TSPVERSION;
446 (void)strcpy(msg->tsp_name, hostname);
447 answer = acksend(msg, &slavenet->dest_addr,
448 (char *)ANYADDR, TSP_ACK, slavenet);
449 if (answer != NULL) {
450 msg->tsp_type = TSP_ACK;
451 length = sizeof(struct sockaddr_in);
452 bytenetorder(msg);
453 if (sendto(sock, (char *)msg,
454 sizeof(struct tsp), 0,
455 (struct sockaddr *)&msaveaddr,
456 length) < 0) {
457 syslog(LOG_ERR, "sendto: %m");
458 exit(1);
459 }
460 }
461 break;
462 case TSP_ACCEPT:
463 case TSP_REFUSE:
464 break;
465 case TSP_RESOLVE:
466 break;
467 case TSP_QUIT:
468 /* become slave */
469 #ifdef MEASURE
470 if (fp != NULL) {
471 (void)fclose(fp);
472 fp = NULL;
473 }
474 #endif
475 longjmp(jmpenv, 2);
476 break;
477 #ifdef TESTING
478 case TSP_TEST:
479 electiontime = 0;
480 break;
481 #endif
482 case TSP_MSITEREQ:
483 if (status & MASTER)
484 break;
485 if (trace) {
486 fprintf(fd, "garbage: ");
487 print(msg, &from);
488 }
489 break;
490
491 case TSP_LOOP:
492 /* looking for loops of masters */
493 if ( !(status & MASTER))
494 break;
495 if (fromnet->status == SLAVE) {
496 if ( !strcmp(msg->tsp_name, hostname)) {
497 for(;;) {
498 to.tsp_type = TSP_RESOLVE;
499 answer = acksend(&to, &fromnet->dest_addr,
500 (char *)ANYADDR, TSP_MASTERACK,
501 fromnet);
502 if (answer == NULL)
503 break;
504 to.tsp_type = TSP_QUIT;
505 (void)strcpy(to.tsp_name, hostname);
506 server = from;
507 answer = acksend(&to, &server,
508 answer->tsp_name, TSP_ACK,
509 (struct netinfo *)NULL);
510 if (answer == NULL) {
511 syslog(LOG_ERR, "loop kill error");
512 } else {
513 electiontime = 0;
514 }
515 }
516 } else {
517 if (msg->tsp_hopcnt-- <= 0)
518 break;
519 bytenetorder(msg);
520 ntp = nettab;
521 for (; ntp != NULL; ntp = ntp->next)
522 if (ntp->status == MASTER)
523 if (sendto(sock, (char *)msg,
524 sizeof(struct tsp), 0,
525 (struct sockaddr *)&ntp->dest_addr,
526 length) < 0) {
527 syslog(LOG_ERR, "sendto: %m");
528 exit(1);
529 }
530 }
531 } else {
532 /*
533 * We should not have received this from a net
534 * we are master on. There must be two masters
535 * in this case.
536 */
537 if (fromnet->my_addr.s_addr == from.sin_addr.s_addr)
538 break;
539 for (;;) {
540 to.tsp_type = TSP_RESOLVE;
541 answer = acksend(&to, &fromnet->dest_addr,
542 (char *)ANYADDR, TSP_MASTERACK,
543 fromnet);
544 if (answer == NULL)
545 break;
546 to.tsp_type = TSP_QUIT;
547 (void)strcpy(to.tsp_name, hostname);
548 server = from;
549 answer = acksend(&to, &server, answer->tsp_name,
550 TSP_ACK, (struct netinfo *)NULL);
551 if (answer == NULL) {
552 syslog(LOG_ERR, "loop kill error2");
553 } else {
554 (void)addmach(msg->tsp_name, &from);
555 }
556 }
557 }
558 break;
559 default:
560 if (trace) {
561 fprintf(fd, "garbage: ");
562 print(msg, &from);
563 }
564 break;
565 }
566 }
567 goto loop;
568 }
569
570 /*
571 * Used before answering a broadcast message to avoid network
572 * contention and likely collisions.
573 */
answerdelay()574 answerdelay()
575 {
576 struct timeval timeout;
577
578 timeout.tv_sec = 0;
579 timeout.tv_usec = delay1;
580
581 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
582 &timeout);
583 return;
584 }
585