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