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