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 * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 301553Srgrimes#ifndef lint 3130642Scharnier#if 0 321553Srgrimesstatic char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93"; 3330642Scharnier#endif 3430642Scharnierstatic const char rcsid[] = 3550479Speter "$FreeBSD: stable/11/usr.sbin/timed/timed/slave.c 331722 2018-03-29 02:50:57Z eadler $"; 361553Srgrimes#endif /* not lint */ 371553Srgrimes 381553Srgrimes#include "globals.h" 391553Srgrimes#include <setjmp.h> 40202204Sed#include <utmpx.h> 411553Srgrimes#include "pathnames.h" 421553Srgrimes 431553Srgrimesextern jmp_buf jmpenv; 441553Srgrimesextern int Mflag; 451553Srgrimesextern int justquit; 461553Srgrimes 471553Srgrimesextern u_short sequence; 481553Srgrimes 4930872Scharnierstatic char master_name[MAXHOSTNAMELEN]; 501553Srgrimesstatic struct netinfo *old_slavenet; 511553Srgrimesstatic int old_status; 521553Srgrimes 53173412Skevlostatic void schgdate(struct tsp *, char *); 54173412Skevlostatic void setmaster(struct tsp *); 55173412Skevlostatic void answerdelay(void); 561553Srgrimes 57331090Seadlervoid 58246209Scharnierslave(void) 591553Srgrimes{ 601553Srgrimes int tries; 611553Srgrimes long electiontime, refusetime, looktime, looptime, adjtime; 621553Srgrimes u_short seq; 631553Srgrimes long fastelection; 641553Srgrimes#define FASTTOUT 3 651553Srgrimes struct in_addr cadr; 661553Srgrimes struct timeval otime; 671553Srgrimes struct sockaddr_in taddr; 681553Srgrimes char tname[MAXHOSTNAMELEN]; 691553Srgrimes struct tsp *msg, to; 7086644Sjhb struct timeval ntime, wait, tmptv; 7137267Sbde time_t tsp_time_sec; 721553Srgrimes struct tsp *answer; 731553Srgrimes int timeout(); 741553Srgrimes char olddate[32]; 751553Srgrimes char newdate[32]; 761553Srgrimes struct netinfo *ntp; 771553Srgrimes struct hosttbl *htp; 78202204Sed struct utmpx utx; 791553Srgrimes 801553Srgrimes 81299707Spfg old_slavenet = NULL; 821553Srgrimes seq = 0; 831553Srgrimes refusetime = 0; 841553Srgrimes adjtime = 0; 851553Srgrimes 86239991Sed (void)gettimeofday(&ntime, NULL); 871553Srgrimes electiontime = ntime.tv_sec + delay2; 881553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 891553Srgrimes if (justquit) 901553Srgrimes looktime = electiontime; 911553Srgrimes else 921553Srgrimes looktime = fastelection; 931553Srgrimes looptime = fastelection; 941553Srgrimes 951553Srgrimes if (slavenet) 961553Srgrimes xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr); 971553Srgrimes if (status & MASTER) { 981553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 991553Srgrimes if (ntp->status == MASTER) 1001553Srgrimes masterup(ntp); 1011553Srgrimes } 1021553Srgrimes } 1031553Srgrimes 1041553Srgrimesloop: 1051553Srgrimes get_goodgroup(0); 106239991Sed (void)gettimeofday(&ntime, NULL); 1071553Srgrimes if (ntime.tv_sec > electiontime) { 1081553Srgrimes if (trace) 1091553Srgrimes fprintf(fd, "election timer expired\n"); 1101553Srgrimes longjmp(jmpenv, 1); 1111553Srgrimes } 1121553Srgrimes 1131553Srgrimes if (ntime.tv_sec >= looktime) { 1141553Srgrimes if (trace) 1151553Srgrimes fprintf(fd, "Looking for nets to master\n"); 1161553Srgrimes 1171553Srgrimes if (Mflag && nignorednets > 0) { 1181553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1191553Srgrimes if (ntp->status == IGNORE 1201553Srgrimes || ntp->status == NOMASTER) { 1211553Srgrimes lookformaster(ntp); 1221553Srgrimes if (ntp->status == MASTER) { 1231553Srgrimes masterup(ntp); 1241553Srgrimes } else if (ntp->status == MASTER) { 1251553Srgrimes ntp->status = NOMASTER; 1261553Srgrimes } 1271553Srgrimes } 1281553Srgrimes if (ntp->status == MASTER 1291553Srgrimes && --ntp->quit_count < 0) 1301553Srgrimes ntp->quit_count = 0; 1311553Srgrimes } 1321553Srgrimes makeslave(slavenet); /* prune extras */ 1331553Srgrimes setstatus(); 1341553Srgrimes } 135239991Sed (void)gettimeofday(&ntime, NULL); 1361553Srgrimes looktime = ntime.tv_sec + delay2; 1371553Srgrimes } 1381553Srgrimes if (ntime.tv_sec >= looptime) { 1391553Srgrimes if (trace) 1401553Srgrimes fprintf(fd, "Looking for loops\n"); 1411553Srgrimes for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 1421553Srgrimes if (ntp->status == MASTER) { 1431553Srgrimes to.tsp_type = TSP_LOOP; 1441553Srgrimes to.tsp_vers = TSPVERSION; 1451553Srgrimes to.tsp_seq = sequence++; 1461553Srgrimes to.tsp_hopcnt = MAX_HOPCNT; 14730830Scharnier (void)strcpy(to.tsp_name, hostname); 1481553Srgrimes bytenetorder(&to); 1491553Srgrimes if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, 1501553Srgrimes (struct sockaddr*)&ntp->dest_addr, 1511553Srgrimes sizeof(ntp->dest_addr)) < 0) { 1521553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 1531553Srgrimes } 1541553Srgrimes } 1551553Srgrimes } 156239991Sed (void)gettimeofday(&ntime, NULL); 1571553Srgrimes looptime = ntime.tv_sec + delay2; 1581553Srgrimes } 1591553Srgrimes 1601553Srgrimes wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec; 1611553Srgrimes if (wait.tv_sec < 0) 1621553Srgrimes wait.tv_sec = 0; 1631553Srgrimes wait.tv_sec += FASTTOUT; 1641553Srgrimes wait.tv_usec = 0; 1651553Srgrimes msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); 1661553Srgrimes 1671553Srgrimes if (msg != NULL) { 1681553Srgrimes /* 1691553Srgrimes * filter stuff not for us 1701553Srgrimes */ 1711553Srgrimes switch (msg->tsp_type) { 1721553Srgrimes case TSP_SETDATE: 1731553Srgrimes case TSP_TRACEOFF: 1741553Srgrimes case TSP_TRACEON: 1751553Srgrimes /* 1761553Srgrimes * XXX check to see they are from ourself 1771553Srgrimes */ 1781553Srgrimes break; 1791553Srgrimes 1801553Srgrimes case TSP_TEST: 1811553Srgrimes case TSP_MSITE: 1821553Srgrimes break; 1831553Srgrimes 1841553Srgrimes case TSP_MASTERUP: 1851553Srgrimes if (!fromnet) { 1861553Srgrimes if (trace) { 1871553Srgrimes fprintf(fd, "slave ignored: "); 1881553Srgrimes print(msg, &from); 1891553Srgrimes } 1901553Srgrimes goto loop; 1911553Srgrimes } 1921553Srgrimes break; 1931553Srgrimes 1941553Srgrimes default: 1951553Srgrimes if (!fromnet 1961553Srgrimes || fromnet->status == IGNORE 1971553Srgrimes || fromnet->status == NOMASTER) { 1981553Srgrimes if (trace) { 1991553Srgrimes fprintf(fd, "slave ignored: "); 2001553Srgrimes print(msg, &from); 2011553Srgrimes } 2021553Srgrimes goto loop; 2031553Srgrimes } 2041553Srgrimes break; 2051553Srgrimes } 2061553Srgrimes 2071553Srgrimes 2081553Srgrimes /* 2091553Srgrimes * now process the message 2101553Srgrimes */ 2111553Srgrimes switch (msg->tsp_type) { 2121553Srgrimes 2131553Srgrimes case TSP_ADJTIME: 2141553Srgrimes if (fromnet != slavenet) 2151553Srgrimes break; 2161553Srgrimes if (!good_host_name(msg->tsp_name)) { 2171553Srgrimes syslog(LOG_NOTICE, 2181553Srgrimes "attempted time adjustment by %s", 2191553Srgrimes msg->tsp_name); 2201553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2211553Srgrimes break; 2221553Srgrimes } 2231553Srgrimes /* 2241553Srgrimes * Speed up loop detection in case we have a loop. 2251553Srgrimes * Otherwise the clocks can race until the loop 2261553Srgrimes * is found. 2271553Srgrimes */ 228239991Sed (void)gettimeofday(&otime, NULL); 2291553Srgrimes if (adjtime < otime.tv_sec) 2301553Srgrimes looptime -= (looptime-otime.tv_sec)/2 + 1; 2311553Srgrimes 2321553Srgrimes setmaster(msg); 2331553Srgrimes if (seq != msg->tsp_seq) { 2341553Srgrimes seq = msg->tsp_seq; 2351553Srgrimes synch(tvtomsround(msg->tsp_time)); 2361553Srgrimes } 237239991Sed (void)gettimeofday(&ntime, NULL); 2381553Srgrimes electiontime = ntime.tv_sec + delay2; 2391553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 2401553Srgrimes adjtime = ntime.tv_sec + SAMPLEINTVL*2; 2411553Srgrimes break; 2421553Srgrimes 2431553Srgrimes case TSP_SETTIME: 2441553Srgrimes if (fromnet != slavenet) 2451553Srgrimes break; 2461553Srgrimes if (seq == msg->tsp_seq) 2471553Srgrimes break; 2481553Srgrimes seq = msg->tsp_seq; 2491553Srgrimes 2501553Srgrimes /* adjust time for residence on the queue */ 251239991Sed (void)gettimeofday(&otime, NULL); 2521553Srgrimes adj_msg_time(msg,&otime); 2531553Srgrimes /* 2541553Srgrimes * the following line is necessary due to syslog 2551553Srgrimes * calling ctime() which clobbers the static buffer 2561553Srgrimes */ 257299709Spfg (void)strlcpy(olddate, date(), sizeof(olddate)); 25837267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 259299709Spfg (void)strlcpy(newdate, ctime(&tsp_time_sec), 260299709Spfg sizeof(newdate)); 2611553Srgrimes 2621553Srgrimes if (!good_host_name(msg->tsp_name)) { 2631553Srgrimes syslog(LOG_NOTICE, 2641553Srgrimes "attempted time setting by untrusted %s to %s", 2651553Srgrimes msg->tsp_name, newdate); 2661553Srgrimes suppress(&from, msg->tsp_name, fromnet); 2671553Srgrimes break; 2681553Srgrimes } 2691553Srgrimes 2701553Srgrimes setmaster(msg); 27186644Sjhb tmptv.tv_sec = msg->tsp_time.tv_sec; 27286644Sjhb tmptv.tv_usec = msg->tsp_time.tv_usec; 27386644Sjhb timevalsub(&ntime, &tmptv, &otime); 2741553Srgrimes if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { 2751553Srgrimes /* 2761553Srgrimes * do not change the clock if we can adjust it 2771553Srgrimes */ 2781553Srgrimes synch(tvtomsround(ntime)); 2791553Srgrimes } else { 280202204Sed utx.ut_type = OLD_TIME; 281202204Sed gettimeofday(&utx.ut_tv, NULL); 282202204Sed pututxline(&utx); 283202204Sed (void)settimeofday(&tmptv, 0); 284202204Sed utx.ut_type = NEW_TIME; 285202204Sed gettimeofday(&utx.ut_tv, NULL); 286202204Sed pututxline(&utx); 2871553Srgrimes syslog(LOG_NOTICE, 2881553Srgrimes "date changed by %s from %s", 2891553Srgrimes msg->tsp_name, olddate); 2901553Srgrimes if (status & MASTER) 2911553Srgrimes spreadtime(); 2921553Srgrimes } 293239991Sed (void)gettimeofday(&ntime, NULL); 2941553Srgrimes electiontime = ntime.tv_sec + delay2; 2951553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 2961553Srgrimes 2971553Srgrimes/* This patches a bad protocol bug. Imagine a system with several networks, 2981553Srgrimes * where there are a pair of redundant gateways between a pair of networks, 2991553Srgrimes * each running timed. Assume that we start with a third machine mastering 3001553Srgrimes * one of the networks, and one of the gateways mastering the other. 3011553Srgrimes * Imagine that the third machine goes away and the non-master gateway 3021553Srgrimes * decides to replace it. If things are timed just 'right,' we will have 3031553Srgrimes * each gateway mastering one network for a little while. If a SETTIME 3041553Srgrimes * message gets into the network at that time, perhaps from the newly 3051553Srgrimes * masterful gateway as it was taking control, the SETTIME will loop 3061553Srgrimes * forever. Each time a gateway receives it on its slave side, it will 3071553Srgrimes * call spreadtime to forward it on its mastered network. We are now in 3081553Srgrimes * a permanent loop, since the SETTIME msgs will keep any clock 3091553Srgrimes * in the network from advancing. Normally, the 'LOOP' stuff will detect 3101553Srgrimes * and correct the situation. However, with the clocks stopped, the 3111553Srgrimes * 'looptime' timer cannot expire. While they are in this state, the 3121553Srgrimes * masters will try to saturate the network with SETTIME packets. 3131553Srgrimes */ 3141553Srgrimes looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1; 3151553Srgrimes break; 3161553Srgrimes 3171553Srgrimes case TSP_MASTERUP: 3181553Srgrimes if (slavenet && fromnet != slavenet) 3191553Srgrimes break; 3201553Srgrimes if (!good_host_name(msg->tsp_name)) { 3211553Srgrimes suppress(&from, msg->tsp_name, fromnet); 3221553Srgrimes if (electiontime > fastelection) 3231553Srgrimes electiontime = fastelection; 3241553Srgrimes break; 3251553Srgrimes } 3261553Srgrimes makeslave(fromnet); 3271553Srgrimes setmaster(msg); 3281553Srgrimes setstatus(); 3291553Srgrimes answerdelay(); 3301553Srgrimes xmit(TSP_SLAVEUP, 0, &from); 331239991Sed (void)gettimeofday(&ntime, NULL); 3321553Srgrimes electiontime = ntime.tv_sec + delay2; 3331553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3341553Srgrimes refusetime = 0; 3351553Srgrimes break; 3361553Srgrimes 3371553Srgrimes case TSP_MASTERREQ: 3381553Srgrimes if (fromnet->status != SLAVE) 3391553Srgrimes break; 340239991Sed (void)gettimeofday(&ntime, NULL); 3411553Srgrimes electiontime = ntime.tv_sec + delay2; 3421553Srgrimes break; 3431553Srgrimes 3441553Srgrimes case TSP_SETDATE: 34537267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 346299709Spfg (void)strlcpy(newdate, ctime(&tsp_time_sec), 347299709Spfg sizeof(newdate)); 3481553Srgrimes schgdate(msg, newdate); 3491553Srgrimes break; 3501553Srgrimes 3511553Srgrimes case TSP_SETDATEREQ: 3521553Srgrimes if (fromnet->status != MASTER) 3531553Srgrimes break; 35437267Sbde tsp_time_sec = msg->tsp_time.tv_sec; 355299709Spfg (void)strlcpy(newdate, ctime(&tsp_time_sec), 356299709Spfg sizeof(newdate)); 3571553Srgrimes htp = findhost(msg->tsp_name); 358299707Spfg if (htp == NULL) { 3591553Srgrimes syslog(LOG_WARNING, 3601553Srgrimes "DATEREQ from uncontrolled machine"); 3611553Srgrimes break; 3621553Srgrimes } 3631553Srgrimes if (!htp->good) { 3641553Srgrimes syslog(LOG_WARNING, 3651553Srgrimes "attempted date change by untrusted %s to %s", 3661553Srgrimes htp->name, newdate); 3671553Srgrimes spreadtime(); 3681553Srgrimes break; 3691553Srgrimes } 3701553Srgrimes schgdate(msg, newdate); 3711553Srgrimes break; 3721553Srgrimes 3731553Srgrimes case TSP_TRACEON: 3741553Srgrimes traceon(); 3751553Srgrimes break; 3761553Srgrimes 3771553Srgrimes case TSP_TRACEOFF: 3781553Srgrimes traceoff("Tracing ended at %s\n"); 3791553Srgrimes break; 3801553Srgrimes 3811553Srgrimes case TSP_SLAVEUP: 3821553Srgrimes newslave(msg); 3831553Srgrimes break; 3841553Srgrimes 3851553Srgrimes case TSP_ELECTION: 3861553Srgrimes if (fromnet->status == SLAVE) { 387239991Sed (void)gettimeofday(&ntime, NULL); 3881553Srgrimes electiontime = ntime.tv_sec + delay2; 3891553Srgrimes fastelection = ntime.tv_sec + FASTTOUT; 3901553Srgrimes seq = 0; 3911553Srgrimes if (!good_host_name(msg->tsp_name)) { 3921553Srgrimes syslog(LOG_NOTICE, 3931553Srgrimes "suppress election of %s", 3941553Srgrimes msg->tsp_name); 3951553Srgrimes to.tsp_type = TSP_QUIT; 3961553Srgrimes electiontime = fastelection; 3971553Srgrimes } else if (cadr.s_addr != from.sin_addr.s_addr 3981553Srgrimes && ntime.tv_sec < refusetime) { 3991553Srgrimes/* if the candidate has to repeat itself, the old code would refuse it 4001553Srgrimes * the second time. That would prevent elections. 4011553Srgrimes */ 4021553Srgrimes to.tsp_type = TSP_REFUSE; 4031553Srgrimes } else { 4041553Srgrimes cadr.s_addr = from.sin_addr.s_addr; 4051553Srgrimes to.tsp_type = TSP_ACCEPT; 4061553Srgrimes refusetime = ntime.tv_sec + 30; 4071553Srgrimes } 4081553Srgrimes taddr = from; 40930830Scharnier (void)strcpy(tname, msg->tsp_name); 41030830Scharnier (void)strcpy(to.tsp_name, hostname); 4111553Srgrimes answerdelay(); 4121553Srgrimes if (!acksend(&to, &taddr, tname, 4131553Srgrimes TSP_ACK, 0, 0)) 4141553Srgrimes syslog(LOG_WARNING, 4151553Srgrimes "no answer from candidate %s\n", 4161553Srgrimes tname); 4171553Srgrimes 4181553Srgrimes } else { /* fromnet->status == MASTER */ 4191553Srgrimes htp = addmach(msg->tsp_name, &from,fromnet); 4201553Srgrimes to.tsp_type = TSP_QUIT; 42130830Scharnier (void)strcpy(to.tsp_name, hostname); 4221553Srgrimes if (!acksend(&to, &htp->addr, htp->name, 4231553Srgrimes TSP_ACK, 0, htp->noanswer)) { 4241553Srgrimes syslog(LOG_ERR, 4251553Srgrimes "no reply from %s to ELECTION-QUIT", 4261553Srgrimes htp->name); 4271553Srgrimes (void)remmach(htp); 4281553Srgrimes } 4291553Srgrimes } 4301553Srgrimes break; 4311553Srgrimes 4321553Srgrimes case TSP_CONFLICT: 4331553Srgrimes if (fromnet->status != MASTER) 4341553Srgrimes break; 4351553Srgrimes /* 4361553Srgrimes * After a network partition, there can be 4371553Srgrimes * more than one master: the first slave to 4381553Srgrimes * come up will notify here the situation. 4391553Srgrimes */ 44030830Scharnier (void)strcpy(to.tsp_name, hostname); 4411553Srgrimes 4421553Srgrimes /* The other master often gets into the same state, 4431553Srgrimes * with boring results. 4441553Srgrimes */ 4451553Srgrimes ntp = fromnet; /* (acksend() can leave fromnet=0 */ 4461553Srgrimes for (tries = 0; tries < 3; tries++) { 4471553Srgrimes to.tsp_type = TSP_RESOLVE; 4481553Srgrimes answer = acksend(&to, &ntp->dest_addr, 4491553Srgrimes ANYADDR, TSP_MASTERACK, 4501553Srgrimes ntp, 0); 4511553Srgrimes if (answer == NULL) 4521553Srgrimes break; 4531553Srgrimes htp = addmach(answer->tsp_name,&from,ntp); 4541553Srgrimes to.tsp_type = TSP_QUIT; 4551553Srgrimes answer = acksend(&to, &htp->addr, htp->name, 4561553Srgrimes TSP_ACK, 0, htp->noanswer); 4571553Srgrimes if (!answer) { 4581553Srgrimes syslog(LOG_WARNING, 4591553Srgrimes "conflict error: no reply from %s to QUIT", 4601553Srgrimes htp->name); 4611553Srgrimes (void)remmach(htp); 4621553Srgrimes } 4631553Srgrimes } 4641553Srgrimes masterup(ntp); 4651553Srgrimes break; 4661553Srgrimes 4671553Srgrimes case TSP_MSITE: 4681553Srgrimes if (!slavenet) 4691553Srgrimes break; 4701553Srgrimes taddr = from; 4711553Srgrimes to.tsp_type = TSP_MSITEREQ; 4721553Srgrimes to.tsp_vers = TSPVERSION; 4731553Srgrimes to.tsp_seq = 0; 47430830Scharnier (void)strcpy(to.tsp_name, hostname); 4751553Srgrimes answer = acksend(&to, &slavenet->dest_addr, 4761553Srgrimes ANYADDR, TSP_ACK, 4771553Srgrimes slavenet, 0); 4781553Srgrimes if (answer != NULL 4791553Srgrimes && good_host_name(answer->tsp_name)) { 4801553Srgrimes setmaster(answer); 4811553Srgrimes to.tsp_type = TSP_ACK; 48230830Scharnier (void)strcpy(to.tsp_name, answer->tsp_name); 4831553Srgrimes bytenetorder(&to); 4841553Srgrimes if (sendto(sock, (char *)&to, 4851553Srgrimes sizeof(struct tsp), 0, 48630642Scharnier (struct sockaddr*)&taddr, 48730830Scharnier sizeof(taddr)) < 0) { 4881553Srgrimes trace_sendto_err(taddr.sin_addr); 4891553Srgrimes } 4901553Srgrimes } 4911553Srgrimes break; 4921553Srgrimes 4931553Srgrimes case TSP_MSITEREQ: 4941553Srgrimes break; 4951553Srgrimes 4961553Srgrimes case TSP_ACCEPT: 4971553Srgrimes case TSP_REFUSE: 4981553Srgrimes case TSP_RESOLVE: 4991553Srgrimes break; 5001553Srgrimes 5011553Srgrimes case TSP_QUIT: 5021553Srgrimes doquit(msg); /* become a slave */ 5031553Srgrimes break; 5041553Srgrimes 5051553Srgrimes case TSP_TEST: 5061553Srgrimes electiontime = 0; 5071553Srgrimes break; 5081553Srgrimes 5091553Srgrimes case TSP_LOOP: 5101553Srgrimes /* looking for loops of masters */ 5111553Srgrimes if (!(status & MASTER)) 5121553Srgrimes break; 5131553Srgrimes if (fromnet->status == SLAVE) { 5141553Srgrimes if (!strcmp(msg->tsp_name, hostname)) { 5151553Srgrimes /* 5161553Srgrimes * Someone forwarded our message back to 5171553Srgrimes * us. There must be a loop. Tell the 5181553Srgrimes * master of this network to quit. 5191553Srgrimes * 5201553Srgrimes * The other master often gets into 5211553Srgrimes * the same state, with boring results. 5221553Srgrimes */ 5231553Srgrimes ntp = fromnet; 5241553Srgrimes for (tries = 0; tries < 3; tries++) { 5251553Srgrimes to.tsp_type = TSP_RESOLVE; 5261553Srgrimes answer = acksend(&to, &ntp->dest_addr, 5271553Srgrimes ANYADDR, TSP_MASTERACK, 5281553Srgrimes ntp,0); 5291553Srgrimes if (answer == NULL) 5301553Srgrimes break; 5311553Srgrimes taddr = from; 53230830Scharnier (void)strcpy(tname, answer->tsp_name); 5331553Srgrimes to.tsp_type = TSP_QUIT; 53430830Scharnier (void)strcpy(to.tsp_name, hostname); 5351553Srgrimes if (!acksend(&to, &taddr, tname, 5361553Srgrimes TSP_ACK, 0, 1)) { 5371553Srgrimes syslog(LOG_ERR, 5381553Srgrimes "no reply from %s to slave LOOP-QUIT", 5391553Srgrimes tname); 5401553Srgrimes } else { 5411553Srgrimes electiontime = 0; 5421553Srgrimes } 5431553Srgrimes } 544239991Sed (void)gettimeofday(&ntime, NULL); 5451553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 5461553Srgrimes } else { 5471553Srgrimes if (msg->tsp_hopcnt-- < 1) 5481553Srgrimes break; 5491553Srgrimes bytenetorder(msg); 550299707Spfg for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 5511553Srgrimes if (ntp->status == MASTER 5521553Srgrimes && 0 > sendto(sock, (char *)msg, 5531553Srgrimes sizeof(struct tsp), 0, 5541553Srgrimes (struct sockaddr*)&ntp->dest_addr, 5551553Srgrimes sizeof(ntp->dest_addr))) 5561553Srgrimes trace_sendto_err(ntp->dest_addr.sin_addr); 5571553Srgrimes } 5581553Srgrimes } 5591553Srgrimes } else { /* fromnet->status == MASTER */ 5601553Srgrimes /* 5611553Srgrimes * We should not have received this from a net 5621553Srgrimes * we are master on. There must be two masters, 5631553Srgrimes * unless the packet was really from us. 5641553Srgrimes */ 5651553Srgrimes if (from.sin_addr.s_addr 5661553Srgrimes == fromnet->my_addr.s_addr) { 5671553Srgrimes if (trace) 5681553Srgrimes fprintf(fd,"discarding forwarded LOOP\n"); 5691553Srgrimes break; 5701553Srgrimes } 5711553Srgrimes 5721553Srgrimes /* 5731553Srgrimes * The other master often gets into the same 5741553Srgrimes * state, with boring results. 5751553Srgrimes */ 5761553Srgrimes ntp = fromnet; 5771553Srgrimes for (tries = 0; tries < 3; tries++) { 5781553Srgrimes to.tsp_type = TSP_RESOLVE; 5791553Srgrimes answer = acksend(&to, &ntp->dest_addr, 5801553Srgrimes ANYADDR, TSP_MASTERACK, 5811553Srgrimes ntp,0); 5821553Srgrimes if (!answer) 5831553Srgrimes break; 5841553Srgrimes htp = addmach(answer->tsp_name, 5851553Srgrimes &from,ntp); 5861553Srgrimes to.tsp_type = TSP_QUIT; 58730830Scharnier (void)strcpy(to.tsp_name, hostname); 5881553Srgrimes if (!acksend(&to,&htp->addr,htp->name, 5891553Srgrimes TSP_ACK, 0, htp->noanswer)) { 5901553Srgrimes syslog(LOG_ERR, 5911553Srgrimes "no reply from %s to master LOOP-QUIT", 5921553Srgrimes htp->name); 5931553Srgrimes (void)remmach(htp); 5941553Srgrimes } 5951553Srgrimes } 596239991Sed (void)gettimeofday(&ntime, NULL); 5971553Srgrimes looptime = ntime.tv_sec + FASTTOUT; 5981553Srgrimes } 5991553Srgrimes break; 6001553Srgrimes default: 6011553Srgrimes if (trace) { 6021553Srgrimes fprintf(fd, "garbage message: "); 6031553Srgrimes print(msg, &from); 6041553Srgrimes } 6051553Srgrimes break; 6061553Srgrimes } 6071553Srgrimes } 6081553Srgrimes goto loop; 6091553Srgrimes} 6101553Srgrimes 6111553Srgrimes 6121553Srgrimes/* 6131553Srgrimes * tell the world who our master is 6141553Srgrimes */ 6151553Srgrimesstatic void 616246209Scharniersetmaster(struct tsp *msg) 6171553Srgrimes{ 6181553Srgrimes if (slavenet 6191553Srgrimes && (slavenet != old_slavenet 6201553Srgrimes || strcmp(msg->tsp_name, master_name) 6211553Srgrimes || old_status != status)) { 62230830Scharnier (void)strcpy(master_name, msg->tsp_name); 6231553Srgrimes old_slavenet = slavenet; 6241553Srgrimes old_status = status; 6251553Srgrimes 6261553Srgrimes if (status & MASTER) { 6271553Srgrimes syslog(LOG_NOTICE, "submaster to %s", master_name); 6281553Srgrimes if (trace) 6291553Srgrimes fprintf(fd, "submaster to %s\n", master_name); 6301553Srgrimes 6311553Srgrimes } else { 6321553Srgrimes syslog(LOG_NOTICE, "slave to %s", master_name); 6331553Srgrimes if (trace) 6341553Srgrimes fprintf(fd, "slave to %s\n", master_name); 6351553Srgrimes } 6361553Srgrimes } 6371553Srgrimes} 6381553Srgrimes 6391553Srgrimes 6401553Srgrimes 6411553Srgrimes/* 6421553Srgrimes * handle date change request on a slave 6431553Srgrimes */ 6441553Srgrimesstatic void 645246209Scharnierschgdate(struct tsp *msg, char *newdate) 6461553Srgrimes{ 6471553Srgrimes struct tsp to; 6481553Srgrimes u_short seq; 6491553Srgrimes struct sockaddr_in taddr; 6501553Srgrimes struct timeval otime; 6511553Srgrimes 6521553Srgrimes if (!slavenet) 6531553Srgrimes return; /* no where to forward */ 6541553Srgrimes 6551553Srgrimes taddr = from; 6561553Srgrimes seq = msg->tsp_seq; 6571553Srgrimes 6581553Srgrimes syslog(LOG_INFO, 6591553Srgrimes "forwarding date change by %s to %s", 6601553Srgrimes msg->tsp_name, newdate); 6611553Srgrimes 6621553Srgrimes /* adjust time for residence on the queue */ 663239991Sed (void)gettimeofday(&otime, NULL); 6641553Srgrimes adj_msg_time(msg, &otime); 6651553Srgrimes 6661553Srgrimes to.tsp_type = TSP_SETDATEREQ; 6671553Srgrimes to.tsp_time = msg->tsp_time; 66830830Scharnier (void)strcpy(to.tsp_name, hostname); 6691553Srgrimes if (!acksend(&to, &slavenet->dest_addr, 6701553Srgrimes ANYADDR, TSP_DATEACK, 6711553Srgrimes slavenet, 0)) 6721553Srgrimes return; /* no answer */ 6731553Srgrimes 6741553Srgrimes xmit(TSP_DATEACK, seq, &taddr); 6751553Srgrimes} 6761553Srgrimes 6771553Srgrimes 6781553Srgrimes/* 6791553Srgrimes * Used before answering a broadcast message to avoid network 6801553Srgrimes * contention and likely collisions. 6811553Srgrimes */ 6821553Srgrimesstatic void 683246209Scharnieranswerdelay(void) 6841553Srgrimes{ 6851553Srgrimes struct timeval timeout; 6861553Srgrimes 6871553Srgrimes timeout.tv_sec = 0; 6881553Srgrimes timeout.tv_usec = delay1; 6891553Srgrimes 6901553Srgrimes (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, 6911553Srgrimes &timeout); 6921553Srgrimes return; 6931553Srgrimes} 694