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