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 long 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: %ld 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: %ld 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: }

Defined functions

addmach defined in line 404; used 12 times
findhost defined in line 383; used 5 times
logwtmp defined in line 540; used 3 times
master defined in line 38; used 1 times
masterup defined in line 475; used 5 times
newslave defined in line 502; used 2 times
prthp defined in line 465; used 3 times
rmmach defined in line 456; used 3 times
rmnetmachs defined in line 439; used 1 times
spreadtime defined in line 364; used 3 times
synch defined in line 276; used 2 times

Defined variables

header defined in line 24; used 4 times
sccsid defined in line 8; never used
wtmp defined in line 535; used 6 times
wtmpfile defined in line 534; used 1 times

Defined macros

MAXLINES defined in line 284; used 1 times
Last modified: 1988-12-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 995
Valid CSS Valid XHTML 1.0 Strict