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: }