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

Defined functions

addnetname defined in line 594; used 2 times
casual defined in line 573; used 7 times
checkignorednets defined in line 411; used 3 times
date defined in line 584; used 13 times
firstslavenet defined in line 558; used 4 times
lookformaster defined in line 419; used 3 times
main defined in line 69; never used
makeslave defined in line 547; used 7 times
setstatus defined in line 500; used 11 times

Defined variables

Mflag defined in line 46; used 3 times
backoff defined in line 27; used 3 times
copyright defined in line 8; never used
delay1 defined in line 31; used 3 times
delay2 defined in line 32; used 11 times
hostname defined in line 34; used 5 times
hp defined in line 35; used 1 times
id defined in line 23; used 1 times
jmpenv defined in line 38; used 5 times
justquit defined in line 47; used 1 times
machup defined in line 29; used 8 times
nets defined in line 53; used 3 times
nignorednets defined in line 42; used 7 times
nmasternets defined in line 41; used 6 times
nnets defined in line 43; used 6 times
nslavenets defined in line 40; used 6 times
sccsid defined in line 12; never used
sequence defined in line 30; used 3 times
slavenet defined in line 44; used 21 times
sock defined in line 25; used 9 times
sock_raw defined in line 25; used 2 times

Defined struct's

nets defined in line 49; used 14 times

Defined macros

TSPTYPES defined in line 16; never used
Last modified: 1994-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6643
Valid CSS Valid XHTML 1.0 Strict