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