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