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 static char sccsid[] = "@(#)slave.c 2.20 (Berkeley) 04/02/89"; 20 #endif /* not lint */ 21 22 #include "globals.h" 23 #include <protocols/timed.h> 24 #include <setjmp.h> 25 #include "pathnames.h" 26 27 extern jmp_buf jmpenv; 28 29 extern u_short sequence; 30 31 slave() 32 { 33 int length; 34 int senddateack; 35 long electiontime, refusetime, looktime; 36 u_short seq; 37 char candidate[MAXHOSTNAMELEN]; 38 struct tsp *msg, to, *readmsg(); 39 struct sockaddr_in saveaddr, msaveaddr; 40 struct timeval time, wait; 41 struct tsp *answer, *acksend(); 42 int timeout(); 43 char *date(); 44 long casual(); 45 int bytenetorder(); 46 char olddate[32]; 47 struct sockaddr_in server; 48 register struct netinfo *ntp; 49 int ind; 50 struct tsp resp; 51 extern int Mflag; 52 extern int justquit; 53 #ifdef MEASURE 54 extern FILE *fp; 55 #endif 56 if (slavenet) { 57 resp.tsp_type = TSP_SLAVEUP; 58 resp.tsp_vers = TSPVERSION; 59 (void)strcpy(resp.tsp_name, hostname); 60 bytenetorder(&resp); 61 if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0, 62 &slavenet->dest_addr, sizeof(struct sockaddr_in)) < 0) { 63 syslog(LOG_ERR, "sendto: %m"); 64 exit(1); 65 } 66 } 67 68 if (status & MASTER) { 69 #ifdef MEASURE 70 if (fp == NULL) { 71 fp = fopen(_PATH_MASTERLOG, "w"); 72 setlinebuf(fp); 73 } 74 #endif 75 syslog(LOG_INFO, "THIS MACHINE IS A SUBMASTER"); 76 if (trace) { 77 fprintf(fd, "THIS MACHINE IS A SUBMASTER\n"); 78 } 79 for (ntp = nettab; ntp != NULL; ntp = ntp->next) 80 if (ntp->status == MASTER) 81 masterup(ntp); 82 83 } else { 84 syslog(LOG_INFO, "THIS MACHINE IS A SLAVE"); 85 if (trace) { 86 fprintf(fd, "THIS MACHINE IS A SLAVE\n"); 87 } 88 } 89 90 seq = 0; 91 senddateack = OFF; 92 refusetime = 0; 93 94 (void)gettimeofday(&time, (struct timezone *)0); 95 electiontime = time.tv_sec + delay2; 96 if (Mflag) 97 if (justquit) 98 looktime = time.tv_sec + delay2; 99 else 100 looktime = 1; 101 else 102 looktime = 0; 103 104 loop: 105 length = sizeof(struct sockaddr_in); 106 (void)gettimeofday(&time, (struct timezone *)0); 107 if (time.tv_sec > electiontime) { 108 if (trace) 109 fprintf(fd, "election timer expired\n"); 110 longjmp(jmpenv, 1); 111 } 112 if (looktime && time.tv_sec > looktime) { 113 if (trace) 114 fprintf(fd, "Looking for nets to master and loops\n"); 115 116 if (nignorednets > 0) { 117 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 118 if (ntp->status == IGNORE) { 119 lookformaster(ntp); 120 if (ntp->status == MASTER) 121 masterup(ntp); 122 else 123 ntp->status = IGNORE; 124 } 125 } 126 setstatus(); 127 #ifdef MEASURE 128 /* 129 * Check to see if we just became master 130 * (file not open) 131 */ 132 if (fp == NULL) { 133 fp = fopen(_PATH_MASTERLOG, "w"); 134 setlinebuf(fp); 135 } 136 #endif 137 } 138 139 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 140 if (ntp->status == MASTER) { 141 to.tsp_type = TSP_LOOP; 142 to.tsp_vers = TSPVERSION; 143 to.tsp_seq = sequence++; 144 to.tsp_hopcnt = 10; 145 (void)strcpy(to.tsp_name, hostname); 146 bytenetorder(&to); 147 if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, 148 &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) { 149 syslog(LOG_ERR, "sendto: %m"); 150 exit(1); 151 } 152 } 153 } 154 (void)gettimeofday(&time, (struct timezone *)0); 155 looktime = time.tv_sec + delay2; 156 } 157 wait.tv_sec = electiontime - time.tv_sec + 10; 158 wait.tv_usec = 0; 159 msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL); 160 if (msg != NULL) { 161 switch (msg->tsp_type) { 162 case TSP_SETDATE: 163 #ifdef TESTING 164 case TSP_TEST: 165 #endif 166 case TSP_MSITE: 167 case TSP_TRACEOFF: 168 case TSP_TRACEON: 169 break; 170 case TSP_MASTERUP: 171 if (fromnet == NULL) { 172 if (trace) { 173 fprintf(fd, "slave ignored: "); 174 print(msg, &from); 175 } 176 goto loop; 177 } 178 break; 179 default: 180 if (fromnet == NULL || fromnet->status == IGNORE) { 181 if (trace) { 182 fprintf(fd, "slave ignored: "); 183 print(msg, &from); 184 } 185 goto loop; 186 } 187 break; 188 } 189 190 switch (msg->tsp_type) { 191 192 case TSP_ADJTIME: 193 if (fromnet->status != SLAVE) 194 break; 195 (void)gettimeofday(&time, (struct timezone *)0); 196 electiontime = time.tv_sec + delay2; 197 if (seq != msg->tsp_seq) { 198 seq = msg->tsp_seq; 199 if ((status & SUBMASTER) == SUBMASTER) { 200 synch((msg->tsp_time.tv_sec * 1000) + 201 (msg->tsp_time.tv_usec / 1000)); 202 } else { 203 adjclock(&(msg->tsp_time)); 204 } 205 } 206 break; 207 case TSP_SETTIME: 208 if (fromnet->status != SLAVE) 209 break; 210 if (seq == msg->tsp_seq) 211 break; 212 213 seq = msg->tsp_seq; 214 215 (void)strcpy(olddate, date()); 216 logwtmp("|", "date", ""); 217 (void)settimeofday(&msg->tsp_time, 218 (struct timezone *)0); 219 logwtmp("{", "date", ""); 220 syslog(LOG_NOTICE, "date changed by %s from: %s", 221 msg->tsp_name, olddate); 222 if ((status & SUBMASTER) == SUBMASTER) 223 spreadtime(); 224 (void)gettimeofday(&time, (struct timezone *)0); 225 electiontime = time.tv_sec + delay2; 226 227 if (senddateack == ON) { 228 senddateack = OFF; 229 msg->tsp_type = TSP_DATEACK; 230 (void)strcpy(msg->tsp_name, hostname); 231 bytenetorder(msg); 232 length = sizeof(struct sockaddr_in); 233 if (sendto(sock, (char *)msg, 234 sizeof(struct tsp), 0, 235 &saveaddr, length) < 0) { 236 syslog(LOG_ERR, "sendto: %m"); 237 exit(1); 238 } 239 } 240 break; 241 case TSP_MASTERUP: 242 if (slavenet && fromnet != slavenet) 243 break; 244 makeslave(fromnet); 245 setstatus(); 246 msg->tsp_type = TSP_SLAVEUP; 247 msg->tsp_vers = TSPVERSION; 248 (void)strcpy(msg->tsp_name, hostname); 249 bytenetorder(msg); 250 answerdelay(); 251 length = sizeof(struct sockaddr_in); 252 if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, 253 &from, length) < 0) { 254 syslog(LOG_ERR, "sendto: %m"); 255 exit(1); 256 } 257 backoff = 1; 258 delay2 = casual((long)MINTOUT, (long)MAXTOUT); 259 (void)gettimeofday(&time, (struct timezone *)0); 260 electiontime = time.tv_sec + delay2; 261 refusetime = 0; 262 break; 263 case TSP_MASTERREQ: 264 if (fromnet->status != SLAVE) 265 break; 266 (void)gettimeofday(&time, (struct timezone *)0); 267 electiontime = time.tv_sec + delay2; 268 break; 269 case TSP_SETDATE: 270 saveaddr = from; 271 msg->tsp_type = TSP_SETDATEREQ; 272 msg->tsp_vers = TSPVERSION; 273 (void)strcpy(msg->tsp_name, hostname); 274 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 275 if (ntp->status == SLAVE) 276 break; 277 } 278 if (ntp == NULL) 279 break; 280 answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR, 281 TSP_DATEACK, ntp); 282 if (answer != NULL) { 283 msg->tsp_type = TSP_ACK; 284 bytenetorder(msg); 285 length = sizeof(struct sockaddr_in); 286 if (sendto(sock, (char *)msg, 287 sizeof(struct tsp), 0, &saveaddr, 288 length) < 0) { 289 syslog(LOG_ERR, "sendto: %m"); 290 exit(1); 291 } 292 senddateack = ON; 293 } 294 break; 295 case TSP_SETDATEREQ: 296 saveaddr = from; 297 if (status != SUBMASTER || fromnet->status != MASTER) 298 break; 299 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 300 if (ntp->status == SLAVE) 301 break; 302 } 303 ind = findhost(msg->tsp_name); 304 if (ind < 0) { 305 syslog(LOG_WARNING, 306 "DATEREQ from uncontrolled machine"); 307 break; 308 } 309 syslog(LOG_DEBUG, 310 "forwarding date change request for %s", 311 msg->tsp_name); 312 (void)strcpy(msg->tsp_name, hostname); 313 answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR, 314 TSP_DATEACK, ntp); 315 if (answer != NULL) { 316 msg->tsp_type = TSP_DATEACK; 317 bytenetorder(msg); 318 length = sizeof(struct sockaddr_in); 319 if (sendto(sock, (char *)msg, 320 sizeof(struct tsp), 0, &saveaddr, 321 length) < 0) { 322 syslog(LOG_ERR, "sendto: %m"); 323 exit(1); 324 } 325 } 326 break; 327 case TSP_TRACEON: 328 if (!(trace)) { 329 fd = fopen(tracefile, "w"); 330 setlinebuf(fd); 331 fprintf(fd, "Tracing started on: %s\n\n", 332 date()); 333 } 334 trace = ON; 335 break; 336 case TSP_TRACEOFF: 337 if (trace) { 338 fprintf(fd, "Tracing ended on: %s\n", date()); 339 (void)fclose(fd); 340 } 341 #ifdef GPROF 342 moncontrol(0); 343 _mcleanup(); 344 moncontrol(1); 345 #endif 346 trace = OFF; 347 break; 348 case TSP_SLAVEUP: 349 if ((status & MASTER) && fromnet->status == MASTER) { 350 ind = addmach(msg->tsp_name, &from); 351 newslave(ind, msg->tsp_seq); 352 } 353 break; 354 case TSP_ELECTION: 355 if (fromnet->status == SLAVE) { 356 (void)gettimeofday(&time, (struct timezone *)0); 357 electiontime = time.tv_sec + delay2; 358 seq = 0; /* reset sequence number */ 359 if (time.tv_sec < refusetime) 360 msg->tsp_type = TSP_REFUSE; 361 else { 362 msg->tsp_type = TSP_ACCEPT; 363 refusetime = time.tv_sec + 30; 364 } 365 (void)strcpy(candidate, msg->tsp_name); 366 (void)strcpy(msg->tsp_name, hostname); 367 answerdelay(); 368 server = from; 369 answer = acksend(msg, &server, candidate, TSP_ACK, 370 (struct netinfo *)NULL); 371 if (answer == NULL) 372 syslog(LOG_WARNING, 373 "no answer from master candidate\n"); 374 } else { /* fromnet->status == MASTER */ 375 to.tsp_type = TSP_QUIT; 376 (void)strcpy(to.tsp_name, hostname); 377 server = from; 378 answer = acksend(&to, &server, msg->tsp_name, 379 TSP_ACK, (struct netinfo *)NULL); 380 if (answer == NULL) { 381 syslog(LOG_WARNING, 382 "election error: no reply to QUIT"); 383 } else { 384 (void) addmach(msg->tsp_name, &from); 385 } 386 } 387 break; 388 case TSP_CONFLICT: 389 if (fromnet->status != MASTER) 390 break; 391 /* 392 * After a network partition, there can be 393 * more than one master: the first slave to 394 * come up will notify here the situation. 395 */ 396 (void)strcpy(to.tsp_name, hostname); 397 398 if (fromnet == NULL) 399 break; 400 for(;;) { 401 to.tsp_type = TSP_RESOLVE; 402 answer = acksend(&to, &fromnet->dest_addr, 403 (char *)ANYADDR, TSP_MASTERACK, fromnet); 404 if (answer == NULL) 405 break; 406 to.tsp_type = TSP_QUIT; 407 server = from; 408 msg = acksend(&to, &server, answer->tsp_name, 409 TSP_ACK, (struct netinfo *)NULL); 410 if (msg == NULL) { 411 syslog(LOG_WARNING, 412 "conflict error: no reply to QUIT"); 413 } else { 414 (void) addmach(answer->tsp_name, &from); 415 } 416 } 417 masterup(fromnet); 418 break; 419 case TSP_MSITE: 420 if (!slavenet) 421 break; 422 msaveaddr = from; 423 msg->tsp_type = TSP_MSITEREQ; 424 msg->tsp_vers = TSPVERSION; 425 (void)strcpy(msg->tsp_name, hostname); 426 answer = acksend(msg, &slavenet->dest_addr, 427 (char *)ANYADDR, TSP_ACK, slavenet); 428 if (answer != NULL) { 429 msg->tsp_type = TSP_ACK; 430 length = sizeof(struct sockaddr_in); 431 bytenetorder(msg); 432 if (sendto(sock, (char *)msg, 433 sizeof(struct tsp), 0, 434 &msaveaddr, length) < 0) { 435 syslog(LOG_ERR, "sendto: %m"); 436 exit(1); 437 } 438 } 439 break; 440 case TSP_ACCEPT: 441 case TSP_REFUSE: 442 break; 443 case TSP_RESOLVE: 444 break; 445 case TSP_QUIT: 446 /* become slave */ 447 #ifdef MEASURE 448 if (fp != NULL) { 449 (void)fclose(fp); 450 fp = NULL; 451 } 452 #endif 453 longjmp(jmpenv, 2); 454 break; 455 #ifdef TESTING 456 case TSP_TEST: 457 electiontime = 0; 458 break; 459 #endif 460 case TSP_MSITEREQ: 461 if (status & MASTER) 462 break; 463 if (trace) { 464 fprintf(fd, "garbage: "); 465 print(msg, &from); 466 } 467 break; 468 469 case TSP_LOOP: 470 /* looking for loops of masters */ 471 if ( !(status & MASTER)) 472 break; 473 if (fromnet->status == SLAVE) { 474 if ( !strcmp(msg->tsp_name, hostname)) { 475 for(;;) { 476 to.tsp_type = TSP_RESOLVE; 477 answer = acksend(&to, &fromnet->dest_addr, 478 (char *)ANYADDR, TSP_MASTERACK, 479 fromnet); 480 if (answer == NULL) 481 break; 482 to.tsp_type = TSP_QUIT; 483 (void)strcpy(to.tsp_name, hostname); 484 server = from; 485 answer = acksend(&to, &server, 486 answer->tsp_name, TSP_ACK, 487 (struct netinfo *)NULL); 488 if (answer == NULL) { 489 syslog(LOG_ERR, "loop kill error"); 490 } else { 491 electiontime = 0; 492 } 493 } 494 } else { 495 if (msg->tsp_hopcnt-- <= 0) 496 break; 497 bytenetorder(msg); 498 ntp = nettab; 499 for (; ntp != NULL; ntp = ntp->next) 500 if (ntp->status == MASTER) 501 if (sendto(sock, (char *)msg, 502 sizeof(struct tsp), 0, 503 &ntp->dest_addr, length) < 0) { 504 syslog(LOG_ERR, "sendto: %m"); 505 exit(1); 506 } 507 } 508 } else { 509 /* 510 * We should not have received this from a net 511 * we are master on. There must be two masters 512 * in this case. 513 */ 514 if (fromnet->my_addr.s_addr == from.sin_addr.s_addr) 515 break; 516 for (;;) { 517 to.tsp_type = TSP_RESOLVE; 518 answer = acksend(&to, &fromnet->dest_addr, 519 (char *)ANYADDR, TSP_MASTERACK, 520 fromnet); 521 if (answer == NULL) 522 break; 523 to.tsp_type = TSP_QUIT; 524 (void)strcpy(to.tsp_name, hostname); 525 server = from; 526 answer = acksend(&to, &server, answer->tsp_name, 527 TSP_ACK, (struct netinfo *)NULL); 528 if (answer == NULL) { 529 syslog(LOG_ERR, "loop kill error2"); 530 } else { 531 (void)addmach(msg->tsp_name, &from); 532 } 533 } 534 } 535 break; 536 default: 537 if (trace) { 538 fprintf(fd, "garbage: "); 539 print(msg, &from); 540 } 541 break; 542 } 543 } 544 goto loop; 545 } 546 547 /* 548 * Used before answering a broadcast message to avoid network 549 * contention and likely collisions. 550 */ 551 answerdelay() 552 { 553 struct timeval timeout; 554 555 timeout.tv_sec = 0; 556 timeout.tv_usec = delay1; 557 558 (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, 559 &timeout); 560 return; 561 } 562