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