slave.c revision 202204
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[] = 3950479Speter "$FreeBSD: head/usr.sbin/timed/timed/slave.c 202204 2010-01-13 18:15:46Z ed $"; 401553Srgrimes#endif /* not lint */ 411553Srgrimes 421553Srgrimes#include "globals.h" 431553Srgrimes#include <setjmp.h> 44202204Sed#include <utmpx.h> 451553Srgrimes#include "pathnames.h" 461553Srgrimes 471553Srgrimesextern jmp_buf jmpenv; 481553Srgrimesextern int Mflag; 491553Srgrimesextern int justquit; 501553Srgrimes 511553Srgrimesextern u_short sequence; 521553Srgrimes 5330872Scharnierstatic char master_name[MAXHOSTNAMELEN]; 541553Srgrimesstatic struct netinfo *old_slavenet; 551553Srgrimesstatic int old_status; 561553Srgrimes 57173412Skevlostatic void schgdate(struct tsp *, char *); 58173412Skevlostatic void setmaster(struct tsp *); 59173412Skevlostatic void answerdelay(void); 601553Srgrimes 611553Srgrimesint 621553Srgrimesslave() 631553Srgrimes{ 641553Srgrimes int tries; 651553Srgrimes long electiontime, refusetime, looktime, looptime, adjtime; 661553Srgrimes u_short seq; 671553Srgrimes long fastelection; 681553Srgrimes#define FASTTOUT 3 691553Srgrimes struct in_addr cadr; 701553Srgrimes struct timeval otime; 711553Srgrimes struct sockaddr_in taddr; 721553Srgrimes char tname[MAXHOSTNAMELEN]; 731553Srgrimes struct tsp *msg, to; 7486644Sjhb struct timeval ntime, wait, tmptv; 7537267Sbde time_t tsp_time_sec; 761553Srgrimes struct tsp *answer; 771553Srgrimes int timeout(); 781553Srgrimes char olddate[32]; 791553Srgrimes char newdate[32]; 801553Srgrimes struct netinfo *ntp; 811553Srgrimes struct hosttbl *htp; 82202204Sed struct utmpx utx; 831553Srgrimes 841553Srgrimes 851553Srgrimes old_slavenet = 0; 861553Srgrimes seq = 0; 871553Srgrimes refusetime = 0; 881553Srgrimes adjtime = 0; 891553Srgrimes 901553Srgrimes (void)gettimeofday(&ntime, 0); 911553Srgrimes electiontime = ntime.tv_sec + delay2; 921553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 931553Srgrimes if (justquit) 941553Srgrimes looktime = electiontime; 951553Srgrimes else 961553Srgrimes looktime = fastelection; 971553Srgrimes looptime = fastelection; 981553Srgrimes 991553Srgrimes if (slavenet) 1001553Srgrimes xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr); 1011553Srgrimes if (status & MASTER) { 1021553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1031553Srgrimes if (ntp->status == MASTER) 1041553Srgrimes masterup(ntp); 1051553Srgrimes } 1061553Srgrimes } 1071553Srgrimes 1081553Srgrimesloop: 1091553Srgrimes get_goodgroup(0); 1101553Srgrimes (void)gettimeofday(&ntime, (struct timezone *)0); 1111553Srgrimes if (ntime.tv_sec > electiontime) { 1121553Srgrimes if (trace) 1131553Srgrimes fprintf(fd, "election timer expired\n"); 1141553Srgrimes longjmp(jmpenv, 1); 1151553Srgrimes } 1161553Srgrimes 1171553Srgrimes if (ntime.tv_sec >= looktime) { 1181553Srgrimes if (trace) 1191553Srgrimes fprintf(fd, "Looking for nets to master\n"); 1201553Srgrimes 1211553Srgrimes if (Mflag && nignorednets > 0) { 1221553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1231553Srgrimes if (ntp->status == IGNORE 1241553Srgrimes || ntp->status == NOMASTER) { 1251553Srgrimes lookformaster(ntp); 1261553Srgrimes if (ntp->status == MASTER) { 1271553Srgrimes masterup(ntp); 1281553Srgrimes } else if (ntp->status == MASTER) { 1291553Srgrimes ntp->status = NOMASTER; 1301553Srgrimes } 1311553Srgrimes } 1321553Srgrimes if (ntp->status == MASTER 1331553Srgrimes && --ntp->quit_count < 0) 1341553Srgrimes ntp->quit_count = 0; 1351553Srgrimes } 1361553Srgrimes makeslave(slavenet); /* prune extras */ 1371553Srgrimes setstatus(); 1381553Srgrimes } 1391553Srgrimes (void)gettimeofday(&ntime, 0); 1401553Srgrimes looktime = ntime.tv_sec + delay2; 1411553Srgrimes } 1421553Srgrimes if (ntime.tv_sec >= looptime) { 1431553Srgrimes if (trace) 1441553Srgrimes fprintf(fd, "Looking for loops\n"); 1451553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1461553Srgrimes if (ntp->status == MASTER) { 1471553Srgrimes to.tsp_type = TSP_LOOP; 1481553Srgrimes to.tsp_vers = TSPVERSION; 1491553Srgrimes to.tsp_seq = sequence++; 1501553Srgrimes to.tsp_hopcnt = MAX_HOPCNT; 15130830Scharnier (void)strcpy(to.tsp_name, hostname); 1521553Srgrimes bytenetorder(&to); 1531553Srgrimes if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, 1541553Srgrimes (struct sockaddr*)&ntp->dest_addr, 1551553Srgrimes sizeof(ntp->dest_addr)) < 0) { 1561553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 1571553Srgrimes } 1581553Srgrimes } 1591553Srgrimes } 1601553Srgrimes (void)gettimeofday(&ntime, 0); 1611553Srgrimes looptime = ntime.tv_sec + delay2; 1621553Srgrimes } 1631553Srgrimes 1641553Srgrimes wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec; 1651553Srgrimes if (wait.tv_sec < 0) 1661553Srgrimes wait.tv_sec = 0; 1671553Srgrimes wait.tv_sec += FASTTOUT; 1681553Srgrimes wait.tv_usec = 0; 1691553Srgrimes msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 1701553Srgrimes 1711553Srgrimes if (msg != NULL) { 1721553Srgrimes /* 1731553Srgrimes * filter stuff not for us 1741553Srgrimes */ 1751553Srgrimes switch (msg->tsp_type) { 1761553Srgrimes case TSP_SETDATE: 1771553Srgrimes case TSP_TRACEOFF: 1781553Srgrimes case TSP_TRACEON: 1791553Srgrimes /* 1801553Srgrimes * XXX check to see they are from ourself 1811553Srgrimes */ 1821553Srgrimes break; 1831553Srgrimes 1841553Srgrimes case TSP_TEST: 1851553Srgrimes case TSP_MSITE: 1861553Srgrimes break; 1871553Srgrimes 1881553Srgrimes case TSP_MASTERUP: 1891553Srgrimes if (!fromnet) { 1901553Srgrimes if (trace) { 1911553Srgrimes fprintf(fd, "slave ignored: "); 1921553Srgrimes print(msg, &from); 1931553Srgrimes } 1941553Srgrimes goto loop; 1951553Srgrimes } 1961553Srgrimes break; 1971553Srgrimes 1981553Srgrimes default: 1991553Srgrimes if (!fromnet 2001553Srgrimes || fromnet->status == IGNORE 2011553Srgrimes || fromnet->status == NOMASTER) { 2021553Srgrimes if (trace) { 2031553Srgrimes fprintf(fd, "slave ignored: "); 2041553Srgrimes print(msg, &from); 2051553Srgrimes } 2061553Srgrimes goto loop; 2071553Srgrimes } 2081553Srgrimes break; 2091553Srgrimes } 2101553Srgrimes 2111553Srgrimes 2121553Srgrimes /* 2131553Srgrimes * now process the message 2141553Srgrimes */ 2151553Srgrimes switch (msg->tsp_type) { 2161553Srgrimes 2171553Srgrimes case TSP_ADJTIME: 2181553Srgrimes if (fromnet != slavenet) 2191553Srgrimes break; 2201553Srgrimes if (!good_host_name(msg->tsp_name)) { 2211553Srgrimes syslog(LOG_NOTICE, 2221553Srgrimes "attempted time adjustment by %s", 2231553Srgrimes msg->tsp_name); 2241553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2251553Srgrimes break; 2261553Srgrimes } 2271553Srgrimes /* 2281553Srgrimes * Speed up loop detection in case we have a loop. 2291553Srgrimes * Otherwise the clocks can race until the loop 2301553Srgrimes * is found. 2311553Srgrimes */ 2321553Srgrimes (void)gettimeofday(&otime, 0); 2331553Srgrimes if (adjtime < otime.tv_sec) 2341553Srgrimes looptime -= (looptime-otime.tv_sec)/2 + 1; 2351553Srgrimes 2361553Srgrimes setmaster(msg); 2371553Srgrimes if (seq != msg->tsp_seq) { 2381553Srgrimes seq = msg->tsp_seq; 2391553Srgrimes synch(tvtomsround(msg->tsp_time)); 2401553Srgrimes } 2411553Srgrimes (void)gettimeofday(&ntime, 0); 2421553Srgrimes electiontime = ntime.tv_sec + delay2; 2431553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 2441553Srgrimes adjtime = ntime.tv_sec + SAMPLEINTVL*2; 2451553Srgrimes break; 2461553Srgrimes 2471553Srgrimes case TSP_SETTIME: 2481553Srgrimes if (fromnet != slavenet) 2491553Srgrimes break; 2501553Srgrimes if (seq == msg->tsp_seq) 2511553Srgrimes break; 2521553Srgrimes seq = msg->tsp_seq; 2531553Srgrimes 2541553Srgrimes /* adjust time for residence on the queue */ 2551553Srgrimes (void)gettimeofday(&otime, 0); 2561553Srgrimes adj_msg_time(msg,&otime); 2571553Srgrimes /* 2581553Srgrimes * the following line is necessary due to syslog 2591553Srgrimes * calling ctime() which clobbers the static buffer 2601553Srgrimes */ 26130830Scharnier (void)strcpy(olddate, date()); 26237267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 26337267Sbde (void)strcpy(newdate, ctime(&tsp_time_sec)); 2641553Srgrimes 2651553Srgrimes if (!good_host_name(msg->tsp_name)) { 2661553Srgrimes syslog(LOG_NOTICE, 2671553Srgrimes "attempted time setting by untrusted %s to %s", 2681553Srgrimes msg->tsp_name, newdate); 2691553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2701553Srgrimes break; 2711553Srgrimes } 2721553Srgrimes 2731553Srgrimes setmaster(msg); 27486644Sjhb tmptv.tv_sec = msg->tsp_time.tv_sec; 27586644Sjhb tmptv.tv_usec = msg->tsp_time.tv_usec; 27686644Sjhb timevalsub(&ntime, &tmptv, &otime); 2771553Srgrimes if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 2781553Srgrimes /* 2791553Srgrimes * do not change the clock if we can adjust it 2801553Srgrimes */ 2811553Srgrimes synch(tvtomsround(ntime)); 2821553Srgrimes } else { 283202204Sed utx.ut_type = OLD_TIME; 284202204Sed gettimeofday(&utx.ut_tv, NULL); 285202204Sed pututxline(&utx); 286202204Sed (void)settimeofday(&tmptv, 0); 287202204Sed utx.ut_type = NEW_TIME; 288202204Sed gettimeofday(&utx.ut_tv, NULL); 289202204Sed pututxline(&utx); 2901553Srgrimes syslog(LOG_NOTICE, 2911553Srgrimes "date changed by %s from %s", 2921553Srgrimes msg->tsp_name, olddate); 2931553Srgrimes if (status & MASTER) 2941553Srgrimes spreadtime(); 2951553Srgrimes } 2961553Srgrimes (void)gettimeofday(&ntime, 0); 2971553Srgrimes electiontime = ntime.tv_sec + delay2; 2981553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 2991553Srgrimes 3001553Srgrimes/* This patches a bad protocol bug. Imagine a system with several networks, 3011553Srgrimes * where there are a pair of redundant gateways between a pair of networks, 3021553Srgrimes * each running timed. Assume that we start with a third machine mastering 3031553Srgrimes * one of the networks, and one of the gateways mastering the other. 3041553Srgrimes * Imagine that the third machine goes away and the non-master gateway 3051553Srgrimes * decides to replace it. If things are timed just 'right,' we will have 3061553Srgrimes * each gateway mastering one network for a little while. If a SETTIME 3071553Srgrimes * message gets into the network at that time, perhaps from the newly 3081553Srgrimes * masterful gateway as it was taking control, the SETTIME will loop 3091553Srgrimes * forever. Each time a gateway receives it on its slave side, it will 3101553Srgrimes * call spreadtime to forward it on its mastered network. We are now in 3111553Srgrimes * a permanent loop, since the SETTIME msgs will keep any clock 3121553Srgrimes * in the network from advancing. Normally, the 'LOOP' stuff will detect 3131553Srgrimes * and correct the situation. However, with the clocks stopped, the 3141553Srgrimes * 'looptime' timer cannot expire. While they are in this state, the 3151553Srgrimes * masters will try to saturate the network with SETTIME packets. 3161553Srgrimes */ 3171553Srgrimes looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1; 3181553Srgrimes break; 3191553Srgrimes 3201553Srgrimes case TSP_MASTERUP: 3211553Srgrimes if (slavenet && fromnet != slavenet) 3221553Srgrimes break; 3231553Srgrimes if (!good_host_name(msg->tsp_name)) { 3241553Srgrimes suppress(&from, msg->tsp_name, fromnet); 3251553Srgrimes if (electiontime > fastelection) 3261553Srgrimes electiontime = fastelection; 3271553Srgrimes break; 3281553Srgrimes } 3291553Srgrimes makeslave(fromnet); 3301553Srgrimes setmaster(msg); 3311553Srgrimes setstatus(); 3321553Srgrimes answerdelay(); 3331553Srgrimes xmit(TSP_SLAVEUP, 0, &from); 3341553Srgrimes (void)gettimeofday(&ntime, 0); 3351553Srgrimes electiontime = ntime.tv_sec + delay2; 3361553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3371553Srgrimes refusetime = 0; 3381553Srgrimes break; 3391553Srgrimes 3401553Srgrimes case TSP_MASTERREQ: 3411553Srgrimes if (fromnet->status != SLAVE) 3421553Srgrimes break; 3431553Srgrimes (void)gettimeofday(&ntime, 0); 3441553Srgrimes electiontime = ntime.tv_sec + delay2; 3451553Srgrimes break; 3461553Srgrimes 3471553Srgrimes case TSP_SETDATE: 34837267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 34937267Sbde (void)strcpy(newdate, ctime(&tsp_time_sec)); 3501553Srgrimes schgdate(msg, newdate); 3511553Srgrimes break; 3521553Srgrimes 3531553Srgrimes case TSP_SETDATEREQ: 3541553Srgrimes if (fromnet->status != MASTER) 3551553Srgrimes break; 35637267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 35737267Sbde (void)strcpy(newdate, ctime(&tsp_time_sec)); 3581553Srgrimes htp = findhost(msg->tsp_name); 3591553Srgrimes if (0 == htp) { 3601553Srgrimes syslog(LOG_WARNING, 3611553Srgrimes "DATEREQ from uncontrolled machine"); 3621553Srgrimes break; 3631553Srgrimes } 3641553Srgrimes if (!htp->good) { 3651553Srgrimes syslog(LOG_WARNING, 3661553Srgrimes "attempted date change by untrusted %s to %s", 3671553Srgrimes htp->name, newdate); 3681553Srgrimes spreadtime(); 3691553Srgrimes break; 3701553Srgrimes } 3711553Srgrimes schgdate(msg, newdate); 3721553Srgrimes break; 3731553Srgrimes 3741553Srgrimes case TSP_TRACEON: 3751553Srgrimes traceon(); 3761553Srgrimes break; 3771553Srgrimes 3781553Srgrimes case TSP_TRACEOFF: 3791553Srgrimes traceoff("Tracing ended at %s\n"); 3801553Srgrimes break; 3811553Srgrimes 3821553Srgrimes case TSP_SLAVEUP: 3831553Srgrimes newslave(msg); 3841553Srgrimes break; 3851553Srgrimes 3861553Srgrimes case TSP_ELECTION: 3871553Srgrimes if (fromnet->status == SLAVE) { 3881553Srgrimes (void)gettimeofday(&ntime, 0); 3891553Srgrimes electiontime = ntime.tv_sec + delay2; 3901553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3911553Srgrimes seq = 0; 3921553Srgrimes if (!good_host_name(msg->tsp_name)) { 3931553Srgrimes syslog(LOG_NOTICE, 3941553Srgrimes "suppress election of %s", 3951553Srgrimes msg->tsp_name); 3961553Srgrimes to.tsp_type = TSP_QUIT; 3971553Srgrimes electiontime = fastelection; 3981553Srgrimes } else if (cadr.s_addr != from.sin_addr.s_addr 3991553Srgrimes && ntime.tv_sec < refusetime) { 4001553Srgrimes/* if the candidate has to repeat itself, the old code would refuse it 4011553Srgrimes * the second time. That would prevent elections. 4021553Srgrimes */ 4031553Srgrimes to.tsp_type = TSP_REFUSE; 4041553Srgrimes } else { 4051553Srgrimes cadr.s_addr = from.sin_addr.s_addr; 4061553Srgrimes to.tsp_type = TSP_ACCEPT; 4071553Srgrimes refusetime = ntime.tv_sec + 30; 4081553Srgrimes } 4091553Srgrimes taddr = from; 41030830Scharnier (void)strcpy(tname, msg->tsp_name); 41130830Scharnier (void)strcpy(to.tsp_name, hostname); 4121553Srgrimes answerdelay(); 4131553Srgrimes if (!acksend(&to, &taddr, tname, 4141553Srgrimes TSP_ACK, 0, 0)) 4151553Srgrimes syslog(LOG_WARNING, 4161553Srgrimes "no answer from candidate %s\n", 4171553Srgrimes tname); 4181553Srgrimes 4191553Srgrimes } else { /* fromnet->status == MASTER */ 4201553Srgrimes htp = addmach(msg->tsp_name, &from,fromnet); 4211553Srgrimes to.tsp_type = TSP_QUIT; 42230830Scharnier (void)strcpy(to.tsp_name, hostname); 4231553Srgrimes if (!acksend(&to, &htp->addr, htp->name, 4241553Srgrimes TSP_ACK, 0, htp->noanswer)) { 4251553Srgrimes syslog(LOG_ERR, 4261553Srgrimes "no reply from %s to ELECTION-QUIT", 4271553Srgrimes htp->name); 4281553Srgrimes (void)remmach(htp); 4291553Srgrimes } 4301553Srgrimes } 4311553Srgrimes break; 4321553Srgrimes 4331553Srgrimes case TSP_CONFLICT: 4341553Srgrimes if (fromnet->status != MASTER) 4351553Srgrimes break; 4361553Srgrimes /* 4371553Srgrimes * After a network partition, there can be 4381553Srgrimes * more than one master: the first slave to 4391553Srgrimes * come up will notify here the situation. 4401553Srgrimes */ 44130830Scharnier (void)strcpy(to.tsp_name, hostname); 4421553Srgrimes 4431553Srgrimes /* The other master often gets into the same state, 4441553Srgrimes * with boring results. 4451553Srgrimes */ 4461553Srgrimes ntp = fromnet; /* (acksend() can leave fromnet=0 */ 4471553Srgrimes for (tries = 0; tries < 3; tries++) { 4481553Srgrimes to.tsp_type = TSP_RESOLVE; 4491553Srgrimes answer = acksend(&to, &ntp->dest_addr, 4501553Srgrimes ANYADDR, TSP_MASTERACK, 4511553Srgrimes ntp, 0); 4521553Srgrimes if (answer == NULL) 4531553Srgrimes break; 4541553Srgrimes htp = addmach(answer->tsp_name,&from,ntp); 4551553Srgrimes to.tsp_type = TSP_QUIT; 4561553Srgrimes answer = acksend(&to, &htp->addr, htp->name, 4571553Srgrimes TSP_ACK, 0, htp->noanswer); 4581553Srgrimes if (!answer) { 4591553Srgrimes syslog(LOG_WARNING, 4601553Srgrimes "conflict error: no reply from %s to QUIT", 4611553Srgrimes htp->name); 4621553Srgrimes (void)remmach(htp); 4631553Srgrimes } 4641553Srgrimes } 4651553Srgrimes masterup(ntp); 4661553Srgrimes break; 4671553Srgrimes 4681553Srgrimes case TSP_MSITE: 4691553Srgrimes if (!slavenet) 4701553Srgrimes break; 4711553Srgrimes taddr = from; 4721553Srgrimes to.tsp_type = TSP_MSITEREQ; 4731553Srgrimes to.tsp_vers = TSPVERSION; 4741553Srgrimes to.tsp_seq = 0; 47530830Scharnier (void)strcpy(to.tsp_name, hostname); 4761553Srgrimes answer = acksend(&to, &slavenet->dest_addr, 4771553Srgrimes ANYADDR, TSP_ACK, 4781553Srgrimes slavenet, 0); 4791553Srgrimes if (answer != NULL 4801553Srgrimes && good_host_name(answer->tsp_name)) { 4811553Srgrimes setmaster(answer); 4821553Srgrimes to.tsp_type = TSP_ACK; 48330830Scharnier (void)strcpy(to.tsp_name, answer->tsp_name); 4841553Srgrimes bytenetorder(&to); 4851553Srgrimes if (sendto(sock, (char *)&to, 4861553Srgrimes sizeof(struct tsp), 0, 48730642Scharnier (struct sockaddr*)&taddr, 48830830Scharnier sizeof(taddr)) < 0) { 4891553Srgrimes trace_sendto_err(taddr.sin_addr); 4901553Srgrimes } 4911553Srgrimes } 4921553Srgrimes break; 4931553Srgrimes 4941553Srgrimes case TSP_MSITEREQ: 4951553Srgrimes break; 4961553Srgrimes 4971553Srgrimes case TSP_ACCEPT: 4981553Srgrimes case TSP_REFUSE: 4991553Srgrimes case TSP_RESOLVE: 5001553Srgrimes break; 5011553Srgrimes 5021553Srgrimes case TSP_QUIT: 5031553Srgrimes doquit(msg); /* become a slave */ 5041553Srgrimes break; 5051553Srgrimes 5061553Srgrimes case TSP_TEST: 5071553Srgrimes electiontime = 0; 5081553Srgrimes break; 5091553Srgrimes 5101553Srgrimes case TSP_LOOP: 5111553Srgrimes /* looking for loops of masters */ 5121553Srgrimes if (!(status & MASTER)) 5131553Srgrimes break; 5141553Srgrimes if (fromnet->status == SLAVE) { 5151553Srgrimes if (!strcmp(msg->tsp_name, hostname)) { 5161553Srgrimes /* 5171553Srgrimes * Someone forwarded our message back to 5181553Srgrimes * us. There must be a loop. Tell the 5191553Srgrimes * master of this network to quit. 5201553Srgrimes * 5211553Srgrimes * The other master often gets into 5221553Srgrimes * the same state, with boring results. 5231553Srgrimes */ 5241553Srgrimes ntp = fromnet; 5251553Srgrimes for (tries = 0; tries < 3; tries++) { 5261553Srgrimes to.tsp_type = TSP_RESOLVE; 5271553Srgrimes answer = acksend(&to, &ntp->dest_addr, 5281553Srgrimes ANYADDR, TSP_MASTERACK, 5291553Srgrimes ntp,0); 5301553Srgrimes if (answer == NULL) 5311553Srgrimes break; 5321553Srgrimes taddr = from; 53330830Scharnier (void)strcpy(tname, answer->tsp_name); 5341553Srgrimes to.tsp_type = TSP_QUIT; 53530830Scharnier (void)strcpy(to.tsp_name, hostname); 5361553Srgrimes if (!acksend(&to, &taddr, tname, 5371553Srgrimes TSP_ACK, 0, 1)) { 5381553Srgrimes syslog(LOG_ERR, 5391553Srgrimes "no reply from %s to slave LOOP-QUIT", 5401553Srgrimes tname); 5411553Srgrimes } else { 5421553Srgrimes electiontime = 0; 5431553Srgrimes } 5441553Srgrimes } 5451553Srgrimes (void)gettimeofday(&ntime, 0); 5461553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 5471553Srgrimes } else { 5481553Srgrimes if (msg->tsp_hopcnt-- < 1) 5491553Srgrimes break; 5501553Srgrimes bytenetorder(msg); 5511553Srgrimes for (ntp = nettab; ntp != 0; ntp = ntp->next) { 5521553Srgrimes if (ntp->status == MASTER 5531553Srgrimes && 0 > sendto(sock, (char *)msg, 5541553Srgrimes sizeof(struct tsp), 0, 5551553Srgrimes (struct sockaddr*)&ntp->dest_addr, 5561553Srgrimes sizeof(ntp->dest_addr))) 5571553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 5581553Srgrimes } 5591553Srgrimes } 5601553Srgrimes } else { /* fromnet->status == MASTER */ 5611553Srgrimes /* 5621553Srgrimes * We should not have received this from a net 5631553Srgrimes * we are master on. There must be two masters, 5641553Srgrimes * unless the packet was really from us. 5651553Srgrimes */ 5661553Srgrimes if (from.sin_addr.s_addr 5671553Srgrimes == fromnet->my_addr.s_addr) { 5681553Srgrimes if (trace) 5691553Srgrimes fprintf(fd,"discarding forwarded LOOP\n"); 5701553Srgrimes break; 5711553Srgrimes } 5721553Srgrimes 5731553Srgrimes /* 5741553Srgrimes * The other master often gets into the same 5751553Srgrimes * state, with boring results. 5761553Srgrimes */ 5771553Srgrimes ntp = fromnet; 5781553Srgrimes for (tries = 0; tries < 3; tries++) { 5791553Srgrimes to.tsp_type = TSP_RESOLVE; 5801553Srgrimes answer = acksend(&to, &ntp->dest_addr, 5811553Srgrimes ANYADDR, TSP_MASTERACK, 5821553Srgrimes ntp,0); 5831553Srgrimes if (!answer) 5841553Srgrimes break; 5851553Srgrimes htp = addmach(answer->tsp_name, 5861553Srgrimes &from,ntp); 5871553Srgrimes to.tsp_type = TSP_QUIT; 58830830Scharnier (void)strcpy(to.tsp_name, hostname); 5891553Srgrimes if (!acksend(&to,&htp->addr,htp->name, 5901553Srgrimes TSP_ACK, 0, htp->noanswer)) { 5911553Srgrimes syslog(LOG_ERR, 5921553Srgrimes "no reply from %s to master LOOP-QUIT", 5931553Srgrimes htp->name); 5941553Srgrimes (void)remmach(htp); 5951553Srgrimes } 5961553Srgrimes } 5971553Srgrimes (void)gettimeofday(&ntime, 0); 5981553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 5991553Srgrimes } 6001553Srgrimes break; 6011553Srgrimes default: 6021553Srgrimes if (trace) { 6031553Srgrimes fprintf(fd, "garbage message: "); 6041553Srgrimes print(msg, &from); 6051553Srgrimes } 6061553Srgrimes break; 6071553Srgrimes } 6081553Srgrimes } 6091553Srgrimes goto loop; 6101553Srgrimes} 6111553Srgrimes 6121553Srgrimes 6131553Srgrimes/* 6141553Srgrimes * tell the world who our master is 6151553Srgrimes */ 6161553Srgrimesstatic void 6171553Srgrimessetmaster(msg) 6181553Srgrimes struct tsp *msg; 6191553Srgrimes{ 6201553Srgrimes if (slavenet 6211553Srgrimes && (slavenet != old_slavenet 6221553Srgrimes || strcmp(msg->tsp_name, master_name) 6231553Srgrimes || old_status != status)) { 62430830Scharnier (void)strcpy(master_name, msg->tsp_name); 6251553Srgrimes old_slavenet = slavenet; 6261553Srgrimes old_status = status; 6271553Srgrimes 6281553Srgrimes if (status & MASTER) { 6291553Srgrimes syslog(LOG_NOTICE, "submaster to %s", master_name); 6301553Srgrimes if (trace) 6311553Srgrimes fprintf(fd, "submaster to %s\n", master_name); 6321553Srgrimes 6331553Srgrimes } else { 6341553Srgrimes syslog(LOG_NOTICE, "slave to %s", master_name); 6351553Srgrimes if (trace) 6361553Srgrimes fprintf(fd, "slave to %s\n", master_name); 6371553Srgrimes } 6381553Srgrimes } 6391553Srgrimes} 6401553Srgrimes 6411553Srgrimes 6421553Srgrimes 6431553Srgrimes/* 6441553Srgrimes * handle date change request on a slave 6451553Srgrimes */ 6461553Srgrimesstatic void 6471553Srgrimesschgdate(msg, newdate) 6481553Srgrimes struct tsp *msg; 6491553Srgrimes char *newdate; 6501553Srgrimes{ 6511553Srgrimes struct tsp to; 6521553Srgrimes u_short seq; 6531553Srgrimes struct sockaddr_in taddr; 6541553Srgrimes struct timeval otime; 6551553Srgrimes 6561553Srgrimes if (!slavenet) 6571553Srgrimes return; /* no where to forward */ 6581553Srgrimes 6591553Srgrimes taddr = from; 6601553Srgrimes seq = msg->tsp_seq; 6611553Srgrimes 6621553Srgrimes syslog(LOG_INFO, 6631553Srgrimes "forwarding date change by %s to %s", 6641553Srgrimes msg->tsp_name, newdate); 6651553Srgrimes 6661553Srgrimes /* adjust time for residence on the queue */ 6671553Srgrimes (void)gettimeofday(&otime, 0); 6681553Srgrimes adj_msg_time(msg, &otime); 6691553Srgrimes 6701553Srgrimes to.tsp_type = TSP_SETDATEREQ; 6711553Srgrimes to.tsp_time = msg->tsp_time; 67230830Scharnier (void)strcpy(to.tsp_name, hostname); 6731553Srgrimes if (!acksend(&to, &slavenet->dest_addr, 6741553Srgrimes ANYADDR, TSP_DATEACK, 6751553Srgrimes slavenet, 0)) 6761553Srgrimes return; /* no answer */ 6771553Srgrimes 6781553Srgrimes xmit(TSP_DATEACK, seq, &taddr); 6791553Srgrimes} 6801553Srgrimes 6811553Srgrimes 6821553Srgrimes/* 6831553Srgrimes * Used before answering a broadcast message to avoid network 6841553Srgrimes * contention and likely collisions. 6851553Srgrimes */ 6861553Srgrimesstatic void 6871553Srgrimesanswerdelay() 6881553Srgrimes{ 6891553Srgrimes struct timeval timeout; 6901553Srgrimes 6911553Srgrimes timeout.tv_sec = 0; 6921553Srgrimes timeout.tv_usec = delay1; 6931553Srgrimes 6941553Srgrimes (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, 6951553Srgrimes &timeout); 6961553Srgrimes return; 6971553Srgrimes} 698