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