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