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) 06/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 } 632