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: char copyright[] =
   9: "@(#) Copyright (c) 1985 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)timed.c	2.10 (Berkeley) 6/2/86";
  15: #endif not lint
  16: 
  17: #include "globals.h"
  18: #define TSPTYPES
  19: #include <protocols/timed.h>
  20: #include <net/if.h>
  21: #include <sys/file.h>
  22: #include <sys/ioctl.h>
  23: #include <setjmp.h>
  24: 
  25: int id;
  26: int trace;
  27: int sock, sock_raw;
  28: int status = 0;
  29: int backoff;
  30: int slvcount;               /* no. of slaves controlled by master */
  31: int machup;
  32: u_short sequence;           /* sequence number */
  33: long delay1;
  34: long delay2;
  35: long random();
  36: char hostname[MAXHOSTNAMELEN];
  37: struct host hp[NHOSTS];
  38: char tracefile[] = "/usr/adm/timed.log";
  39: FILE *fd;
  40: jmp_buf jmpenv;
  41: struct netinfo *nettab = NULL;
  42: int nslavenets;     /* Number of networks were I could be a slave */
  43: int nmasternets;    /* Number of networks were I could be a master */
  44: int nignorednets;   /* Number of ignored networks */
  45: int nnets;      /* Number of networks I am connected to */
  46: struct netinfo *slavenet;
  47: struct netinfo *firstslavenet();
  48: int Mflag;
  49: int justquit = 0;
  50: 
  51: struct nets {
  52:     char *name;
  53:     long net;
  54:     struct nets *next;
  55: } *nets = (struct nets *)0;
  56: 
  57: /*
  58:  * The timedaemons synchronize the clocks of hosts in a local area network.
  59:  * One daemon runs as master, all the others as slaves. The master
  60:  * performs the task of computing clock differences and sends correction
  61:  * values to the slaves.
  62:  * Slaves start an election to choose a new master when the latter disappears
  63:  * because of a machine crash, network partition, or when killed.
  64:  * A resolution protocol is used to kill all but one of the masters
  65:  * that happen to exist in segments of a partitioned network when the
  66:  * network partition is fixed.
  67:  *
  68:  * Authors: Riccardo Gusella & Stefano Zatti
  69:  */
  70: 
  71: main(argc, argv)
  72: int argc;
  73: char **argv;
  74: {
  75:     int on;
  76:     int ret;
  77:     long seed;
  78:     int nflag, iflag;
  79:     struct timeval time;
  80:     struct servent *srvp;
  81:     long casual();
  82:     char *date();
  83:     int n;
  84:     int flag;
  85:     char buf[BUFSIZ];
  86:     struct ifconf ifc;
  87:     struct ifreq ifreq, *ifr;
  88:     register struct netinfo *ntp;
  89:     struct netinfo *ntip;
  90:     struct netinfo *savefromnet;
  91:     struct sockaddr_in server;
  92:     u_short port;
  93:     uid_t getuid();
  94: 
  95: #ifdef lint
  96:     ntip = NULL;
  97: #endif
  98: 
  99:     Mflag = 0;
 100:     on = 1;
 101:     backoff = 1;
 102:     trace = OFF;
 103:     nflag = OFF;
 104:     iflag = OFF;
 105:     openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
 106: 
 107:     if (getuid() != 0) {
 108:         fprintf(stderr, "Timed: not superuser\n");
 109:         exit(1);
 110:     }
 111: 
 112:     while (--argc > 0 && **++argv == '-') {
 113:         (*argv)++;
 114:         do {
 115:             switch (**argv) {
 116: 
 117:             case 'M':
 118:                 Mflag = 1;
 119:                 break;
 120:             case 't':
 121:                 trace = ON;
 122:                 break;
 123:             case 'n':
 124:                 argc--, argv++;
 125:                 if (iflag) {
 126:                     fprintf(stderr,
 127:                     "timed: -i and -n make no sense together\n");
 128:                 } else {
 129:                     nflag = ON;
 130:                     addnetname(*argv);
 131:                 }
 132:                 while (*(++(*argv)+1)) ;
 133:                 break;
 134:             case 'i':
 135:                 argc--, argv++;
 136:                 if (nflag) {
 137:                     fprintf(stderr,
 138:                     "timed: -i and -n make no sense together\n");
 139:                 } else {
 140:                     iflag = ON;
 141:                     addnetname(*argv);
 142:                 }
 143:                 while (*(++(*argv)+1)) ;
 144:                 break;
 145:             default:
 146:                 fprintf(stderr, "timed: -%c: unknown option\n",
 147:                             **argv);
 148:                 break;
 149:             }
 150:         } while (*++(*argv));
 151:     }
 152: 
 153: #ifndef DEBUG
 154:     if (fork())
 155:         exit(0);
 156:     { int s;
 157:       for (s = getdtablesize(); s >= 0; --s)
 158:         (void) close(s);
 159:       (void) open("/dev/null", 0);
 160:       (void) dup2(0, 1);
 161:       (void) dup2(0, 2);
 162:       s = open("/dev/tty", 2);
 163:       if (s >= 0) {
 164:         (void) ioctl(s, TIOCNOTTY, (char *)0);
 165:         (void) close(s);
 166:       }
 167:     }
 168: #endif
 169: 
 170:     if (trace == ON) {
 171:         fd = fopen(tracefile, "w");
 172:         setlinebuf(fd);
 173:         fprintf(fd, "Tracing started on: %s\n\n",
 174:                     date());
 175:     }
 176: 
 177:     srvp = getservbyname("timed", "udp");
 178:     if (srvp == 0) {
 179:         syslog(LOG_CRIT, "unknown service 'timed/udp'");
 180:         exit(1);
 181:     }
 182:     port = srvp->s_port;
 183:     server.sin_port = srvp->s_port;
 184:     server.sin_family = AF_INET;
 185:     sock = socket(AF_INET, SOCK_DGRAM, 0);
 186:     if (sock < 0) {
 187:         syslog(LOG_ERR, "socket: %m");
 188:         exit(1);
 189:     }
 190:     if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
 191:                             sizeof(on)) < 0) {
 192:         syslog(LOG_ERR, "setsockopt: %m");
 193:         exit(1);
 194:     }
 195:     if (bind(sock, &server, sizeof(server))) {
 196:         if (errno == EADDRINUSE)
 197:                 syslog(LOG_ERR, "server already running");
 198:         else
 199:                 syslog(LOG_ERR, "bind: %m");
 200:         exit(1);
 201:     }
 202: 
 203:     /* choose a unique seed for random number generation */
 204:     (void)gettimeofday(&time, (struct timezone *)0);
 205:     seed = time.tv_sec + time.tv_usec;
 206:     srandom(seed);
 207: 
 208:     sequence = random();     /* initial seq number */
 209: 
 210:     /* rounds kernel variable time to multiple of 5 ms. */
 211:     time.tv_sec = 0;
 212:     time.tv_usec = -((time.tv_usec/1000) % 5) * 1000;
 213:     (void)adjtime(&time, (struct timeval *)0);
 214: 
 215:     id = getpid();
 216: 
 217:     if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
 218:         syslog(LOG_ERR, "gethostname: %m");
 219:         exit(1);
 220:     }
 221:     hp[0].name = hostname;
 222: 
 223:     if (nflag || iflag) {
 224:         struct netent *getnetent();
 225:         struct netent *n;
 226:         struct nets *np;
 227:         for ( np = nets ; np ; np = np->next) {
 228:             n = getnetbyname(np->name);
 229:             if (n == NULL) {
 230:                 syslog(LOG_ERR, "getnetbyname: unknown net %s",
 231:                     np->name);
 232:                 exit(1);
 233:             }
 234:             np->net = n->n_net;
 235:         }
 236:     }
 237:     ifc.ifc_len = sizeof(buf);
 238:     ifc.ifc_buf = buf;
 239:     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
 240:         syslog(LOG_ERR, "get interface configuration: %m");
 241:         exit(1);
 242:     }
 243:     n = ifc.ifc_len/sizeof(struct ifreq);
 244:     ntp = NULL;
 245:     for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
 246:         if (ifr->ifr_addr.sa_family != AF_INET)
 247:             continue;
 248:         ifreq = *ifr;
 249:         if (ntp == NULL)
 250:             ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
 251:         ntp->my_addr =
 252:             ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
 253:         if (ioctl(sock, SIOCGIFFLAGS,
 254:                     (char *)&ifreq) < 0) {
 255:             syslog(LOG_ERR, "get interface flags: %m");
 256:             continue;
 257:         }
 258:         if ((ifreq.ifr_flags & IFF_UP) == 0 ||
 259:             ((ifreq.ifr_flags & IFF_BROADCAST) == 0 &&
 260:             (ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) {
 261:             continue;
 262:         }
 263:         if (ifreq.ifr_flags & IFF_BROADCAST)
 264:             flag = 1;
 265:         else
 266:             flag = 0;
 267:         if (ioctl(sock, SIOCGIFNETMASK,
 268:                     (char *)&ifreq) < 0) {
 269:             syslog(LOG_ERR, "get netmask: %m");
 270:             continue;
 271:         }
 272:         ntp->mask = ((struct sockaddr_in *)
 273:             &ifreq.ifr_addr)->sin_addr.s_addr;
 274:         if (flag) {
 275:             if (ioctl(sock, SIOCGIFBRDADDR,
 276:                         (char *)&ifreq) < 0) {
 277:                 syslog(LOG_ERR, "get broadaddr: %m");
 278:                 continue;
 279:             }
 280:             ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
 281:         } else {
 282:             if (ioctl(sock, SIOCGIFDSTADDR,
 283:                         (char *)&ifreq) < 0) {
 284:                 syslog(LOG_ERR, "get destaddr: %m");
 285:                 continue;
 286:             }
 287:             ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
 288:         }
 289:         ntp->dest_addr.sin_port = port;
 290:         if (nflag || iflag) {
 291:             u_long addr, mask;
 292:             struct nets *n;
 293: 
 294:             addr = ntohl(ntp->dest_addr.sin_addr.s_addr);
 295:             mask = ntohl(ntp->mask);
 296:             while ((mask & 1) == 0) {
 297:                 addr >>= 1;
 298:                 mask >>= 1;
 299:             }
 300:             for (n = nets ; n ; n = n->next)
 301:                 if (addr == n->net)
 302:                     break;
 303:             if (nflag && !n || iflag && n)
 304:                 continue;
 305:         }
 306:         ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr;
 307:         ntp->next = NULL;
 308:         if (nettab == NULL) {
 309:             nettab = ntp;
 310:         } else {
 311:             ntip->next = ntp;
 312:         }
 313:         ntip = ntp;
 314:         ntp = NULL;
 315:     }
 316:     if (ntp)
 317:         (void) free((char *)ntp);
 318:     if (nettab == NULL) {
 319:         syslog(LOG_ERR, "No network usable");
 320:         exit(1);
 321:     }
 322: 
 323:     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
 324:         lookformaster(ntp);
 325:     setstatus();
 326:     /*
 327: 	 * Take care of some basic initialization.
 328: 	 */
 329:     /* us. delay to be used in response to broadcast */
 330:     delay1 = casual((long)10000, 200000);
 331: 
 332:     /* election timer delay in secs. */
 333:     delay2 = casual((long)MINTOUT, (long)MAXTOUT);
 334: 
 335:     if (Mflag) {
 336:         /* open raw socket used to measure time differences */
 337:         sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 338:         if (sock_raw < 0)  {
 339:             syslog(LOG_ERR, "opening raw socket: %m");
 340:             exit (1);
 341:         }
 342: 
 343:         /*
 344: 		 * number (increased by 1) of slaves controlled by master:
 345: 		 * used in master.c, candidate.c, networkdelta.c, and
 346: 		 * correct.c
 347: 		 */
 348:         slvcount = 1;
 349:         ret = setjmp(jmpenv);
 350: 
 351:         switch (ret) {
 352: 
 353:         case 0:
 354:             makeslave(firstslavenet());
 355:             setstatus();
 356:             break;
 357:         case 1:
 358:             /* Just lost our master */
 359:             setstatus();
 360:             slavenet->status = election(slavenet);
 361:             checkignorednets();
 362:             setstatus();
 363:             if (slavenet->status == MASTER)
 364:                 makeslave(firstslavenet());
 365:             else
 366:                 makeslave(slavenet);
 367:             setstatus();
 368:             break;
 369:         case 2:
 370:             /* Just been told to quit */
 371:             fromnet->status = SLAVE;
 372:             setstatus();
 373:             savefromnet = fromnet;
 374:             rmnetmachs(fromnet);
 375:             checkignorednets();
 376:             if (slavenet)
 377:                 makeslave(slavenet);
 378:             else
 379:                 makeslave(savefromnet);
 380:             setstatus();
 381:             justquit = 1;
 382:             break;
 383: 
 384:         default:
 385:             /* this should not happen */
 386:             syslog(LOG_ERR, "Attempt to enter invalid state");
 387:             break;
 388:         }
 389: 
 390:         if (status == MASTER)
 391:             master();
 392:         else
 393:             slave();
 394:     } else {
 395:         /* if Mflag is not set timedaemon is forced to act as a slave */
 396:         status = SLAVE;
 397:         if (setjmp(jmpenv)) {
 398:             setstatus();
 399:             checkignorednets();
 400:         }
 401:         makeslave(firstslavenet());
 402:         for (ntp = nettab; ntp != NULL; ntp = ntp->next)
 403:             if (ntp->status == MASTER)
 404:                 ntp->status = IGNORE;
 405:         setstatus();
 406:         slave();
 407:     }
 408: }
 409: 
 410: /*
 411:  * Try to become master over ignored nets..
 412:  */
 413: checkignorednets()
 414: {
 415:     register struct netinfo *ntp;
 416:     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
 417:         if (ntp->status == IGNORE)
 418:             lookformaster(ntp);
 419: }
 420: 
 421: lookformaster(ntp)
 422:     register struct netinfo *ntp;
 423: {
 424:     struct tsp resp, conflict, *answer, *readmsg(), *acksend();
 425:     struct timeval time;
 426:     char mastername[MAXHOSTNAMELEN];
 427:     struct sockaddr_in masteraddr;
 428: 
 429:     ntp->status = SLAVE;
 430:     /* look for master */
 431:     resp.tsp_type = TSP_MASTERREQ;
 432:     (void)strcpy(resp.tsp_name, hostname);
 433:     answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR,
 434:         TSP_MASTERACK, ntp);
 435:     if (answer == NULL) {
 436:         /*
 437: 		 * Various conditions can cause conflict: race between
 438: 		 * two just started timedaemons when no master is
 439: 		 * present, or timedaemon started during an election.
 440: 		 * Conservative approach is taken: give up and became a
 441: 		 * slave postponing election of a master until first
 442: 		 * timer expires.
 443: 		 */
 444:         time.tv_sec = time.tv_usec = 0;
 445:         answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR,
 446:             &time, ntp);
 447:         if (answer != NULL) {
 448:             ntp->status = SLAVE;
 449:             return;
 450:         }
 451: 
 452:         time.tv_sec = time.tv_usec = 0;
 453:         answer = readmsg(TSP_MASTERUP, (char *)ANYADDR,
 454:             &time, ntp);
 455:         if (answer != NULL) {
 456:             ntp->status = SLAVE;
 457:             return;
 458:         }
 459: 
 460:         time.tv_sec = time.tv_usec = 0;
 461:         answer = readmsg(TSP_ELECTION, (char *)ANYADDR,
 462:             &time, ntp);
 463:         if (answer != NULL) {
 464:             ntp->status = SLAVE;
 465:             return;
 466:         }
 467:         ntp->status = MASTER;
 468:     } else {
 469:         (void)strcpy(mastername, answer->tsp_name);
 470:         masteraddr = from;
 471: 
 472:         /*
 473: 		 * If network has been partitioned, there might be other
 474: 		 * masters; tell the one we have just acknowledged that
 475: 		 * it has to gain control over the others.
 476: 		 */
 477:         time.tv_sec = 0;
 478:         time.tv_usec = 300000;
 479:         answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time,
 480:             ntp);
 481:         /*
 482: 		 * checking also not to send CONFLICT to ack'ed master
 483: 		 * due to duplicated MASTERACKs
 484: 		 */
 485:         if (answer != NULL &&
 486:             strcmp(answer->tsp_name, mastername) != 0) {
 487:             conflict.tsp_type = TSP_CONFLICT;
 488:             (void)strcpy(conflict.tsp_name, hostname);
 489:             if (acksend(&conflict, &masteraddr, mastername,
 490:                 TSP_ACK, (struct netinfo *)NULL) == NULL) {
 491:                 syslog(LOG_ERR,
 492:                     "error on sending TSP_CONFLICT");
 493:                 exit(1);
 494:             }
 495:         }
 496:     }
 497: }
 498: /*
 499:  * based on the current network configuration, set the status, and count
 500:  * networks;
 501:  */
 502: setstatus()
 503: {
 504:     register struct netinfo *ntp;
 505: 
 506:     status = 0;
 507:     nmasternets = nslavenets = nnets = nignorednets = 0;
 508:     if (trace)
 509:         fprintf(fd, "Net status:\n");
 510:     for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
 511:         switch ((int)ntp->status) {
 512:           case MASTER:
 513:             nmasternets++;
 514:             break;
 515:           case SLAVE:
 516:             nslavenets++;
 517:             break;
 518:           case IGNORE:
 519:             nignorednets++;
 520:             break;
 521:         }
 522:         if (trace) {
 523:             fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
 524:             switch ((int)ntp->status) {
 525:               case MASTER:
 526:                 fprintf(fd, "MASTER\n");
 527:                 break;
 528:               case SLAVE:
 529:                 fprintf(fd, "SLAVE\n");
 530:                 break;
 531:               case IGNORE:
 532:                 fprintf(fd, "IGNORE\n");
 533:                 break;
 534:               default:
 535:                 fprintf(fd, "invalid state %d\n");
 536:                 break;
 537:             }
 538:         }
 539:         nnets++;
 540:         status |= ntp->status;
 541:     }
 542:     status &= ~IGNORE;
 543:     if (trace)
 544:         fprintf(fd,
 545:               "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
 546:               nnets, nmasternets, nslavenets, nignorednets);
 547: }
 548: 
 549: makeslave(net)
 550:     struct netinfo *net;
 551: {
 552:     register struct netinfo *ntp;
 553: 
 554:     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
 555:         if (ntp->status == SLAVE && ntp != net)
 556:             ntp->status = IGNORE;
 557:     slavenet = net;
 558: }
 559: 
 560: struct netinfo *
 561: firstslavenet()
 562: {
 563:     register struct netinfo *ntp;
 564: 
 565:     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
 566:         if (ntp->status == SLAVE)
 567:             return (ntp);
 568:     return ((struct netinfo *)0);
 569: }
 570: 
 571: /*
 572:  * `casual' returns a random number in the range [inf, sup]
 573:  */
 574: 
 575: long
 576: casual(inf, sup)
 577: long inf;
 578: long sup;
 579: {
 580:     float value;
 581: 
 582:     value = (float)(random() & 0x7fffffff) / 0x7fffffff;
 583:     return(inf + (sup - inf) * value);
 584: }
 585: 
 586: char *
 587: date()
 588: {
 589:     char    *ctime();
 590:     struct  timeval tv;
 591: 
 592:     (void)gettimeofday(&tv, (struct timezone *)0);
 593:     return (ctime(&tv.tv_sec));
 594: }
 595: 
 596: addnetname(name)
 597:     char *name;
 598: {
 599:     register struct nets **netlist = &nets;
 600: 
 601:     while (*netlist)
 602:         netlist = &((*netlist)->next);
 603:     *netlist = (struct nets *)malloc(sizeof **netlist);
 604:     if (*netlist == (struct nets *)0) {
 605:         syslog(LOG_ERR, "malloc failed");
 606:         exit(1);
 607:     }
 608:     bzero((char *)*netlist, sizeof(**netlist));
 609:     (*netlist)->name = name;
 610: }

Defined functions

addnetname defined in line 596; used 2 times
casual defined in line 575; used 7 times
checkignorednets defined in line 413; used 3 times
date defined in line 586; used 13 times
firstslavenet defined in line 560; used 4 times
lookformaster defined in line 421; used 3 times
main defined in line 71; never used
makeslave defined in line 549; used 7 times
setstatus defined in line 502; used 11 times

Defined variables

Mflag defined in line 48; used 3 times
backoff defined in line 29; used 3 times
copyright defined in line 8; never used
delay1 defined in line 33; used 3 times
delay2 defined in line 34; used 11 times
hostname defined in line 36; used 5 times
hp defined in line 37; used 1 times
id defined in line 25; used 1 times
jmpenv defined in line 40; used 5 times
justquit defined in line 49; used 1 times
machup defined in line 31; used 8 times
nets defined in line 55; used 3 times
nettab defined in line 41; used 28 times
nignorednets defined in line 44; used 7 times
nmasternets defined in line 43; used 6 times
nnets defined in line 45; used 6 times
nslavenets defined in line 42; used 6 times
sccsid defined in line 14; never used
slavenet defined in line 46; used 21 times
slvcount defined in line 30; used 21 times
sock defined in line 27; used 9 times
sock_raw defined in line 27; used 2 times
status defined in line 28; used 81 times
trace defined in line 26; used 48 times
tracefile defined in line 38; used 4 times

Defined struct's

nets defined in line 51; used 14 times

Defined macros

TSPTYPES defined in line 18; never used
Last modified: 1986-06-02
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2064
Valid CSS Valid XHTML 1.0 Strict