slave.c revision 30642
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1985, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3530642Scharnier#if 0 361553Srgrimesstatic char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93"; 3730642Scharnier#endif 3830642Scharnierstatic const char rcsid[] = 3930642Scharnier "$Id$"; 401553Srgrimes#endif /* not lint */ 411553Srgrimes 421553Srgrimes#include "globals.h" 431553Srgrimes#include <setjmp.h> 441553Srgrimes#include "pathnames.h" 451553Srgrimes 461553Srgrimesextern jmp_buf jmpenv; 471553Srgrimesextern int Mflag; 481553Srgrimesextern int justquit; 491553Srgrimes 501553Srgrimesextern u_short sequence; 511553Srgrimes 521553Srgrimesstatic char master_name[MAXHOSTNAMELEN+1]; 531553Srgrimesstatic struct netinfo *old_slavenet; 541553Srgrimesstatic int old_status; 551553Srgrimes 561553Srgrimesstatic void schgdate __P((struct tsp *, char *)); 571553Srgrimesstatic void setmaster __P((struct tsp *)); 581553Srgrimesstatic void answerdelay __P((void)); 591553Srgrimes 601553Srgrimes#ifdef sgi 611553Srgrimesextern void logwtmp __P((struct timeval *, struct timeval *)); 621553Srgrimes#else 631553Srgrimesextern void logwtmp __P((char *, char *, char *)); 641553Srgrimes#endif /* sgi */ 651553Srgrimes 661553Srgrimesint 671553Srgrimesslave() 681553Srgrimes{ 691553Srgrimes int tries; 701553Srgrimes long electiontime, refusetime, looktime, looptime, adjtime; 711553Srgrimes u_short seq; 721553Srgrimes long fastelection; 731553Srgrimes#define FASTTOUT 3 741553Srgrimes struct in_addr cadr; 751553Srgrimes struct timeval otime; 761553Srgrimes struct sockaddr_in taddr; 771553Srgrimes char tname[MAXHOSTNAMELEN]; 781553Srgrimes struct tsp *msg, to; 791553Srgrimes struct timeval ntime, wait; 801553Srgrimes struct tsp *answer; 811553Srgrimes int timeout(); 821553Srgrimes char olddate[32]; 831553Srgrimes char newdate[32]; 841553Srgrimes struct netinfo *ntp; 851553Srgrimes struct hosttbl *htp; 861553Srgrimes 871553Srgrimes 881553Srgrimes old_slavenet = 0; 891553Srgrimes seq = 0; 901553Srgrimes refusetime = 0; 911553Srgrimes adjtime = 0; 921553Srgrimes 931553Srgrimes (void)gettimeofday(&ntime, 0); 941553Srgrimes electiontime = ntime.tv_sec + delay2; 951553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 961553Srgrimes if (justquit) 971553Srgrimes looktime = electiontime; 981553Srgrimes else 991553Srgrimes looktime = fastelection; 1001553Srgrimes looptime = fastelection; 1011553Srgrimes 1021553Srgrimes if (slavenet) 1031553Srgrimes xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr); 1041553Srgrimes if (status & MASTER) { 1051553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1061553Srgrimes if (ntp->status == MASTER) 1071553Srgrimes masterup(ntp); 1081553Srgrimes } 1091553Srgrimes } 1101553Srgrimes 1111553Srgrimesloop: 1121553Srgrimes get_goodgroup(0); 1131553Srgrimes (void)gettimeofday(&ntime, (struct timezone *)0); 1141553Srgrimes if (ntime.tv_sec > electiontime) { 1151553Srgrimes if (trace) 1161553Srgrimes fprintf(fd, "election timer expired\n"); 1171553Srgrimes longjmp(jmpenv, 1); 1181553Srgrimes } 1191553Srgrimes 1201553Srgrimes if (ntime.tv_sec >= looktime) { 1211553Srgrimes if (trace) 1221553Srgrimes fprintf(fd, "Looking for nets to master\n"); 1231553Srgrimes 1241553Srgrimes if (Mflag && nignorednets > 0) { 1251553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1261553Srgrimes if (ntp->status == IGNORE 1271553Srgrimes || ntp->status == NOMASTER) { 1281553Srgrimes lookformaster(ntp); 1291553Srgrimes if (ntp->status == MASTER) { 1301553Srgrimes masterup(ntp); 1311553Srgrimes } else if (ntp->status == MASTER) { 1321553Srgrimes ntp->status = NOMASTER; 1331553Srgrimes } 1341553Srgrimes } 1351553Srgrimes if (ntp->status == MASTER 1361553Srgrimes && --ntp->quit_count < 0) 1371553Srgrimes ntp->quit_count = 0; 1381553Srgrimes } 1391553Srgrimes makeslave(slavenet); /* prune extras */ 1401553Srgrimes setstatus(); 1411553Srgrimes } 1421553Srgrimes (void)gettimeofday(&ntime, 0); 1431553Srgrimes looktime = ntime.tv_sec + delay2; 1441553Srgrimes } 1451553Srgrimes if (ntime.tv_sec >= looptime) { 1461553Srgrimes if (trace) 1471553Srgrimes fprintf(fd, "Looking for loops\n"); 1481553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1491553Srgrimes if (ntp->status == MASTER) { 1501553Srgrimes to.tsp_type = TSP_LOOP; 1511553Srgrimes to.tsp_vers = TSPVERSION; 1521553Srgrimes to.tsp_seq = sequence++; 1531553Srgrimes to.tsp_hopcnt = MAX_HOPCNT; 15430642Scharnier (void)strncpy(to.tsp_name, hostname, 15530642Scharnier sizeof to.tsp_name-1); 15630642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 1571553Srgrimes bytenetorder(&to); 1581553Srgrimes if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, 1591553Srgrimes (struct sockaddr*)&ntp->dest_addr, 1601553Srgrimes sizeof(ntp->dest_addr)) < 0) { 1611553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 1621553Srgrimes } 1631553Srgrimes } 1641553Srgrimes } 1651553Srgrimes (void)gettimeofday(&ntime, 0); 1661553Srgrimes looptime = ntime.tv_sec + delay2; 1671553Srgrimes } 1681553Srgrimes 1691553Srgrimes wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec; 1701553Srgrimes if (wait.tv_sec < 0) 1711553Srgrimes wait.tv_sec = 0; 1721553Srgrimes wait.tv_sec += FASTTOUT; 1731553Srgrimes wait.tv_usec = 0; 1741553Srgrimes msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 1751553Srgrimes 1761553Srgrimes if (msg != NULL) { 1771553Srgrimes /* 1781553Srgrimes * filter stuff not for us 1791553Srgrimes */ 1801553Srgrimes switch (msg->tsp_type) { 1811553Srgrimes case TSP_SETDATE: 1821553Srgrimes case TSP_TRACEOFF: 1831553Srgrimes case TSP_TRACEON: 1841553Srgrimes /* 1851553Srgrimes * XXX check to see they are from ourself 1861553Srgrimes */ 1871553Srgrimes break; 1881553Srgrimes 1891553Srgrimes case TSP_TEST: 1901553Srgrimes case TSP_MSITE: 1911553Srgrimes break; 1921553Srgrimes 1931553Srgrimes case TSP_MASTERUP: 1941553Srgrimes if (!fromnet) { 1951553Srgrimes if (trace) { 1961553Srgrimes fprintf(fd, "slave ignored: "); 1971553Srgrimes print(msg, &from); 1981553Srgrimes } 1991553Srgrimes goto loop; 2001553Srgrimes } 2011553Srgrimes break; 2021553Srgrimes 2031553Srgrimes default: 2041553Srgrimes if (!fromnet 2051553Srgrimes || fromnet->status == IGNORE 2061553Srgrimes || fromnet->status == NOMASTER) { 2071553Srgrimes if (trace) { 2081553Srgrimes fprintf(fd, "slave ignored: "); 2091553Srgrimes print(msg, &from); 2101553Srgrimes } 2111553Srgrimes goto loop; 2121553Srgrimes } 2131553Srgrimes break; 2141553Srgrimes } 2151553Srgrimes 2161553Srgrimes 2171553Srgrimes /* 2181553Srgrimes * now process the message 2191553Srgrimes */ 2201553Srgrimes switch (msg->tsp_type) { 2211553Srgrimes 2221553Srgrimes case TSP_ADJTIME: 2231553Srgrimes if (fromnet != slavenet) 2241553Srgrimes break; 2251553Srgrimes if (!good_host_name(msg->tsp_name)) { 2261553Srgrimes syslog(LOG_NOTICE, 2271553Srgrimes "attempted time adjustment by %s", 2281553Srgrimes msg->tsp_name); 2291553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2301553Srgrimes break; 2311553Srgrimes } 2321553Srgrimes /* 2331553Srgrimes * Speed up loop detection in case we have a loop. 2341553Srgrimes * Otherwise the clocks can race until the loop 2351553Srgrimes * is found. 2361553Srgrimes */ 2371553Srgrimes (void)gettimeofday(&otime, 0); 2381553Srgrimes if (adjtime < otime.tv_sec) 2391553Srgrimes looptime -= (looptime-otime.tv_sec)/2 + 1; 2401553Srgrimes 2411553Srgrimes setmaster(msg); 2421553Srgrimes if (seq != msg->tsp_seq) { 2431553Srgrimes seq = msg->tsp_seq; 2441553Srgrimes synch(tvtomsround(msg->tsp_time)); 2451553Srgrimes } 2461553Srgrimes (void)gettimeofday(&ntime, 0); 2471553Srgrimes electiontime = ntime.tv_sec + delay2; 2481553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 2491553Srgrimes adjtime = ntime.tv_sec + SAMPLEINTVL*2; 2501553Srgrimes break; 2511553Srgrimes 2521553Srgrimes case TSP_SETTIME: 2531553Srgrimes if (fromnet != slavenet) 2541553Srgrimes break; 2551553Srgrimes if (seq == msg->tsp_seq) 2561553Srgrimes break; 2571553Srgrimes seq = msg->tsp_seq; 2581553Srgrimes 2591553Srgrimes /* adjust time for residence on the queue */ 2601553Srgrimes (void)gettimeofday(&otime, 0); 2611553Srgrimes adj_msg_time(msg,&otime); 2621553Srgrimes#ifdef sgi 2631553Srgrimes (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); 2641553Srgrimes (void)cftime(olddate, "%D %T", &otime.tv_sec); 2651553Srgrimes#else 2661553Srgrimes /* 2671553Srgrimes * the following line is necessary due to syslog 2681553Srgrimes * calling ctime() which clobbers the static buffer 2691553Srgrimes */ 27030642Scharnier (void)strncpy(olddate, date(), sizeof olddate-1); 27130642Scharnier olddate[sizeof olddate-1] = '\0'; 27230642Scharnier (void)strncpy(newdate, ctime(&msg->tsp_time.tv_sec), 27330642Scharnier sizeof newdate-1); 27430642Scharnier newdate[sizeof newdate-1] = '\0'; 2751553Srgrimes#endif /* sgi */ 2761553Srgrimes 2771553Srgrimes if (!good_host_name(msg->tsp_name)) { 2781553Srgrimes syslog(LOG_NOTICE, 2791553Srgrimes "attempted time setting by untrusted %s to %s", 2801553Srgrimes msg->tsp_name, newdate); 2811553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2821553Srgrimes break; 2831553Srgrimes } 2841553Srgrimes 2851553Srgrimes setmaster(msg); 2861553Srgrimes timevalsub(&ntime, &msg->tsp_time, &otime); 2871553Srgrimes if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 2881553Srgrimes /* 2891553Srgrimes * do not change the clock if we can adjust it 2901553Srgrimes */ 2911553Srgrimes synch(tvtomsround(ntime)); 2921553Srgrimes } else { 2931553Srgrimes#ifdef sgi 2941553Srgrimes if (0 > settimeofday(&msg->tsp_time, 0)) { 2951553Srgrimes syslog(LOG_ERR,"settimeofdate(): %m"); 2961553Srgrimes break; 2971553Srgrimes } 2981553Srgrimes logwtmp(&otime, &msg->tsp_time); 2991553Srgrimes#else 3001553Srgrimes logwtmp("|", "date", ""); 3011553Srgrimes (void)settimeofday(&msg->tsp_time, 0); 30219093Sscrappy logwtmp("{", "date", ""); 3031553Srgrimes#endif /* sgi */ 3041553Srgrimes syslog(LOG_NOTICE, 3051553Srgrimes "date changed by %s from %s", 3061553Srgrimes msg->tsp_name, olddate); 3071553Srgrimes if (status & MASTER) 3081553Srgrimes spreadtime(); 3091553Srgrimes } 3101553Srgrimes (void)gettimeofday(&ntime, 0); 3111553Srgrimes electiontime = ntime.tv_sec + delay2; 3121553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3131553Srgrimes 3141553Srgrimes/* This patches a bad protocol bug. Imagine a system with several networks, 3151553Srgrimes * where there are a pair of redundant gateways between a pair of networks, 3161553Srgrimes * each running timed. Assume that we start with a third machine mastering 3171553Srgrimes * one of the networks, and one of the gateways mastering the other. 3181553Srgrimes * Imagine that the third machine goes away and the non-master gateway 3191553Srgrimes * decides to replace it. If things are timed just 'right,' we will have 3201553Srgrimes * each gateway mastering one network for a little while. If a SETTIME 3211553Srgrimes * message gets into the network at that time, perhaps from the newly 3221553Srgrimes * masterful gateway as it was taking control, the SETTIME will loop 3231553Srgrimes * forever. Each time a gateway receives it on its slave side, it will 3241553Srgrimes * call spreadtime to forward it on its mastered network. We are now in 3251553Srgrimes * a permanent loop, since the SETTIME msgs will keep any clock 3261553Srgrimes * in the network from advancing. Normally, the 'LOOP' stuff will detect 3271553Srgrimes * and correct the situation. However, with the clocks stopped, the 3281553Srgrimes * 'looptime' timer cannot expire. While they are in this state, the 3291553Srgrimes * masters will try to saturate the network with SETTIME packets. 3301553Srgrimes */ 3311553Srgrimes looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1; 3321553Srgrimes break; 3331553Srgrimes 3341553Srgrimes case TSP_MASTERUP: 3351553Srgrimes if (slavenet && fromnet != slavenet) 3361553Srgrimes break; 3371553Srgrimes if (!good_host_name(msg->tsp_name)) { 3381553Srgrimes suppress(&from, msg->tsp_name, fromnet); 3391553Srgrimes if (electiontime > fastelection) 3401553Srgrimes electiontime = fastelection; 3411553Srgrimes break; 3421553Srgrimes } 3431553Srgrimes makeslave(fromnet); 3441553Srgrimes setmaster(msg); 3451553Srgrimes setstatus(); 3461553Srgrimes answerdelay(); 3471553Srgrimes xmit(TSP_SLAVEUP, 0, &from); 3481553Srgrimes (void)gettimeofday(&ntime, 0); 3491553Srgrimes electiontime = ntime.tv_sec + delay2; 3501553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3511553Srgrimes refusetime = 0; 3521553Srgrimes break; 3531553Srgrimes 3541553Srgrimes case TSP_MASTERREQ: 3551553Srgrimes if (fromnet->status != SLAVE) 3561553Srgrimes break; 3571553Srgrimes (void)gettimeofday(&ntime, 0); 3581553Srgrimes electiontime = ntime.tv_sec + delay2; 3591553Srgrimes break; 3601553Srgrimes 3611553Srgrimes case TSP_SETDATE: 3621553Srgrimes#ifdef sgi 3631553Srgrimes (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); 3641553Srgrimes#else 36530642Scharnier (void)strncpy(newdate, ctime(&msg->tsp_time.tv_sec), 36630642Scharnier sizeof newdate-1); 36730642Scharnier newdate[sizeof newdate-1] = '\0'; 3681553Srgrimes#endif /* sgi */ 3691553Srgrimes schgdate(msg, newdate); 3701553Srgrimes break; 3711553Srgrimes 3721553Srgrimes case TSP_SETDATEREQ: 3731553Srgrimes if (fromnet->status != MASTER) 3741553Srgrimes break; 3751553Srgrimes#ifdef sgi 3761553Srgrimes (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); 3771553Srgrimes#else 37830642Scharnier (void)strncpy(newdate, ctime(&msg->tsp_time.tv_sec), 37930642Scharnier sizeof newdate-1); 38030642Scharnier newdate[sizeof newdate-1] = '\0'; 3811553Srgrimes#endif /* sgi */ 3821553Srgrimes htp = findhost(msg->tsp_name); 3831553Srgrimes if (0 == htp) { 3841553Srgrimes syslog(LOG_WARNING, 3851553Srgrimes "DATEREQ from uncontrolled machine"); 3861553Srgrimes break; 3871553Srgrimes } 3881553Srgrimes if (!htp->good) { 3891553Srgrimes syslog(LOG_WARNING, 3901553Srgrimes "attempted date change by untrusted %s to %s", 3911553Srgrimes htp->name, newdate); 3921553Srgrimes spreadtime(); 3931553Srgrimes break; 3941553Srgrimes } 3951553Srgrimes schgdate(msg, newdate); 3961553Srgrimes break; 3971553Srgrimes 3981553Srgrimes case TSP_TRACEON: 3991553Srgrimes traceon(); 4001553Srgrimes break; 4011553Srgrimes 4021553Srgrimes case TSP_TRACEOFF: 4031553Srgrimes traceoff("Tracing ended at %s\n"); 4041553Srgrimes break; 4051553Srgrimes 4061553Srgrimes case TSP_SLAVEUP: 4071553Srgrimes newslave(msg); 4081553Srgrimes break; 4091553Srgrimes 4101553Srgrimes case TSP_ELECTION: 4111553Srgrimes if (fromnet->status == SLAVE) { 4121553Srgrimes (void)gettimeofday(&ntime, 0); 4131553Srgrimes electiontime = ntime.tv_sec + delay2; 4141553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 4151553Srgrimes seq = 0; 4161553Srgrimes if (!good_host_name(msg->tsp_name)) { 4171553Srgrimes syslog(LOG_NOTICE, 4181553Srgrimes "suppress election of %s", 4191553Srgrimes msg->tsp_name); 4201553Srgrimes to.tsp_type = TSP_QUIT; 4211553Srgrimes electiontime = fastelection; 4221553Srgrimes } else if (cadr.s_addr != from.sin_addr.s_addr 4231553Srgrimes && ntime.tv_sec < refusetime) { 4241553Srgrimes/* if the candidate has to repeat itself, the old code would refuse it 4251553Srgrimes * the second time. That would prevent elections. 4261553Srgrimes */ 4271553Srgrimes to.tsp_type = TSP_REFUSE; 4281553Srgrimes } else { 4291553Srgrimes cadr.s_addr = from.sin_addr.s_addr; 4301553Srgrimes to.tsp_type = TSP_ACCEPT; 4311553Srgrimes refusetime = ntime.tv_sec + 30; 4321553Srgrimes } 4331553Srgrimes taddr = from; 43430642Scharnier (void)strncpy(tname, msg->tsp_name, 43530642Scharnier sizeof tname-1); 43630642Scharnier tname[sizeof tname-1] = '\0'; 43730642Scharnier (void)strncpy(to.tsp_name, hostname, 43830642Scharnier sizeof to.tsp_name-1); 43930642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 4401553Srgrimes answerdelay(); 4411553Srgrimes if (!acksend(&to, &taddr, tname, 4421553Srgrimes TSP_ACK, 0, 0)) 4431553Srgrimes syslog(LOG_WARNING, 4441553Srgrimes "no answer from candidate %s\n", 4451553Srgrimes tname); 4461553Srgrimes 4471553Srgrimes } else { /* fromnet->status == MASTER */ 4481553Srgrimes htp = addmach(msg->tsp_name, &from,fromnet); 4491553Srgrimes to.tsp_type = TSP_QUIT; 45030642Scharnier (void)strncpy(to.tsp_name, hostname, 45130642Scharnier sizeof to.tsp_name-1); 45230642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 4531553Srgrimes if (!acksend(&to, &htp->addr, htp->name, 4541553Srgrimes TSP_ACK, 0, htp->noanswer)) { 4551553Srgrimes syslog(LOG_ERR, 4561553Srgrimes "no reply from %s to ELECTION-QUIT", 4571553Srgrimes htp->name); 4581553Srgrimes (void)remmach(htp); 4591553Srgrimes } 4601553Srgrimes } 4611553Srgrimes break; 4621553Srgrimes 4631553Srgrimes case TSP_CONFLICT: 4641553Srgrimes if (fromnet->status != MASTER) 4651553Srgrimes break; 4661553Srgrimes /* 4671553Srgrimes * After a network partition, there can be 4681553Srgrimes * more than one master: the first slave to 4691553Srgrimes * come up will notify here the situation. 4701553Srgrimes */ 47130642Scharnier (void)strncpy(to.tsp_name, hostname, 47230642Scharnier sizeof to.tsp_name-1); 47330642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 4741553Srgrimes 4751553Srgrimes /* The other master often gets into the same state, 4761553Srgrimes * with boring results. 4771553Srgrimes */ 4781553Srgrimes ntp = fromnet; /* (acksend() can leave fromnet=0 */ 4791553Srgrimes for (tries = 0; tries < 3; tries++) { 4801553Srgrimes to.tsp_type = TSP_RESOLVE; 4811553Srgrimes answer = acksend(&to, &ntp->dest_addr, 4821553Srgrimes ANYADDR, TSP_MASTERACK, 4831553Srgrimes ntp, 0); 4841553Srgrimes if (answer == NULL) 4851553Srgrimes break; 4861553Srgrimes htp = addmach(answer->tsp_name,&from,ntp); 4871553Srgrimes to.tsp_type = TSP_QUIT; 4881553Srgrimes answer = acksend(&to, &htp->addr, htp->name, 4891553Srgrimes TSP_ACK, 0, htp->noanswer); 4901553Srgrimes if (!answer) { 4911553Srgrimes syslog(LOG_WARNING, 4921553Srgrimes "conflict error: no reply from %s to QUIT", 4931553Srgrimes htp->name); 4941553Srgrimes (void)remmach(htp); 4951553Srgrimes } 4961553Srgrimes } 4971553Srgrimes masterup(ntp); 4981553Srgrimes break; 4991553Srgrimes 5001553Srgrimes case TSP_MSITE: 5011553Srgrimes if (!slavenet) 5021553Srgrimes break; 5031553Srgrimes taddr = from; 5041553Srgrimes to.tsp_type = TSP_MSITEREQ; 5051553Srgrimes to.tsp_vers = TSPVERSION; 5061553Srgrimes to.tsp_seq = 0; 50730642Scharnier (void)strncpy(to.tsp_name, hostname, 50830642Scharnier sizeof to.tsp_name-1); 50930642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 5101553Srgrimes answer = acksend(&to, &slavenet->dest_addr, 5111553Srgrimes ANYADDR, TSP_ACK, 5121553Srgrimes slavenet, 0); 5131553Srgrimes if (answer != NULL 5141553Srgrimes && good_host_name(answer->tsp_name)) { 5151553Srgrimes setmaster(answer); 5161553Srgrimes to.tsp_type = TSP_ACK; 51730642Scharnier (void)strncpy(to.tsp_name, answer->tsp_name, 51830642Scharnier sizeof to.tsp_name-1); 51930642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 5201553Srgrimes bytenetorder(&to); 5211553Srgrimes if (sendto(sock, (char *)&to, 5221553Srgrimes sizeof(struct tsp), 0, 52330642Scharnier (struct sockaddr*)&taddr, 52430642Scharnier sizeof(taddr)) < 0) { 5251553Srgrimes trace_sendto_err(taddr.sin_addr); 5261553Srgrimes } 5271553Srgrimes } 5281553Srgrimes break; 5291553Srgrimes 5301553Srgrimes case TSP_MSITEREQ: 5311553Srgrimes break; 5321553Srgrimes 5331553Srgrimes case TSP_ACCEPT: 5341553Srgrimes case TSP_REFUSE: 5351553Srgrimes case TSP_RESOLVE: 5361553Srgrimes break; 5371553Srgrimes 5381553Srgrimes case TSP_QUIT: 5391553Srgrimes doquit(msg); /* become a slave */ 5401553Srgrimes break; 5411553Srgrimes 5421553Srgrimes case TSP_TEST: 5431553Srgrimes electiontime = 0; 5441553Srgrimes break; 5451553Srgrimes 5461553Srgrimes case TSP_LOOP: 5471553Srgrimes /* looking for loops of masters */ 5481553Srgrimes if (!(status & MASTER)) 5491553Srgrimes break; 5501553Srgrimes if (fromnet->status == SLAVE) { 5511553Srgrimes if (!strcmp(msg->tsp_name, hostname)) { 5521553Srgrimes /* 5531553Srgrimes * Someone forwarded our message back to 5541553Srgrimes * us. There must be a loop. Tell the 5551553Srgrimes * master of this network to quit. 5561553Srgrimes * 5571553Srgrimes * The other master often gets into 5581553Srgrimes * the same state, with boring results. 5591553Srgrimes */ 5601553Srgrimes ntp = fromnet; 5611553Srgrimes for (tries = 0; tries < 3; tries++) { 5621553Srgrimes to.tsp_type = TSP_RESOLVE; 5631553Srgrimes answer = acksend(&to, &ntp->dest_addr, 5641553Srgrimes ANYADDR, TSP_MASTERACK, 5651553Srgrimes ntp,0); 5661553Srgrimes if (answer == NULL) 5671553Srgrimes break; 5681553Srgrimes taddr = from; 56930642Scharnier (void)strncpy(tname, answer->tsp_name, 57030642Scharnier sizeof tname-1); 57130642Scharnier tname[sizeof tname-1] = '\0'; 5721553Srgrimes to.tsp_type = TSP_QUIT; 57330642Scharnier (void)strncpy(to.tsp_name, hostname, 57430642Scharnier sizeof to.tsp_name-1); 57530642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 5761553Srgrimes if (!acksend(&to, &taddr, tname, 5771553Srgrimes TSP_ACK, 0, 1)) { 5781553Srgrimes syslog(LOG_ERR, 5791553Srgrimes "no reply from %s to slave LOOP-QUIT", 5801553Srgrimes tname); 5811553Srgrimes } else { 5821553Srgrimes electiontime = 0; 5831553Srgrimes } 5841553Srgrimes } 5851553Srgrimes (void)gettimeofday(&ntime, 0); 5861553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 5871553Srgrimes } else { 5881553Srgrimes if (msg->tsp_hopcnt-- < 1) 5891553Srgrimes break; 5901553Srgrimes bytenetorder(msg); 5911553Srgrimes for (ntp = nettab; ntp != 0; ntp = ntp->next) { 5921553Srgrimes if (ntp->status == MASTER 5931553Srgrimes && 0 > sendto(sock, (char *)msg, 5941553Srgrimes sizeof(struct tsp), 0, 5951553Srgrimes (struct sockaddr*)&ntp->dest_addr, 5961553Srgrimes sizeof(ntp->dest_addr))) 5971553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 5981553Srgrimes } 5991553Srgrimes } 6001553Srgrimes } else { /* fromnet->status == MASTER */ 6011553Srgrimes /* 6021553Srgrimes * We should not have received this from a net 6031553Srgrimes * we are master on. There must be two masters, 6041553Srgrimes * unless the packet was really from us. 6051553Srgrimes */ 6061553Srgrimes if (from.sin_addr.s_addr 6071553Srgrimes == fromnet->my_addr.s_addr) { 6081553Srgrimes if (trace) 6091553Srgrimes fprintf(fd,"discarding forwarded LOOP\n"); 6101553Srgrimes break; 6111553Srgrimes } 6121553Srgrimes 6131553Srgrimes /* 6141553Srgrimes * The other master often gets into the same 6151553Srgrimes * state, with boring results. 6161553Srgrimes */ 6171553Srgrimes ntp = fromnet; 6181553Srgrimes for (tries = 0; tries < 3; tries++) { 6191553Srgrimes to.tsp_type = TSP_RESOLVE; 6201553Srgrimes answer = acksend(&to, &ntp->dest_addr, 6211553Srgrimes ANYADDR, TSP_MASTERACK, 6221553Srgrimes ntp,0); 6231553Srgrimes if (!answer) 6241553Srgrimes break; 6251553Srgrimes htp = addmach(answer->tsp_name, 6261553Srgrimes &from,ntp); 6271553Srgrimes to.tsp_type = TSP_QUIT; 62830642Scharnier (void)strncpy(to.tsp_name, hostname, 62930642Scharnier sizeof to.tsp_name-1); 63030642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 6311553Srgrimes if (!acksend(&to,&htp->addr,htp->name, 6321553Srgrimes TSP_ACK, 0, htp->noanswer)) { 6331553Srgrimes syslog(LOG_ERR, 6341553Srgrimes "no reply from %s to master LOOP-QUIT", 6351553Srgrimes htp->name); 6361553Srgrimes (void)remmach(htp); 6371553Srgrimes } 6381553Srgrimes } 6391553Srgrimes (void)gettimeofday(&ntime, 0); 6401553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 6411553Srgrimes } 6421553Srgrimes break; 6431553Srgrimes default: 6441553Srgrimes if (trace) { 6451553Srgrimes fprintf(fd, "garbage message: "); 6461553Srgrimes print(msg, &from); 6471553Srgrimes } 6481553Srgrimes break; 6491553Srgrimes } 6501553Srgrimes } 6511553Srgrimes goto loop; 6521553Srgrimes} 6531553Srgrimes 6541553Srgrimes 6551553Srgrimes/* 6561553Srgrimes * tell the world who our master is 6571553Srgrimes */ 6581553Srgrimesstatic void 6591553Srgrimessetmaster(msg) 6601553Srgrimes struct tsp *msg; 6611553Srgrimes{ 6621553Srgrimes if (slavenet 6631553Srgrimes && (slavenet != old_slavenet 6641553Srgrimes || strcmp(msg->tsp_name, master_name) 6651553Srgrimes || old_status != status)) { 66630642Scharnier (void)strncpy(master_name, msg->tsp_name, 66730642Scharnier sizeof master_name-1); 66830642Scharnier master_name[sizeof master_name-1] = '\0'; 6691553Srgrimes old_slavenet = slavenet; 6701553Srgrimes old_status = status; 6711553Srgrimes 6721553Srgrimes if (status & MASTER) { 6731553Srgrimes syslog(LOG_NOTICE, "submaster to %s", master_name); 6741553Srgrimes if (trace) 6751553Srgrimes fprintf(fd, "submaster to %s\n", master_name); 6761553Srgrimes 6771553Srgrimes } else { 6781553Srgrimes syslog(LOG_NOTICE, "slave to %s", master_name); 6791553Srgrimes if (trace) 6801553Srgrimes fprintf(fd, "slave to %s\n", master_name); 6811553Srgrimes } 6821553Srgrimes } 6831553Srgrimes} 6841553Srgrimes 6851553Srgrimes 6861553Srgrimes 6871553Srgrimes/* 6881553Srgrimes * handle date change request on a slave 6891553Srgrimes */ 6901553Srgrimesstatic void 6911553Srgrimesschgdate(msg, newdate) 6921553Srgrimes struct tsp *msg; 6931553Srgrimes char *newdate; 6941553Srgrimes{ 6951553Srgrimes struct tsp to; 6961553Srgrimes u_short seq; 6971553Srgrimes struct sockaddr_in taddr; 6981553Srgrimes struct timeval otime; 6991553Srgrimes 7001553Srgrimes if (!slavenet) 7011553Srgrimes return; /* no where to forward */ 7021553Srgrimes 7031553Srgrimes taddr = from; 7041553Srgrimes seq = msg->tsp_seq; 7051553Srgrimes 7061553Srgrimes syslog(LOG_INFO, 7071553Srgrimes "forwarding date change by %s to %s", 7081553Srgrimes msg->tsp_name, newdate); 7091553Srgrimes 7101553Srgrimes /* adjust time for residence on the queue */ 7111553Srgrimes (void)gettimeofday(&otime, 0); 7121553Srgrimes adj_msg_time(msg, &otime); 7131553Srgrimes 7141553Srgrimes to.tsp_type = TSP_SETDATEREQ; 7151553Srgrimes to.tsp_time = msg->tsp_time; 71630642Scharnier (void)strncpy(to.tsp_name, hostname, sizeof to.tsp_name-1); 71730642Scharnier to.tsp_name[sizeof to.tsp_name-1] = '\0'; 7181553Srgrimes if (!acksend(&to, &slavenet->dest_addr, 7191553Srgrimes ANYADDR, TSP_DATEACK, 7201553Srgrimes slavenet, 0)) 7211553Srgrimes return; /* no answer */ 7221553Srgrimes 7231553Srgrimes xmit(TSP_DATEACK, seq, &taddr); 7241553Srgrimes} 7251553Srgrimes 7261553Srgrimes 7271553Srgrimes/* 7281553Srgrimes * Used before answering a broadcast message to avoid network 7291553Srgrimes * contention and likely collisions. 7301553Srgrimes */ 7311553Srgrimesstatic void 7321553Srgrimesanswerdelay() 7331553Srgrimes{ 7341553Srgrimes#ifdef sgi 7351553Srgrimes sginap(delay1); 7361553Srgrimes#else 7371553Srgrimes struct timeval timeout; 7381553Srgrimes 7391553Srgrimes timeout.tv_sec = 0; 7401553Srgrimes timeout.tv_usec = delay1; 7411553Srgrimes 7421553Srgrimes (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, 7431553Srgrimes &timeout); 7441553Srgrimes return; 7451553Srgrimes#endif /* sgi */ 7461553Srgrimes} 747