|
|
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: 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.