xref: /386bsd/usr/src/usr.sbin/timed/timed/slave.c (revision a2142627)
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