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