|
|
1.1 ! root 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[] = "@(#)master.c 2.16 (Berkeley) 6/18/88"; ! 20: #endif /* not lint */ ! 21: ! 22: #include "globals.h" ! 23: #include <protocols/timed.h> ! 24: #include <sys/file.h> ! 25: #include <setjmp.h> ! 26: #include <utmp.h> ! 27: ! 28: extern int machup; ! 29: extern int measure_delta; ! 30: extern jmp_buf jmpenv; ! 31: ! 32: extern u_short sequence; ! 33: ! 34: #ifdef MEASURE ! 35: int header; ! 36: FILE *fp = NULL; ! 37: #endif ! 38: ! 39: /* ! 40: * The main function of `master' is to periodically compute the differences ! 41: * (deltas) between its clock and the clocks of the slaves, to compute the ! 42: * network average delta, and to send to the slaves the differences between ! 43: * their individual deltas and the network delta. ! 44: * While waiting, it receives messages from the slaves (i.e. requests for ! 45: * master's name, remote requests to set the network time, ...), and ! 46: * takes the appropriate action. ! 47: */ ! 48: ! 49: master() ! 50: { ! 51: int ind; ! 52: long pollingtime; ! 53: struct timeval wait; ! 54: struct timeval time; ! 55: struct timeval otime; ! 56: struct timezone tzone; ! 57: struct tsp *msg, to; ! 58: struct sockaddr_in saveaddr; ! 59: int findhost(); ! 60: char *date(); ! 61: struct tsp *readmsg(); ! 62: struct tsp *answer, *acksend(); ! 63: char olddate[32]; ! 64: struct sockaddr_in server; ! 65: register struct netinfo *ntp; ! 66: ! 67: #ifdef MEASURE ! 68: if (fp == NULL) { ! 69: fp = fopen("/usr/adm/timed.masterlog", "w"); ! 70: setlinebuf(fp); ! 71: } ! 72: #endif ! 73: ! 74: syslog(LOG_INFO, "This machine is master"); ! 75: if (trace) ! 76: fprintf(fd, "THIS MACHINE IS MASTER\n"); ! 77: ! 78: for (ntp = nettab; ntp != NULL; ntp = ntp->next) ! 79: if (ntp->status == MASTER) ! 80: masterup(ntp); ! 81: pollingtime = 0; ! 82: ! 83: loop: ! 84: (void)gettimeofday(&time, (struct timezone *)0); ! 85: if (time.tv_sec >= pollingtime) { ! 86: pollingtime = time.tv_sec + SAMPLEINTVL; ! 87: synch(0L); ! 88: ! 89: for (ntp = nettab; ntp != NULL; ntp = ntp->next) { ! 90: to.tsp_type = TSP_LOOP; ! 91: to.tsp_vers = TSPVERSION; ! 92: to.tsp_seq = sequence++; ! 93: to.tsp_hopcnt = 10; ! 94: (void)strcpy(to.tsp_name, hostname); ! 95: bytenetorder(&to); ! 96: if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, ! 97: &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) { ! 98: syslog(LOG_ERR, "sendto: %m"); ! 99: exit(1); ! 100: } ! 101: } ! 102: } ! 103: ! 104: wait.tv_sec = pollingtime - time.tv_sec; ! 105: wait.tv_usec = 0; ! 106: msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL); ! 107: if (msg != NULL) { ! 108: switch (msg->tsp_type) { ! 109: ! 110: case TSP_MASTERREQ: ! 111: break; ! 112: case TSP_SLAVEUP: ! 113: ind = addmach(msg->tsp_name, &from); ! 114: newslave(ind, msg->tsp_seq); ! 115: break; ! 116: case TSP_SETDATE: ! 117: saveaddr = from; ! 118: /* ! 119: * the following line is necessary due to syslog ! 120: * calling ctime() which clobbers the static buffer ! 121: */ ! 122: (void)strcpy(olddate, date()); ! 123: (void)gettimeofday(&time, &tzone); ! 124: otime = time; ! 125: time.tv_sec = msg->tsp_time.tv_sec; ! 126: time.tv_usec = msg->tsp_time.tv_usec; ! 127: (void)settimeofday(&time, &tzone); ! 128: syslog(LOG_NOTICE, "date changed from: %s", olddate); ! 129: logwtmp(otime, time); ! 130: msg->tsp_type = TSP_DATEACK; ! 131: msg->tsp_vers = TSPVERSION; ! 132: (void)strcpy(msg->tsp_name, hostname); ! 133: bytenetorder(msg); ! 134: if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, ! 135: &saveaddr, sizeof(struct sockaddr_in)) < 0) { ! 136: syslog(LOG_ERR, "sendto: %m"); ! 137: exit(1); ! 138: } ! 139: spreadtime(); ! 140: pollingtime = 0; ! 141: break; ! 142: case TSP_SETDATEREQ: ! 143: ind = findhost(msg->tsp_name); ! 144: if (ind < 0) { ! 145: syslog(LOG_WARNING, ! 146: "DATEREQ from uncontrolled machine"); ! 147: break; ! 148: } ! 149: if (hp[ind].seq != msg->tsp_seq) { ! 150: hp[ind].seq = msg->tsp_seq; ! 151: /* ! 152: * the following line is necessary due to syslog ! 153: * calling ctime() which clobbers the static buffer ! 154: */ ! 155: (void)strcpy(olddate, date()); ! 156: (void)gettimeofday(&time, &tzone); ! 157: otime = time; ! 158: time.tv_sec = msg->tsp_time.tv_sec; ! 159: time.tv_usec = msg->tsp_time.tv_usec; ! 160: (void)settimeofday(&time, &tzone); ! 161: syslog(LOG_NOTICE, ! 162: "date changed by %s from: %s", ! 163: msg->tsp_name, olddate); ! 164: logwtmp(otime, time); ! 165: spreadtime(); ! 166: pollingtime = 0; ! 167: } ! 168: break; ! 169: case TSP_MSITE: ! 170: case TSP_MSITEREQ: ! 171: break; ! 172: case TSP_TRACEON: ! 173: if (!(trace)) { ! 174: fd = fopen(tracefile, "w"); ! 175: setlinebuf(fd); ! 176: fprintf(fd, "Tracing started on: %s\n\n", ! 177: date()); ! 178: } ! 179: trace = ON; ! 180: break; ! 181: case TSP_TRACEOFF: ! 182: if (trace) { ! 183: fprintf(fd, "Tracing ended on: %s\n", date()); ! 184: (void)fclose(fd); ! 185: } ! 186: #ifdef GPROF ! 187: moncontrol(0); ! 188: _mcleanup(); ! 189: moncontrol(1); ! 190: #endif ! 191: trace = OFF; ! 192: break; ! 193: case TSP_ELECTION: ! 194: to.tsp_type = TSP_QUIT; ! 195: (void)strcpy(to.tsp_name, hostname); ! 196: server = from; ! 197: answer = acksend(&to, &server, msg->tsp_name, TSP_ACK, ! 198: (struct netinfo *)NULL); ! 199: if (answer == NULL) { ! 200: syslog(LOG_ERR, "election error"); ! 201: } else { ! 202: (void) addmach(msg->tsp_name, &from); ! 203: } ! 204: pollingtime = 0; ! 205: break; ! 206: case TSP_CONFLICT: ! 207: /* ! 208: * After a network partition, there can be ! 209: * more than one master: the first slave to ! 210: * come up will notify here the situation. ! 211: */ ! 212: ! 213: (void)strcpy(to.tsp_name, hostname); ! 214: ! 215: if (fromnet == NULL) ! 216: break; ! 217: for(;;) { ! 218: to.tsp_type = TSP_RESOLVE; ! 219: answer = acksend(&to, &fromnet->dest_addr, ! 220: (char *)ANYADDR, TSP_MASTERACK, fromnet); ! 221: if (answer == NULL) ! 222: break; ! 223: to.tsp_type = TSP_QUIT; ! 224: server = from; ! 225: msg = acksend(&to, &server, answer->tsp_name, ! 226: TSP_ACK, (struct netinfo *)NULL); ! 227: if (msg == NULL) { ! 228: syslog(LOG_ERR, "error on sending QUIT"); ! 229: } else { ! 230: (void) addmach(answer->tsp_name, &from); ! 231: } ! 232: } ! 233: masterup(fromnet); ! 234: pollingtime = 0; ! 235: break; ! 236: case TSP_RESOLVE: ! 237: /* ! 238: * do not want to call synch() while waiting ! 239: * to be killed! ! 240: */ ! 241: (void)gettimeofday(&time, (struct timezone *)0); ! 242: pollingtime = time.tv_sec + SAMPLEINTVL; ! 243: break; ! 244: case TSP_QUIT: ! 245: /* become slave */ ! 246: #ifdef MEASURE ! 247: if (fp != NULL) { ! 248: (void)fclose(fp); ! 249: fp = NULL; ! 250: } ! 251: #endif ! 252: longjmp(jmpenv, 2); ! 253: break; ! 254: case TSP_LOOP: ! 255: /* ! 256: * We should not have received this from a net ! 257: * we are master on. There must be two masters ! 258: * in this case. ! 259: */ ! 260: to.tsp_type = TSP_QUIT; ! 261: (void)strcpy(to.tsp_name, hostname); ! 262: server = from; ! 263: answer = acksend(&to, &server, msg->tsp_name, TSP_ACK, ! 264: (struct netinfo *)NULL); ! 265: if (answer == NULL) { ! 266: syslog(LOG_WARNING, ! 267: "loop breakage: no reply to QUIT"); ! 268: } else { ! 269: (void)addmach(msg->tsp_name, &from); ! 270: } ! 271: default: ! 272: if (trace) { ! 273: fprintf(fd, "garbage: "); ! 274: print(msg, &from); ! 275: } ! 276: break; ! 277: } ! 278: } ! 279: goto loop; ! 280: } ! 281: ! 282: /* ! 283: * `synch' synchronizes all the slaves by calling measure, ! 284: * networkdelta and correct ! 285: */ ! 286: ! 287: synch(mydelta) ! 288: long mydelta; ! 289: { ! 290: int i; ! 291: int measure_status; ! 292: long netdelta; ! 293: struct timeval tack; ! 294: #ifdef MEASURE ! 295: #define MAXLINES 8 ! 296: static int lines = 1; ! 297: struct timeval start, end; ! 298: #endif ! 299: int measure(); ! 300: int correct(); ! 301: long networkdelta(); ! 302: char *date(); ! 303: ! 304: if (slvcount > 1) { ! 305: #ifdef MEASURE ! 306: (void)gettimeofday(&start, (struct timezone *)0); ! 307: if (header == ON || --lines == 0) { ! 308: fprintf(fp, "%s\n", date()); ! 309: for (i=0; i<slvcount; i++) ! 310: fprintf(fp, "%.7s\t", hp[i].name); ! 311: fprintf(fp, "\n"); ! 312: lines = MAXLINES; ! 313: header = OFF; ! 314: } ! 315: #endif ! 316: machup = 1; ! 317: hp[0].delta = 0; ! 318: for(i=1; i<slvcount; i++) { ! 319: tack.tv_sec = 0; ! 320: tack.tv_usec = 500000; ! 321: if ((measure_status = measure(&tack, &hp[i].addr)) <0) { ! 322: syslog(LOG_ERR, "measure: %m"); ! 323: exit(1); ! 324: } ! 325: hp[i].delta = measure_delta; ! 326: if (measure_status == GOOD) ! 327: machup++; ! 328: } ! 329: if (status & SLAVE) { ! 330: /* called by a submaster */ ! 331: if (trace) ! 332: fprintf(fd, "submaster correct: %d ms.\n", ! 333: mydelta); ! 334: correct(mydelta); ! 335: } else { ! 336: if (machup > 1) { ! 337: netdelta = networkdelta(); ! 338: if (trace) ! 339: fprintf(fd, ! 340: "master correct: %d ms.\n", ! 341: mydelta); ! 342: correct(netdelta); ! 343: } ! 344: } ! 345: #ifdef MEASURE ! 346: gettimeofday(&end, 0); ! 347: end.tv_sec -= start.tv_sec; ! 348: end.tv_usec -= start.tv_usec; ! 349: if (end.tv_usec < 0) { ! 350: end.tv_sec -= 1; ! 351: end.tv_usec += 1000000; ! 352: } ! 353: fprintf(fp, "%d ms.\n", (end.tv_sec*1000+end.tv_usec/1000)); ! 354: #endif ! 355: for(i=1; i<slvcount; i++) { ! 356: if (hp[i].delta == HOSTDOWN) { ! 357: rmmach(i); ! 358: #ifdef MEASURE ! 359: header = ON; ! 360: #endif ! 361: } ! 362: } ! 363: } else { ! 364: if (status & SLAVE) { ! 365: correct(mydelta); ! 366: } ! 367: } ! 368: } ! 369: ! 370: /* ! 371: * 'spreadtime' sends the time to each slave after the master ! 372: * has received the command to set the network time ! 373: */ ! 374: ! 375: spreadtime() ! 376: { ! 377: int i; ! 378: struct tsp to; ! 379: struct tsp *answer, *acksend(); ! 380: ! 381: for(i=1; i<slvcount; i++) { ! 382: to.tsp_type = TSP_SETTIME; ! 383: (void)strcpy(to.tsp_name, hostname); ! 384: (void)gettimeofday(&to.tsp_time, (struct timezone *)0); ! 385: answer = acksend(&to, &hp[i].addr, hp[i].name, TSP_ACK, ! 386: (struct netinfo *)NULL); ! 387: if (answer == NULL) { ! 388: syslog(LOG_WARNING, ! 389: "no reply to SETTIME from: %s", hp[i].name); ! 390: } ! 391: } ! 392: } ! 393: ! 394: findhost(name) ! 395: char *name; ! 396: { ! 397: int i; ! 398: int ind; ! 399: ! 400: ind = -1; ! 401: for (i=1; i<slvcount; i++) { ! 402: if (strcmp(name, hp[i].name) == 0) { ! 403: ind = i; ! 404: break; ! 405: } ! 406: } ! 407: return(ind); ! 408: } ! 409: ! 410: /* ! 411: * 'addmach' adds a host to the list of controlled machines ! 412: * if not already there ! 413: */ ! 414: ! 415: addmach(name, addr) ! 416: char *name; ! 417: struct sockaddr_in *addr; ! 418: { ! 419: int ret; ! 420: int findhost(); ! 421: ! 422: ret = findhost(name); ! 423: if (ret < 0) { ! 424: hp[slvcount].addr = *addr; ! 425: hp[slvcount].name = (char *)malloc(MAXHOSTNAMELEN); ! 426: (void)strcpy(hp[slvcount].name, name); ! 427: hp[slvcount].seq = 0; ! 428: ret = slvcount; ! 429: if (slvcount < NHOSTS) ! 430: slvcount++; ! 431: else { ! 432: syslog(LOG_ERR, "no more slots in host table"); ! 433: } ! 434: } else { ! 435: /* need to clear sequence number anyhow */ ! 436: hp[ret].seq = 0; ! 437: } ! 438: #ifdef MEASURE ! 439: header = ON; ! 440: #endif ! 441: return(ret); ! 442: } ! 443: ! 444: /* ! 445: * Remove all the machines from the host table that exist on the given ! 446: * network. This is called when a master transitions to a slave on a ! 447: * given network. ! 448: */ ! 449: ! 450: rmnetmachs(ntp) ! 451: register struct netinfo *ntp; ! 452: { ! 453: int i; ! 454: ! 455: if (trace) ! 456: prthp(); ! 457: for (i = 1; i < slvcount; i++) ! 458: if ((hp[i].addr.sin_addr.s_addr & ntp->mask) == ntp->net) ! 459: rmmach(i--); ! 460: if (trace) ! 461: prthp(); ! 462: } ! 463: ! 464: /* ! 465: * remove the machine with the given index in the host table. ! 466: */ ! 467: rmmach(ind) ! 468: int ind; ! 469: { ! 470: if (trace) ! 471: fprintf(fd, "rmmach: %s\n", hp[ind].name); ! 472: free(hp[ind].name); ! 473: hp[ind] = hp[--slvcount]; ! 474: } ! 475: ! 476: prthp() ! 477: { ! 478: int i; ! 479: ! 480: fprintf(fd, "host table:"); ! 481: for (i=1; i<slvcount; i++) ! 482: fprintf(fd, " %s", hp[i].name); ! 483: fprintf(fd, "\n"); ! 484: } ! 485: ! 486: masterup(net) ! 487: struct netinfo *net; ! 488: { ! 489: struct timeval wait; ! 490: struct tsp to, *msg, *readmsg(); ! 491: ! 492: to.tsp_type = TSP_MASTERUP; ! 493: to.tsp_vers = TSPVERSION; ! 494: (void)strcpy(to.tsp_name, hostname); ! 495: bytenetorder(&to); ! 496: if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, &net->dest_addr, ! 497: sizeof(struct sockaddr_in)) < 0) { ! 498: syslog(LOG_ERR, "sendto: %m"); ! 499: exit(1); ! 500: } ! 501: ! 502: for (;;) { ! 503: wait.tv_sec = 1; ! 504: wait.tv_usec = 0; ! 505: msg = readmsg(TSP_SLAVEUP, (char *)ANYADDR, &wait, net); ! 506: if (msg != NULL) { ! 507: (void) addmach(msg->tsp_name, &from); ! 508: } else ! 509: break; ! 510: } ! 511: } ! 512: ! 513: newslave(ind, seq) ! 514: u_short seq; ! 515: { ! 516: struct tsp to; ! 517: struct tsp *answer, *acksend(); ! 518: ! 519: if (trace) ! 520: prthp(); ! 521: if (seq == 0 || hp[ind].seq != seq) { ! 522: hp[ind].seq = seq; ! 523: to.tsp_type = TSP_SETTIME; ! 524: (void)strcpy(to.tsp_name, hostname); ! 525: /* ! 526: * give the upcoming slave the time ! 527: * to check its input queue before ! 528: * setting the time ! 529: */ ! 530: sleep(1); ! 531: (void) gettimeofday(&to.tsp_time, ! 532: (struct timezone *)0); ! 533: answer = acksend(&to, &hp[ind].addr, ! 534: hp[ind].name, TSP_ACK, ! 535: (struct netinfo *)NULL); ! 536: if (answer == NULL) { ! 537: syslog(LOG_WARNING, ! 538: "no reply to initial SETTIME from: %s", ! 539: hp[ind].name); ! 540: rmmach(ind); ! 541: } ! 542: } ! 543: } ! 544: ! 545: char *wtmpfile = "/usr/adm/wtmp"; ! 546: struct utmp wtmp[2] = { ! 547: { "|", "", "", 0 }, ! 548: { "{", "", "", 0 } ! 549: }; ! 550: ! 551: logwtmp(otime, ntime) ! 552: struct timeval otime, ntime; ! 553: { ! 554: int f; ! 555: ! 556: wtmp[0].ut_time = otime.tv_sec + (otime.tv_usec + 500000) / 1000000; ! 557: wtmp[1].ut_time = ntime.tv_sec + (ntime.tv_usec + 500000) / 1000000; ! 558: if (wtmp[0].ut_time == wtmp[1].ut_time) ! 559: return; ! 560: if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) { ! 561: (void) write(f, (char *)wtmp, sizeof(wtmp)); ! 562: (void) close(f); ! 563: } ! 564: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.