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