Commit | Line | Data |
---|---|---|
dc32c900 RG |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
65215728 | 8 | static char sccsid[] = "@(#)master.c 1.3 (Berkeley) %G%"; |
dc32c900 RG |
9 | #endif not lint |
10 | ||
11 | #include "globals.h" | |
12 | #include <protocols/timed.h> | |
13 | #include <setjmp.h> | |
14 | ||
dc32c900 RG |
15 | extern struct sockaddr_in from; |
16 | extern struct sockaddr_in server; | |
17 | ||
18 | extern int trace; | |
19 | extern int machup; | |
20 | extern int slvcount; | |
21 | extern int measure_delta; | |
22 | extern int sock; | |
23 | extern char hostname[]; | |
24 | extern struct host hp[]; | |
25 | extern char *fj; | |
26 | extern FILE *fd; | |
27 | ||
28 | #ifdef MEASURE | |
29 | int header; | |
30 | char *fi; | |
31 | FILE *fp; | |
32 | #endif | |
33 | ||
34 | /* | |
35 | * The main function of `master' is to periodically compute the differences | |
36 | * (deltas) between its clock and the clocks of the slaves, to compute the | |
37 | * network average delta, and to send to the slaves the differences between | |
38 | * their individual deltas and the network delta. | |
39 | * While waiting, it receives messages from the slaves (i.e. requests for | |
40 | * master's name, remote requests to set the network time, ...), and | |
41 | * takes the appropriate action. | |
42 | */ | |
43 | ||
44 | master() | |
45 | { | |
46 | int ind; | |
47 | int length; | |
48 | long pollingtime; | |
49 | struct timeval wait; | |
50 | struct timeval time; | |
51 | struct timezone tzone; | |
52 | struct timeval mytime; | |
53 | struct tsp *msg, to; | |
54 | struct sockaddr_in saveaddr; | |
55 | extern jmp_buf jmpenv; | |
56 | int findhost(); | |
57 | char *date(); | |
58 | char *strcpy(); | |
59 | struct tsp *readmsg(); | |
60 | struct tsp *answer, *acksend(); | |
65215728 | 61 | char olddate[32]; |
dc32c900 RG |
62 | |
63 | #ifdef MEASURE | |
64 | fi = "/usr/adm/timed.masterlog"; | |
65 | fp = fopen(fi, "w"); | |
66 | #endif | |
67 | ||
f99c5f73 | 68 | syslog(LOG_INFO, "THIS MACHINE IS MASTER"); |
dc32c900 RG |
69 | if (trace) |
70 | fprintf(fd, "THIS MACHINE IS MASTER\n"); | |
71 | ||
72 | masterup(); | |
73 | pollingtime = 0; | |
74 | ||
75 | loop: | |
76 | (void)gettimeofday(&time, (struct timezone *)0); | |
77 | if (time.tv_sec >= pollingtime) { | |
78 | pollingtime = time.tv_sec + SAMPLEINTVL; | |
79 | synch(); | |
80 | } | |
81 | ||
82 | wait.tv_sec = pollingtime - time.tv_sec; | |
83 | wait.tv_usec = 0; | |
84 | msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait); | |
85 | if (msg != NULL) { | |
86 | switch (msg->tsp_type) { | |
87 | ||
88 | case TSP_MASTERREQ: | |
89 | ind = addmach(msg->tsp_name); | |
90 | if (trace) | |
91 | prthp(); | |
92 | if (hp[ind].seq != msg->tsp_seq) { | |
93 | hp[ind].seq = msg->tsp_seq; | |
94 | bcopy((char *)&hp[ind].addr, | |
95 | (char *)&(server.sin_addr.s_addr), | |
96 | hp[ind].length); | |
97 | to.tsp_type = TSP_SETTIME; | |
98 | (void)strcpy(to.tsp_name, hostname); | |
99 | /* | |
100 | * give the upcoming slave the time | |
101 | * to check its input queue before | |
102 | * setting the time | |
103 | */ | |
104 | sleep(1); | |
105 | to.tsp_time.tv_usec = 0; | |
106 | (void)gettimeofday(&mytime, (struct timezone *)0); | |
107 | to.tsp_time.tv_sec = mytime.tv_sec; | |
108 | answer = acksend(&to, hp[ind].name, TSP_ACK); | |
109 | if (answer == NULL) { | |
f99c5f73 | 110 | syslog(LOG_ERR, "ERROR ON SETTIME machine: %s", hp[ind].name); |
dc32c900 RG |
111 | slvcount--; |
112 | } | |
dc32c900 RG |
113 | } |
114 | break; | |
115 | case TSP_SLAVEUP: | |
116 | (void) addmach(msg->tsp_name); | |
dc32c900 RG |
117 | break; |
118 | case TSP_DATE: | |
119 | saveaddr = from; | |
120 | msg->tsp_time.tv_usec = 0; | |
65215728 JB |
121 | /* |
122 | * the following line is necessary due to syslog | |
123 | * calling ctime() which clobbers the static buffer | |
124 | */ | |
125 | (void)strcpy(olddate, date()); | |
dc32c900 RG |
126 | (void)gettimeofday(&time, &tzone); |
127 | time.tv_sec += msg->tsp_time.tv_sec; | |
128 | time.tv_sec++; | |
129 | (void)settimeofday(&time, &tzone); | |
f99c5f73 | 130 | syslog(LOG_NOTICE, "date changed from: %s", olddate); |
dc32c900 RG |
131 | msg->tsp_type = TSP_DATEACK; |
132 | msg->tsp_vers = TSPVERSION; | |
133 | (void)strcpy(msg->tsp_name, hostname); | |
134 | bytenetorder(msg); | |
135 | length = sizeof(struct sockaddr_in); | |
136 | if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, | |
137 | &saveaddr, length) < 0) { | |
f99c5f73 | 138 | syslog(LOG_ERR, "sendto: %m"); |
dc32c900 RG |
139 | exit(1); |
140 | } | |
141 | spreadtime(); | |
142 | pollingtime = 0; | |
143 | break; | |
144 | case TSP_DATEREQ: | |
145 | ind = findhost(msg->tsp_name); | |
146 | if (ind < 0) { | |
f99c5f73 JB |
147 | syslog(LOG_ERR, |
148 | "DATEREQ from uncontrolled machine"); | |
149 | break; | |
dc32c900 RG |
150 | } |
151 | if (hp[ind].seq != msg->tsp_seq) { | |
152 | hp[ind].seq = msg->tsp_seq; | |
153 | msg->tsp_time.tv_usec = 0; | |
65215728 JB |
154 | /* |
155 | * the following line is necessary due to syslog | |
156 | * calling ctime() which clobbers the static buffer | |
157 | */ | |
158 | (void)strcpy(olddate, date()); | |
dc32c900 RG |
159 | (void)gettimeofday(&time, &tzone); |
160 | time.tv_sec += msg->tsp_time.tv_sec; | |
161 | time.tv_sec++; | |
162 | (void)settimeofday(&time, &tzone); | |
f99c5f73 JB |
163 | syslog(LOG_NOTICE, |
164 | "date changed by %s from: %s", | |
165 | msg->tsp_name, olddate); | |
dc32c900 RG |
166 | spreadtime(); |
167 | pollingtime = 0; | |
168 | } | |
169 | break; | |
170 | case TSP_MSITE: | |
171 | msg->tsp_type = TSP_ACK; | |
172 | msg->tsp_vers = TSPVERSION; | |
173 | (void)strcpy(msg->tsp_name, hostname); | |
174 | bytenetorder(msg); | |
175 | length = sizeof(struct sockaddr_in); | |
176 | if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, | |
177 | &from, length) < 0) { | |
f99c5f73 | 178 | syslog(LOG_ERR, "sendto: %m"); |
dc32c900 RG |
179 | exit(1); |
180 | } | |
181 | break; | |
182 | case TSP_MSITEREQ: | |
183 | break; | |
184 | case TSP_TRACEON: | |
185 | if (!(trace)) { | |
186 | fd = fopen(fj, "w"); | |
187 | fprintf(fd, "Tracing started on: %s\n\n", | |
188 | date()); | |
189 | (void)fflush(fd); | |
190 | } | |
191 | trace = ON; | |
192 | break; | |
193 | case TSP_TRACEOFF: | |
194 | if (trace) { | |
195 | fprintf(fd, "Tracing ended on: %s\n", date()); | |
196 | (void)fflush(fd); | |
f99c5f73 | 197 | (void)fclose(fd); |
dc32c900 RG |
198 | } |
199 | trace = OFF; | |
200 | break; | |
201 | case TSP_ELECTION: | |
202 | to.tsp_type = TSP_QUIT; | |
203 | (void)strcpy(to.tsp_name, hostname); | |
204 | server = from; | |
205 | answer = acksend(&to, msg->tsp_name, TSP_ACK); | |
206 | if (answer == NULL) { | |
f99c5f73 | 207 | syslog(LOG_ERR, "election error"); |
dc32c900 RG |
208 | } else { |
209 | (void) addmach(msg->tsp_name); | |
210 | } | |
211 | pollingtime = 0; | |
212 | break; | |
213 | case TSP_CONFLICT: | |
214 | /* | |
215 | * After a network partition, there can be | |
216 | * more than one master: the first slave to | |
217 | * come up will notify here the situation. | |
218 | */ | |
219 | ||
220 | (void)strcpy(to.tsp_name, hostname); | |
221 | ||
222 | for(;;) { | |
223 | to.tsp_type = TSP_RESOLVE; | |
224 | answer = acksend(&to, (char *)ANYADDR, | |
225 | TSP_MASTERACK); | |
226 | if (answer == NULL) | |
227 | break; | |
dc32c900 RG |
228 | to.tsp_type = TSP_QUIT; |
229 | server = from; | |
230 | msg = acksend(&to, answer->tsp_name, | |
231 | TSP_MASTERACK); | |
232 | if (msg == NULL) { | |
f99c5f73 JB |
233 | syslog(LOG_ERR, "error on sending QUIT"); |
234 | } else { | |
235 | (void) addmach(answer->tsp_name); | |
dc32c900 RG |
236 | } |
237 | } | |
238 | masterup(); | |
239 | pollingtime = 0; | |
240 | break; | |
241 | case TSP_RESOLVE: | |
242 | /* | |
243 | * do not want to call synch() while waiting | |
244 | * to be killed! | |
245 | */ | |
246 | (void)gettimeofday(&time, (struct timezone *)0); | |
247 | pollingtime = time.tv_sec + SAMPLEINTVL; | |
248 | break; | |
249 | case TSP_QUIT: | |
250 | /* become slave */ | |
251 | #ifdef MEASURE | |
f99c5f73 | 252 | (void)fclose(fp); |
dc32c900 RG |
253 | #endif |
254 | longjmp(jmpenv, 2); | |
255 | break; | |
256 | default: | |
257 | if (trace) { | |
258 | fprintf(fd, "garbage: "); | |
259 | print(msg); | |
260 | } | |
261 | break; | |
262 | } | |
263 | } | |
264 | goto loop; | |
265 | } | |
266 | ||
267 | /* | |
268 | * `synch' synchronizes all the slaves by calling measure, | |
269 | * networkdelta and correct | |
270 | */ | |
271 | ||
272 | synch() | |
273 | { | |
274 | int i; | |
275 | int measure_status; | |
276 | long netdelta; | |
277 | struct timeval tack; | |
278 | #ifdef MEASURE | |
279 | #define MAXLINES 8 | |
f99c5f73 | 280 | static int lines = 1; |
dc32c900 RG |
281 | struct timeval start, end; |
282 | #endif | |
283 | int measure(); | |
284 | int correct(); | |
285 | long networkdelta(); | |
286 | char *date(); | |
287 | ||
288 | if (slvcount > 1) { | |
289 | #ifdef MEASURE | |
290 | (void)gettimeofday(&start, (struct timezone *)0); | |
291 | if (header == ON || --lines == 0) { | |
292 | fprintf(fp, "%s\n", date()); | |
293 | for (i=0; i<slvcount; i++) | |
294 | fprintf(fp, "%.7s\t", hp[i].name); | |
295 | fprintf(fp, "\n"); | |
296 | lines = MAXLINES; | |
297 | header = OFF; | |
298 | } | |
299 | #endif | |
300 | machup = 1; | |
301 | hp[0].delta = 0; | |
302 | for(i=1; i<slvcount; i++) { | |
303 | bcopy((char *)&hp[i].addr, | |
304 | (char *)&(server.sin_addr.s_addr), | |
305 | hp[i].length); | |
306 | tack.tv_sec = 0; | |
307 | tack.tv_usec = 100000; | |
308 | if ((measure_status = measure(&tack, ON)) < 0) { | |
f99c5f73 | 309 | syslog(LOG_ERR, "measure: %m"); |
dc32c900 RG |
310 | exit(1); |
311 | } | |
312 | hp[i].delta = measure_delta; | |
313 | if (measure_status == GOOD) | |
314 | machup++; | |
315 | } | |
316 | if (machup > 1) { | |
317 | netdelta = networkdelta(); | |
318 | correct(netdelta); | |
319 | } | |
320 | #ifdef MEASURE | |
321 | gettimeofday(&end, 0); | |
322 | end.tv_sec -= start.tv_sec; | |
323 | end.tv_usec -= start.tv_usec; | |
324 | if (end.tv_usec < 0) { | |
325 | end.tv_sec -= 1; | |
326 | end.tv_usec += 1000000; | |
327 | } | |
328 | fprintf(fp, "%d ms.\n", (end.tv_sec*1000+end.tv_usec/1000)); | |
329 | (void)fflush(fp); | |
330 | #endif | |
331 | for(i=1; i<slvcount; i++) { | |
332 | if (hp[i].delta == HOSTDOWN) { | |
333 | free((char *)hp[i].name); | |
334 | hp[i] = hp[--slvcount]; | |
335 | #ifdef MEASURE | |
336 | header = ON; | |
337 | #endif | |
338 | } | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | /* | |
344 | * 'spreadtime' sends the time to each slave after the master | |
345 | * has received the command to set the network time | |
346 | */ | |
347 | ||
348 | spreadtime() | |
349 | { | |
350 | int i; | |
dc32c900 RG |
351 | struct tsp to; |
352 | struct tsp *answer, *acksend(); | |
353 | ||
354 | for(i=1; i<slvcount; i++) { | |
355 | bcopy((char *)&hp[i].addr, (char *)&(server.sin_addr.s_addr), | |
356 | hp[i].length); | |
357 | to.tsp_type = TSP_SETTIME; | |
dc32c900 | 358 | (void)strcpy(to.tsp_name, hostname); |
f99c5f73 | 359 | (void)gettimeofday(&to.tsp_time, (struct timezone *)0); |
dc32c900 RG |
360 | answer = acksend(&to, hp[i].name, TSP_ACK); |
361 | if (answer == NULL) { | |
f99c5f73 | 362 | syslog(LOG_ERR, "ERROR ON SETTIME machine: %s", hp[i].name); |
dc32c900 RG |
363 | } |
364 | } | |
365 | } | |
366 | ||
367 | findhost(name) | |
368 | char *name; | |
369 | { | |
370 | int i; | |
371 | int ind; | |
372 | ||
373 | ind = -1; | |
374 | for (i=1; i<slvcount; i++) { | |
375 | if (strcmp(name, hp[i].name) == 0) { | |
376 | ind = i; | |
377 | break; | |
378 | } | |
379 | } | |
380 | return(ind); | |
381 | } | |
382 | ||
383 | /* | |
384 | * 'addmach' adds a host to the list of controlled machines | |
385 | * if not already there | |
386 | */ | |
387 | ||
388 | addmach(name) | |
389 | char *name; | |
390 | { | |
391 | int ret; | |
392 | int findhost(); | |
393 | char *malloc(); | |
394 | struct hostent *hptmp, *gethostbyname(); | |
395 | ||
396 | ret = findhost(name); | |
397 | if (ret < 0) { | |
398 | hptmp = gethostbyname(name); | |
399 | if (hptmp == NULL) { | |
f99c5f73 | 400 | syslog(LOG_ERR, "gethostbyname: %m"); |
dc32c900 RG |
401 | exit(1); |
402 | } | |
403 | hp[slvcount].length = hptmp->h_length; | |
404 | bcopy((char *)hptmp->h_addr, (char *)&hp[slvcount].addr, | |
405 | hptmp->h_length); | |
f99c5f73 JB |
406 | hp[slvcount].name = (char *)malloc(MAXHOSTNAMELEN); |
407 | (void)strcpy(hp[slvcount].name, name); | |
dc32c900 RG |
408 | hp[slvcount].seq = 0; |
409 | ret = slvcount; | |
410 | if (slvcount < NHOSTS) | |
411 | slvcount++; | |
412 | else { | |
f99c5f73 | 413 | syslog(LOG_ALERT, "no more slots in host table"); |
dc32c900 RG |
414 | } |
415 | } else { | |
416 | /* need to clear sequence number anyhow */ | |
417 | hp[ret].seq = 0; | |
418 | } | |
419 | #ifdef MEASURE | |
420 | header = ON; | |
421 | #endif | |
422 | return(ret); | |
423 | } | |
424 | ||
425 | prthp() | |
426 | { | |
427 | int i; | |
428 | ||
429 | fprintf(fd, "host table:"); | |
430 | for (i=1; i<slvcount; i++) | |
431 | fprintf(fd, " %s", hp[i].name); | |
432 | fprintf(fd, "\n"); | |
433 | } | |
434 | ||
435 | masterup() | |
436 | { | |
437 | struct timeval wait; | |
438 | char *strcpy(); | |
439 | struct tsp to, *msg, *readmsg(); | |
440 | ||
441 | to.tsp_type = TSP_MASTERUP; | |
442 | (void)strcpy(to.tsp_name, hostname); | |
443 | broadcast(&to); | |
444 | ||
445 | for (;;) { | |
446 | wait.tv_sec = 1; | |
447 | wait.tv_usec = 0; | |
448 | msg = readmsg(TSP_SLAVEUP, (char *)ANYADDR, &wait); | |
449 | if (msg != NULL) { | |
450 | (void) addmach(msg->tsp_name); | |
451 | } else | |
452 | break; | |
453 | } | |
454 | } |