Ejemplo n.º 1
0
static int findHTTPhost(struct sockaddr_in *addr, char *hostname, int port) {
    struct servent *servent;
    int ret;

    pthread_mutex_lock(&host_lock);
    memset(addr,0,sizeof(*addr));
    addr->sin_family = AF_INET;
    if ( port>=0 )
	addr->sin_port = htons(port);
    else if (( servent = getservbyname("http","tcp"))!=NULL )
	addr->sin_port = servent->s_port;	/* Already in server byteorder */
    else
	addr->sin_port = htons(80);
    endservent();
    ret = findhost(addr,hostname);
    pthread_mutex_unlock(&host_lock);
return( ret );
}
Ejemplo n.º 2
0
int getto(const stralloc *sa)
	/* find list address in line. If found, return 1, else return 0. */
{
  unsigned int pos = 0;
  unsigned int pos1;

  if (!sa->len) return 0;		/* no To: or Cc: line */
  while ((pos += 1 + byte_chr(sa->s+pos+1,sa->len-pos-1,'@')) != sa->len) {
    pos1 = findhost(sa,pos);
    if (pos1 == pos) break;
    if (pos1 + outhost.len <= sa->len)
      if (!case_diffb(sa->s+pos1,outhost.len,outhost.s)) { /* got host */
        pos1 = findlocal(sa,pos);
        if (pos1 == pos) break;
        ++pos1;				/* avoids 1 x 2 below */
        if (pos1 >= outlocal.len)
        if (!case_diffb(sa->s+pos1-outlocal.len,outlocal.len,outlocal.s))
          return 1;			/* got local as well */
     }
  }
  return 0;
}
Ejemplo n.º 3
0
int dofsck(void *source, int cargc, char **cargv) {
  int i,j;
  nick *sender=source, *np, *np2;
  host *hp;
  realname *rnp;
  unsigned int nickmarker;
  int errors=0;
  unsigned int nummask,mnum;

  /* Start off with strict nick consistency checks.. */

  controlreply(sender,"- Performing nickname checks"); 

  nickmarker=nextnickmarker();

  for(i=0;i<HOSTHASHSIZE;i++)
    for(hp=hosttable[i];hp;hp=hp->next)
      hp->marker=0;
  
  for(i=0;i<REALNAMEHASHSIZE;i++)
    for(rnp=realnametable[i];rnp;rnp=rnp->next)
      rnp->marker=0;

  controlreply(sender," - Scanning nick hash table");
  
  for (i=0;i<NICKHASHSIZE;i++) {
    for(np=nicktable[i];np;np=np->next) {
      if (np->marker==nickmarker) {
        controlreply(sender, "ERROR: bumped into the same nick %s/%s twice in hash table.",longtonumeric(np->numeric,5),np->nick);
        errors++;
      }
      
      /* Mark this nick so we can check we found them all */
      np->marker=nickmarker;

      /* Check that we can find this nick with the lookup functions */
      if (getnickbynick(np->nick) != np) {
	controlreply(sender, "ERROR: can't find %s/%s using getnickbynick().",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      if (getnickbynumeric(np->numeric) != np) {
	controlreply(sender, "ERROR: can't find %s/%s using getnickbynumeric().",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      /* Check that the nick appears in the list of nicks using its host */
      if (findhost(np->host->name->content) != np->host) {
	controlreply(sender, "ERROR: can't find %s/%s's host (%s) using findhost().",
		     longtonumeric(np->numeric,5),np->nick,np->host->name->content);
	errors++;
      }

      for(np2=np->host->nicks;np2;np2=np2->nextbyhost)
	if (np2==np)
	  break;

      if (!np2) {
	controlreply(sender, "ERROR: can't find %s/%s (host=%s) on the host users list.",
		     longtonumeric(np->numeric,5),np->nick,np->host->name->content);
	errors++;
      }

      np->host->marker++;

      /* Same for realnames */
      if (findrealname(np->realname->name->content) != np->realname) {
	controlreply(sender, "ERROR: can't find %s/%s's realname (%s) using findrealname().",
		     longtonumeric(np->numeric,5),np->nick,np->realname->name->content);
	errors++;
      }

      for(np2=np->realname->nicks;np2;np2=np2->nextbyrealname)
	if (np2==np)
	  break;

      if (!np2) {
	controlreply(sender, 
		     "ERROR: can't find %s/%s (realname=%s) on the realname users list.",
		     longtonumeric(np->numeric,5),np->nick,np->realname->name->content);
	errors++;
      }

      np->realname->marker++;

      if (IsAccount(np) && !np->authname[0]) {
	controlreply(sender, "ERROR: nick %s/%s is +r but no authname stored.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

/*
      if (!IsAccount(np) && np->authname[0]) {
	controlreply(sender, "ERROR: nick %s/%s is -r but carries authname '%s'.",
		     longtonumeric(np->numeric,5),np->nick,np->authname);
	errors++;
      }
*/

      if (IsSetHost(np) && (!np->sethost || !np->shident)) {
	controlreply(sender, "ERROR: nick %s/%s is +h but nick or hostname not set.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

      if (!IsSetHost(np) && (np->sethost || np->shident)) {
	controlreply(sender, "ERROR: nick %s/%s is -h but has nick or hostname set.",
		     longtonumeric(np->numeric,5),np->nick);
	errors++;
      }

    }
  }

  controlreply(sender," - Scanning server user tables");
      
  for(i=0;i<MAXSERVERS;i++) {
    if (serverlist[i].linkstate != LS_INVALID) {
      nummask=((MAXSERVERS-1)<<18) | serverlist[i].maxusernum;
      for (j=0;j<=serverlist[i].maxusernum;j++) {
	if ((np=servernicks[i][j])) {
	  mnum=(i<<18) | j;
	  if ((np->numeric & nummask) != mnum) {
	    controlreply(sender, "ERROR: nick %s/%s has wrong masked numeric.",longtonumeric(np->numeric,5),np->nick);
	    errors++;
          }
	  if (np->marker != nickmarker) {
	    controlreply(sender, "ERROR: nick %s/%s in server user table but not hash!",
			 longtonumeric(np->numeric,5),np->nick);
	    errors++;
	  }
	  np->marker=0;
	}
      }
    }
  }

  controlreply(sender," - Scanning host and realname tables");
  
  for (i=0;i<HOSTHASHSIZE;i++) {
    for (hp=hosttable[i];hp;hp=hp->next) {

      /* Check that the user counts match up */
      if (hp->clonecount != hp->marker) {
	controlreply(sender,
		     "ERROR: host %s has inconsistent clone count (stored=%d, measured=%u)",
		     hp->name->content,hp->clonecount,hp->marker);
	errors++;
      }
      
      for (np=hp->nicks;np;np=np->nextbyhost) {
	if (np->host != hp) {
	  controlreply(sender, 
		       "ERROR: nick %s/%s is in list for wrong host "
		       "(in list for %s, actual host %s).",
		       longtonumeric(np->numeric,5),np->nick,hp->name->content,
		       np->host->name->content);
	  errors++;
	}
      }
      
      hp->marker=0;
    }
  }

  for (i=0;i<REALNAMEHASHSIZE;i++) {
    for (rnp=realnametable[i];rnp;rnp=rnp->next) {
      if (rnp->usercount != rnp->marker) {
	controlreply(sender,
		     "ERROR: realname '%s' has inconsistent clone count "
		     "(stored=%d, measured=%d).",
		     rnp->name->content,rnp->usercount,rnp->marker);
	errors++;
      }

      for (np=rnp->nicks;np;np=np->nextbyrealname) {
	if (np->realname != rnp) {
	  controlreply(sender, 
		       "ERROR: nick %s/%s is in list for wrong realname "
		       "(in list for '%s', actual realname '%s').",
		       longtonumeric(np->numeric,5),np->nick,
		       rnp->name->content, np->realname->name->content);
	  errors++;
	}
      }
      
      rnp->marker=0;
    }
  }

  if (errors) 
    controlreply(sender,"All checks complete. %d errors found.",errors);
  else 
    controlreply(sender,"All checks complete. No errors found.");

  return CMD_OK;
}
Ejemplo n.º 4
0
int
slave()
{
	int tries;
	long electiontime, refusetime, looktime, looptime, adjtime;
	u_short seq;
	long fastelection;
#define FASTTOUT 3
	struct in_addr cadr;
	struct timeval otime;
	struct sockaddr_in taddr;
	char tname[MAXHOSTNAMELEN];
	struct tsp *msg, to;
	struct timeval ntime, wait, tmptv;
	time_t tsp_time_sec;
	struct tsp *answer;
	int timeout();
	char olddate[32];
	char newdate[32];
	struct netinfo *ntp;
	struct hosttbl *htp;
	struct utmpx utx;


	old_slavenet = 0;
	seq = 0;
	refusetime = 0;
	adjtime = 0;

	(void)gettimeofday(&ntime, NULL);
	electiontime = ntime.tv_sec + delay2;
	fastelection = ntime.tv_sec + FASTTOUT;
	if (justquit)
		looktime = electiontime;
	else
		looktime = fastelection;
	looptime = fastelection;

	if (slavenet)
		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
	if (status & MASTER) {
		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
			if (ntp->status == MASTER)
				masterup(ntp);
		}
	}

loop:
	get_goodgroup(0);
	(void)gettimeofday(&ntime, NULL);
	if (ntime.tv_sec > electiontime) {
		if (trace)
			fprintf(fd, "election timer expired\n");
		longjmp(jmpenv, 1);
	}

	if (ntime.tv_sec >= looktime) {
		if (trace)
			fprintf(fd, "Looking for nets to master\n");

		if (Mflag && nignorednets > 0) {
			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
				if (ntp->status == IGNORE
				    || ntp->status == NOMASTER) {
					lookformaster(ntp);
					if (ntp->status == MASTER) {
						masterup(ntp);
					} else if (ntp->status == MASTER) {
						ntp->status = NOMASTER;
					}
				}
				if (ntp->status == MASTER
				    && --ntp->quit_count < 0)
					ntp->quit_count = 0;
			}
			makeslave(slavenet);	/* prune extras */
			setstatus();
		}
		(void)gettimeofday(&ntime, NULL);
		looktime = ntime.tv_sec + delay2;
	}
	if (ntime.tv_sec >= looptime) {
		if (trace)
			fprintf(fd, "Looking for loops\n");
		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
		    if (ntp->status == MASTER) {
			to.tsp_type = TSP_LOOP;
			to.tsp_vers = TSPVERSION;
			to.tsp_seq = sequence++;
			to.tsp_hopcnt = MAX_HOPCNT;
			(void)strcpy(to.tsp_name, hostname);
			bytenetorder(&to);
			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
				   (struct sockaddr*)&ntp->dest_addr,
				   sizeof(ntp->dest_addr)) < 0) {
				trace_sendto_err(ntp->dest_addr.sin_addr);
			}
		    }
		}
		(void)gettimeofday(&ntime, NULL);
		looptime = ntime.tv_sec + delay2;
	}

	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
	if (wait.tv_sec < 0)
		wait.tv_sec = 0;
	wait.tv_sec += FASTTOUT;
	wait.tv_usec = 0;
	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);

	if (msg != NULL) {
		/*
		 * filter stuff not for us
		 */
		switch (msg->tsp_type) {
		case TSP_SETDATE:
		case TSP_TRACEOFF:
		case TSP_TRACEON:
			/*
			 * XXX check to see they are from ourself
			 */
			break;

		case TSP_TEST:
		case TSP_MSITE:
			break;

		case TSP_MASTERUP:
			if (!fromnet) {
				if (trace) {
					fprintf(fd, "slave ignored: ");
					print(msg, &from);
				}
				goto loop;
			}
			break;

		default:
			if (!fromnet
			    || fromnet->status == IGNORE
			    || fromnet->status == NOMASTER) {
				if (trace) {
					fprintf(fd, "slave ignored: ");
					print(msg, &from);
				}
				goto loop;
			}
			break;
		}


		/*
		 * now process the message
		 */
		switch (msg->tsp_type) {

		case TSP_ADJTIME:
			if (fromnet != slavenet)
				break;
			if (!good_host_name(msg->tsp_name)) {
				syslog(LOG_NOTICE,
				   "attempted time adjustment by %s",
				       msg->tsp_name);
				suppress(&from, msg->tsp_name, fromnet);
				break;
			}
			/*
			 * Speed up loop detection in case we have a loop.
			 * Otherwise the clocks can race until the loop
			 * is found.
			 */
			(void)gettimeofday(&otime, NULL);
			if (adjtime < otime.tv_sec)
				looptime -= (looptime-otime.tv_sec)/2 + 1;

			setmaster(msg);
			if (seq != msg->tsp_seq) {
				seq = msg->tsp_seq;
				synch(tvtomsround(msg->tsp_time));
			}
			(void)gettimeofday(&ntime, NULL);
			electiontime = ntime.tv_sec + delay2;
			fastelection = ntime.tv_sec + FASTTOUT;
			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
			break;

		case TSP_SETTIME:
			if (fromnet != slavenet)
				break;
			if (seq == msg->tsp_seq)
				break;
			seq = msg->tsp_seq;

			/* adjust time for residence on the queue */
			(void)gettimeofday(&otime, NULL);
			adj_msg_time(msg,&otime);
			/*
			 * the following line is necessary due to syslog
			 * calling ctime() which clobbers the static buffer
			 */
			(void)strcpy(olddate, date());
			tsp_time_sec = msg->tsp_time.tv_sec;
			(void)strcpy(newdate, ctime(&tsp_time_sec));

			if (!good_host_name(msg->tsp_name)) {
				syslog(LOG_NOTICE,
			    "attempted time setting by untrusted %s to %s",
				       msg->tsp_name, newdate);
				suppress(&from, msg->tsp_name, fromnet);
				break;
			}

			setmaster(msg);
 			tmptv.tv_sec = msg->tsp_time.tv_sec;
 			tmptv.tv_usec = msg->tsp_time.tv_usec;
			timevalsub(&ntime, &tmptv, &otime);
			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
				/*
				 * do not change the clock if we can adjust it
				 */
				synch(tvtomsround(ntime));
			} else {
				utx.ut_type = OLD_TIME;
				gettimeofday(&utx.ut_tv, NULL);
				pututxline(&utx);
				(void)settimeofday(&tmptv, 0);
				utx.ut_type = NEW_TIME;
				gettimeofday(&utx.ut_tv, NULL);
				pututxline(&utx);
				syslog(LOG_NOTICE,
				       "date changed by %s from %s",
					msg->tsp_name, olddate);
				if (status & MASTER)
					spreadtime();
			}
			(void)gettimeofday(&ntime, NULL);
			electiontime = ntime.tv_sec + delay2;
			fastelection = ntime.tv_sec + FASTTOUT;

/* This patches a bad protocol bug.  Imagine a system with several networks,
 * where there are a pair of redundant gateways between a pair of networks,
 * each running timed.  Assume that we start with a third machine mastering
 * one of the networks, and one of the gateways mastering the other.
 * Imagine that the third machine goes away and the non-master gateway
 * decides to replace it.  If things are timed just 'right,' we will have
 * each gateway mastering one network for a little while.  If a SETTIME
 * message gets into the network at that time, perhaps from the newly
 * masterful gateway as it was taking control, the SETTIME will loop
 * forever.  Each time a gateway receives it on its slave side, it will
 * call spreadtime to forward it on its mastered network.  We are now in
 * a permanent loop, since the SETTIME msgs will keep any clock
 * in the network from advancing.  Normally, the 'LOOP' stuff will detect
 * and correct the situation.  However, with the clocks stopped, the
 * 'looptime' timer cannot expire.  While they are in this state, the
 * masters will try to saturate the network with SETTIME packets.
 */
			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
			break;

		case TSP_MASTERUP:
			if (slavenet && fromnet != slavenet)
				break;
			if (!good_host_name(msg->tsp_name)) {
				suppress(&from, msg->tsp_name, fromnet);
				if (electiontime > fastelection)
					electiontime = fastelection;
				break;
			}
			makeslave(fromnet);
			setmaster(msg);
			setstatus();
			answerdelay();
			xmit(TSP_SLAVEUP, 0, &from);
			(void)gettimeofday(&ntime, NULL);
			electiontime = ntime.tv_sec + delay2;
			fastelection = ntime.tv_sec + FASTTOUT;
			refusetime = 0;
			break;

		case TSP_MASTERREQ:
			if (fromnet->status != SLAVE)
				break;
			(void)gettimeofday(&ntime, NULL);
			electiontime = ntime.tv_sec + delay2;
			break;

		case TSP_SETDATE:
			tsp_time_sec = msg->tsp_time.tv_sec;
			(void)strcpy(newdate, ctime(&tsp_time_sec));
			schgdate(msg, newdate);
			break;

		case TSP_SETDATEREQ:
			if (fromnet->status != MASTER)
				break;
			tsp_time_sec = msg->tsp_time.tv_sec;
			(void)strcpy(newdate, ctime(&tsp_time_sec));
			htp = findhost(msg->tsp_name);
			if (0 == htp) {
				syslog(LOG_WARNING,
				       "DATEREQ from uncontrolled machine");
				break;
			}
			if (!htp->good) {
				syslog(LOG_WARNING,
				"attempted date change by untrusted %s to %s",
				       htp->name, newdate);
				spreadtime();
				break;
			}
			schgdate(msg, newdate);
			break;

		case TSP_TRACEON:
			traceon();
			break;

		case TSP_TRACEOFF:
			traceoff("Tracing ended at %s\n");
			break;

		case TSP_SLAVEUP:
			newslave(msg);
			break;

		case TSP_ELECTION:
			if (fromnet->status == SLAVE) {
				(void)gettimeofday(&ntime, NULL);
				electiontime = ntime.tv_sec + delay2;
				fastelection = ntime.tv_sec + FASTTOUT;
				seq = 0;
				if (!good_host_name(msg->tsp_name)) {
					syslog(LOG_NOTICE,
					       "suppress election of %s",
					       msg->tsp_name);
					to.tsp_type = TSP_QUIT;
					electiontime = fastelection;
				} else if (cadr.s_addr != from.sin_addr.s_addr
					   && ntime.tv_sec < refusetime) {
/* if the candidate has to repeat itself, the old code would refuse it
 * the second time.  That would prevent elections.
 */
					to.tsp_type = TSP_REFUSE;
				} else {
					cadr.s_addr = from.sin_addr.s_addr;
					to.tsp_type = TSP_ACCEPT;
					refusetime = ntime.tv_sec + 30;
				}
				taddr = from;
				(void)strcpy(tname, msg->tsp_name);
				(void)strcpy(to.tsp_name, hostname);
				answerdelay();
				if (!acksend(&to, &taddr, tname,
					     TSP_ACK, 0, 0))
					syslog(LOG_WARNING,
					     "no answer from candidate %s\n",
					       tname);

			} else {	/* fromnet->status == MASTER */
				htp = addmach(msg->tsp_name, &from,fromnet);
				to.tsp_type = TSP_QUIT;
				(void)strcpy(to.tsp_name, hostname);
				if (!acksend(&to, &htp->addr, htp->name,
					     TSP_ACK, 0, htp->noanswer)) {
					syslog(LOG_ERR,
					  "no reply from %s to ELECTION-QUIT",
					       htp->name);
					(void)remmach(htp);
				}
			}
			break;

		case TSP_CONFLICT:
			if (fromnet->status != MASTER)
				break;
			/*
			 * After a network partition, there can be
			 * more than one master: the first slave to
			 * come up will notify here the situation.
			 */
			(void)strcpy(to.tsp_name, hostname);

			/* The other master often gets into the same state,
			 * with boring results.
			 */
			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
			for (tries = 0; tries < 3; tries++) {
				to.tsp_type = TSP_RESOLVE;
				answer = acksend(&to, &ntp->dest_addr,
						 ANYADDR, TSP_MASTERACK,
						 ntp, 0);
				if (answer == NULL)
					break;
				htp = addmach(answer->tsp_name,&from,ntp);
				to.tsp_type = TSP_QUIT;
				answer = acksend(&to, &htp->addr, htp->name,
						 TSP_ACK, 0, htp->noanswer);
				if (!answer) {
					syslog(LOG_WARNING,
				  "conflict error: no reply from %s to QUIT",
						htp->name);
					(void)remmach(htp);
				}
			}
			masterup(ntp);
			break;

		case TSP_MSITE:
			if (!slavenet)
				break;
			taddr = from;
			to.tsp_type = TSP_MSITEREQ;
			to.tsp_vers = TSPVERSION;
			to.tsp_seq = 0;
			(void)strcpy(to.tsp_name, hostname);
			answer = acksend(&to, &slavenet->dest_addr,
					 ANYADDR, TSP_ACK,
					 slavenet, 0);
			if (answer != NULL
			    && good_host_name(answer->tsp_name)) {
				setmaster(answer);
				to.tsp_type = TSP_ACK;
				(void)strcpy(to.tsp_name, answer->tsp_name);
				bytenetorder(&to);
				if (sendto(sock, (char *)&to,
					   sizeof(struct tsp), 0,
					   (struct sockaddr*)&taddr,
					   sizeof(taddr)) < 0) {
					trace_sendto_err(taddr.sin_addr);
				}
			}
			break;

		case TSP_MSITEREQ:
			break;

		case TSP_ACCEPT:
		case TSP_REFUSE:
		case TSP_RESOLVE:
			break;

		case TSP_QUIT:
			doquit(msg);		/* become a slave */
			break;

		case TSP_TEST:
			electiontime = 0;
			break;

		case TSP_LOOP:
			/* looking for loops of masters */
			if (!(status & MASTER))
				break;
			if (fromnet->status == SLAVE) {
			    if (!strcmp(msg->tsp_name, hostname)) {
				/*
				 * Someone forwarded our message back to
				 * us.  There must be a loop.  Tell the
				 * master of this network to quit.
				 *
				 * The other master often gets into
				 * the same state, with boring results.
				 */
				ntp = fromnet;
				for (tries = 0; tries < 3; tries++) {
				    to.tsp_type = TSP_RESOLVE;
				    answer = acksend(&to, &ntp->dest_addr,
						     ANYADDR, TSP_MASTERACK,
						     ntp,0);
				    if (answer == NULL)
					break;
				    taddr = from;
				    (void)strcpy(tname, answer->tsp_name);
				    to.tsp_type = TSP_QUIT;
				    (void)strcpy(to.tsp_name, hostname);
				    if (!acksend(&to, &taddr, tname,
						 TSP_ACK, 0, 1)) {
					syslog(LOG_ERR,
					"no reply from %s to slave LOOP-QUIT",
						 tname);
				    } else {
					electiontime = 0;
				    }
				}
				(void)gettimeofday(&ntime, NULL);
				looptime = ntime.tv_sec + FASTTOUT;
			    } else {
				if (msg->tsp_hopcnt-- < 1)
				    break;
				bytenetorder(msg);
				for (ntp = nettab; ntp != 0; ntp = ntp->next) {
				    if (ntp->status == MASTER
					&& 0 > sendto(sock, (char *)msg,
						      sizeof(struct tsp), 0,
					      (struct sockaddr*)&ntp->dest_addr,
						      sizeof(ntp->dest_addr)))
				    trace_sendto_err(ntp->dest_addr.sin_addr);
				}
			    }
			} else {	/* fromnet->status == MASTER */
			    /*
			     * We should not have received this from a net
			     * we are master on.  There must be two masters,
			     * unless the packet was really from us.
			     */
			    if (from.sin_addr.s_addr
				== fromnet->my_addr.s_addr) {
				if (trace)
				    fprintf(fd,"discarding forwarded LOOP\n");
				break;
			    }

			    /*
			     * The other master often gets into the same
			     * state, with boring results.
			     */
			    ntp = fromnet;
			    for (tries = 0; tries < 3; tries++) {
				to.tsp_type = TSP_RESOLVE;
				answer = acksend(&to, &ntp->dest_addr,
						 ANYADDR, TSP_MASTERACK,
						ntp,0);
				if (!answer)
					break;
				htp = addmach(answer->tsp_name,
					      &from,ntp);
				to.tsp_type = TSP_QUIT;
				(void)strcpy(to.tsp_name, hostname);
				if (!acksend(&to,&htp->addr,htp->name,
					     TSP_ACK, 0, htp->noanswer)) {
					syslog(LOG_ERR,
				    "no reply from %s to master LOOP-QUIT",
					       htp->name);
					(void)remmach(htp);
				}
			    }
			    (void)gettimeofday(&ntime, NULL);
			    looptime = ntime.tv_sec + FASTTOUT;
			}
			break;
		default:
			if (trace) {
				fprintf(fd, "garbage message: ");
				print(msg, &from);
			}
			break;
		}
	}
	goto loop;
}
Ejemplo n.º 5
0
/*
 * The main function of `master' is to periodically compute the differences
 * (deltas) between its clock and the clocks of the slaves, to compute the
 * network average delta, and to send to the slaves the differences between
 * their individual deltas and the network delta.
 * While waiting, it receives messages from the slaves (i.e. requests for
 * master's name, remote requests to set the network time, ...), and
 * takes the appropriate action.
 */
int
master()
{
	struct hosttbl *htp;
	long pollingtime;
#define POLLRATE 4
	int polls;
	struct timeval wait, ntime;
	time_t tsp_time_sec;
	struct tsp *msg, *answer, to;
	char newdate[32];
	struct sockaddr_in taddr;
	char tname[MAXHOSTNAMELEN];
	struct netinfo *ntp;
	int i;

	syslog(LOG_NOTICE, "This machine is master");
	if (trace)
		fprintf(fd, "This machine is master\n");
	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
		if (ntp->status == MASTER)
			masterup(ntp);
	}
	(void)gettimeofday(&ntime, 0);
	pollingtime = ntime.tv_sec+3;
	if (justquit)
		polls = 0;
	else
		polls = POLLRATE-1;

/* Process all outstanding messages before spending the long time necessary
 *	to update all timers.
 */
loop:
	(void)gettimeofday(&ntime, 0);
	wait.tv_sec = pollingtime - ntime.tv_sec;
	if (wait.tv_sec < 0)
		wait.tv_sec = 0;
	wait.tv_usec = 0;
	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
	if (!msg) {
		(void)gettimeofday(&ntime, 0);
		if (ntime.tv_sec >= pollingtime) {
			pollingtime = ntime.tv_sec + SAMPLEINTVL;
			get_goodgroup(0);

/* If a bogus master told us to quit, we can have decided to ignore a
 * network.  Therefore, periodically try to take over everything.
 */
			polls = (polls + 1) % POLLRATE;
			if (0 == polls && nignorednets > 0) {
				trace_msg("Looking for nets to re-master\n");
				for (ntp = nettab; ntp; ntp = ntp->next) {
					if (ntp->status == IGNORE
					    || ntp->status == NOMASTER) {
						lookformaster(ntp);
						if (ntp->status == MASTER) {
							masterup(ntp);
							polls = POLLRATE-1;
						}
					}
					if (ntp->status == MASTER
					    && --ntp->quit_count < 0)
						ntp->quit_count = 0;
				}
				if (polls != 0)
					setstatus();
			}

			synch(0L);

			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
				to.tsp_type = TSP_LOOP;
				to.tsp_vers = TSPVERSION;
				to.tsp_seq = sequence++;
				to.tsp_hopcnt = MAX_HOPCNT;
				(void)strcpy(to.tsp_name, hostname);
				bytenetorder(&to);
				if (sendto(sock, (char *)&to,
					   sizeof(struct tsp), 0,
					   (struct sockaddr*)&ntp->dest_addr,
					   sizeof(ntp->dest_addr)) < 0) {
				   trace_sendto_err(ntp->dest_addr.sin_addr);
				}
			}
		}


	} else {
		switch (msg->tsp_type) {

		case TSP_MASTERREQ:
			break;

		case TSP_SLAVEUP:
			newslave(msg);
			break;

		case TSP_SETDATE:
			/*
			 * XXX check to see it is from ourself
			 */
			tsp_time_sec = msg->tsp_time.tv_sec;
			(void)strcpy(newdate, ctime(&tsp_time_sec));
			if (!good_host_name(msg->tsp_name)) {
				syslog(LOG_NOTICE,
				       "attempted date change by %s to %s",
				       msg->tsp_name, newdate);
				spreadtime();
				break;
			}

			mchgdate(msg);
			(void)gettimeofday(&ntime, 0);
			pollingtime = ntime.tv_sec + SAMPLEINTVL;
			break;

		case TSP_SETDATEREQ:
			if (!fromnet || fromnet->status != MASTER)
				break;
			tsp_time_sec = msg->tsp_time.tv_sec;
			(void)strcpy(newdate, ctime(&tsp_time_sec));
			htp = findhost(msg->tsp_name);
			if (htp == 0) {
				syslog(LOG_ERR,
				       "attempted SET DATEREQ by uncontrolled %s to %s",
				       msg->tsp_name, newdate);
				break;
			}
			if (htp->seq == msg->tsp_seq)
				break;
			htp->seq = msg->tsp_seq;
			if (!htp->good) {
				syslog(LOG_NOTICE,
				"attempted SET DATEREQ by untrusted %s to %s",
				       msg->tsp_name, newdate);
				spreadtime();
				break;
			}

			mchgdate(msg);
			(void)gettimeofday(&ntime, 0);
			pollingtime = ntime.tv_sec + SAMPLEINTVL;
			break;

		case TSP_MSITE:
			xmit(TSP_ACK, msg->tsp_seq, &from);
			break;

		case TSP_MSITEREQ:
			break;

		case TSP_TRACEON:
			traceon();
			break;

		case TSP_TRACEOFF:
			traceoff("Tracing ended at %s\n");
			break;

		case TSP_ELECTION:
			if (!fromnet)
				break;
			if (fromnet->status == MASTER) {
				pollingtime = 0;
				(void)addmach(msg->tsp_name, &from,fromnet);
			}
			taddr = from;
			(void)strcpy(tname, msg->tsp_name);
			to.tsp_type = TSP_QUIT;
			(void)strcpy(to.tsp_name, hostname);
			answer = acksend(&to, &taddr, tname,
					 TSP_ACK, 0, 1);
			if (answer == NULL) {
				syslog(LOG_ERR, "election error by %s",
				       tname);
			}
			break;

		case TSP_CONFLICT:
			/*
			 * After a network partition, there can be
			 * more than one master: the first slave to
			 * come up will notify here the situation.
			 */
			if (!fromnet || fromnet->status != MASTER)
				break;
			(void)strcpy(to.tsp_name, hostname);

			/* The other master often gets into the same state,
			 * with boring results if we stay at it forever.
			 */
			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
			for (i = 0; i < 3; i++) {
				to.tsp_type = TSP_RESOLVE;
				(void)strcpy(to.tsp_name, hostname);
				answer = acksend(&to, &ntp->dest_addr,
						 ANYADDR, TSP_MASTERACK,
						 ntp, 0);
				if (!answer)
					break;
				htp = addmach(answer->tsp_name,&from,ntp);
				to.tsp_type = TSP_QUIT;
				msg = acksend(&to, &htp->addr, htp->name,
					      TSP_ACK, 0, htp->noanswer);
				if (msg == NULL) {
					syslog(LOG_ERR,
				    "no response from %s to CONFLICT-QUIT",
					       htp->name);
				}
			}
			masterup(ntp);
			pollingtime = 0;
			break;

		case TSP_RESOLVE:
			if (!fromnet || fromnet->status != MASTER)
				break;
			/*
			 * do not want to call synch() while waiting
			 * to be killed!
			 */
			(void)gettimeofday(&ntime, (struct timezone *)0);
			pollingtime = ntime.tv_sec + SAMPLEINTVL;
			break;

		case TSP_QUIT:
			doquit(msg);		/* become a slave */
			break;

		case TSP_LOOP:
			if (!fromnet || fromnet->status != MASTER
			    || !strcmp(msg->tsp_name, hostname))
				break;
			/*
			 * We should not have received this from a net
			 * we are master on.  There must be two masters.
			 */
			htp = addmach(msg->tsp_name, &from,fromnet);
			to.tsp_type = TSP_QUIT;
			(void)strcpy(to.tsp_name, hostname);
			answer = acksend(&to, &htp->addr, htp->name,
					 TSP_ACK, 0, 1);
			if (!answer) {
				syslog(LOG_WARNING,
				"loop breakage: no reply from %s=%s to QUIT",
				    htp->name, inet_ntoa(htp->addr.sin_addr));
				(void)remmach(htp);
			}

		case TSP_TEST:
			if (trace) {
				fprintf(fd,
		"\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
		nnets, nmasternets, nslavenets, nignorednets);
				setstatus();
			}
			pollingtime = 0;
			polls = POLLRATE-1;
			break;

		default:
			if (trace) {
				fprintf(fd, "garbage message: ");
				print(msg, &from);
			}
			break;
		}
	}
	goto loop;
}
Ejemplo n.º 6
0
Archivo: slave.c Proyecto: npe9/sprite
slave()
{
	int length;
	int senddateack;
	long electiontime, refusetime, looktime;
	u_short seq;
	char candidate[MAXHOSTNAMELEN];
	struct tsp *msg, to, *readmsg();
	struct sockaddr_in saveaddr, msaveaddr;
	struct timeval wait;
	struct timeval time, otime;
	struct tsp *answer, *acksend();
	int timeout();
	char *date();
	long casual();
	int bytenetorder();
	char olddate[32];
	struct sockaddr_in server;
	register struct netinfo *ntp;
	int ind;
	struct tsp resp;
	extern int Mflag;
	extern int justquit;
#ifdef MEASURE
	extern FILE *fp;
#endif
	if (slavenet) {
		resp.tsp_type = TSP_SLAVEUP;
		resp.tsp_vers = TSPVERSION;
		(void)strcpy(resp.tsp_name, hostname);
		bytenetorder(&resp);
		if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
		    &slavenet->dest_addr, sizeof(struct sockaddr_in)) < 0) {
			syslog(LOG_ERR, "sendto: %m");
			exit(1);
		}
	}

	if (status & MASTER) {
#ifdef MEASURE
		if (fp == NULL) {
			fp = fopen("/usr/adm/timed.masterlog", "w");
			setlinebuf(fp);
		}
#endif
		syslog(LOG_INFO, "THIS MACHINE IS A SUBMASTER");
		if (trace) {
			fprintf(fd, "THIS MACHINE IS A SUBMASTER\n");
		}
		for (ntp = nettab; ntp != NULL; ntp = ntp->next)
			if (ntp->status == MASTER)
				masterup(ntp);

	} else {
		syslog(LOG_INFO, "THIS MACHINE IS A SLAVE");
		if (trace) {
			fprintf(fd, "THIS MACHINE IS A SLAVE\n");
		}
	}

	seq = 0;
	senddateack = OFF;
	refusetime = 0;

	(void)gettimeofday(&time, (struct timezone *)0);
	electiontime = time.tv_sec + delay2;
	if (Mflag)
		if (justquit)
			looktime = time.tv_sec + delay2;
		else 
			looktime = 1;
	else
		looktime = 0;

loop:
	length = sizeof(struct sockaddr_in);
	(void)gettimeofday(&time, (struct timezone *)0);
	if (time.tv_sec > electiontime) {
		if (trace) 
			fprintf(fd, "election timer expired\n");
		longjmp(jmpenv, 1);
	}
	if (looktime && time.tv_sec > looktime) {
		if (trace) 
			fprintf(fd, "Looking for nets to master and loops\n");
		
		if (nignorednets > 0) {
			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
				if (ntp->status == IGNORE) {
					lookformaster(ntp);
					if (ntp->status == MASTER)
						masterup(ntp);
					else
						ntp->status = IGNORE;
				}
			}
			setstatus();
#ifdef MEASURE
			/*
			 * Check to see if we just became master
			 * (file not open)
			 */
			if (fp == NULL) {
				fp = fopen("/usr/adm/timed.masterlog", "w");
				setlinebuf(fp);
			}
#endif
		}

		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
		    if (ntp->status == MASTER) {
			to.tsp_type = TSP_LOOP;
			to.tsp_vers = TSPVERSION;
			to.tsp_seq = sequence++;
			to.tsp_hopcnt = 10;
			(void)strcpy(to.tsp_name, hostname);
			bytenetorder(&to);
			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
			    &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
				syslog(LOG_ERR, "sendto: %m");
				exit(1);
			}
		    }
		}
		(void)gettimeofday(&time, (struct timezone *)0);
		looktime = time.tv_sec + delay2;
	}
	wait.tv_sec = electiontime - time.tv_sec + 10;
	wait.tv_usec = 0;
	msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
	if (msg != NULL) {
		switch (msg->tsp_type) {
		case TSP_SETDATE:
#ifdef TESTING
		case TSP_TEST:
#endif
		case TSP_MSITE:
		case TSP_TRACEOFF:
		case TSP_TRACEON:
			break;
		case TSP_MASTERUP:
			if (fromnet == NULL) {
				if (trace) {
					fprintf(fd, "slave ignored: ");
					print(msg, &from);
				}
				goto loop;
			}
			break;
		default:
			if (fromnet == NULL || fromnet->status == IGNORE) {
				if (trace) {
					fprintf(fd, "slave ignored: ");
					print(msg, &from);
				}
				goto loop;
			}
			break;
		}

		switch (msg->tsp_type) {

		case TSP_ADJTIME:
			if (fromnet->status != SLAVE)
				break;
			(void)gettimeofday(&time, (struct timezone *)0);
			electiontime = time.tv_sec + delay2;
			if (seq != msg->tsp_seq) {
				seq = msg->tsp_seq;
				if ((status & SUBMASTER) == SUBMASTER) {
					synch((msg->tsp_time.tv_sec * 1000) + 
					    (msg->tsp_time.tv_usec / 1000));
				} else {
					adjclock(&(msg->tsp_time));
				}
			}
			break;
		case TSP_SETTIME:
			if (fromnet->status != SLAVE)
				break;
			if (seq == msg->tsp_seq)
				break;

			seq = msg->tsp_seq;

			(void)strcpy(olddate, date());
			(void)gettimeofday(&otime, (struct timezone *)0);
			(void)settimeofday(&msg->tsp_time,
				(struct timezone *)0);
			syslog(LOG_NOTICE, "date changed by %s from: %s",
				msg->tsp_name, olddate);
			logwtmp(otime, msg->tsp_time);
			if ((status & SUBMASTER) == SUBMASTER)
				spreadtime();
			(void)gettimeofday(&time, (struct timezone *)0);
			electiontime = time.tv_sec + delay2;

			if (senddateack == ON) {
				senddateack = OFF;
				msg->tsp_type = TSP_DATEACK;
				(void)strcpy(msg->tsp_name, hostname);
				bytenetorder(msg);
				length = sizeof(struct sockaddr_in);
				if (sendto(sock, (char *)msg, 
						sizeof(struct tsp), 0,
						&saveaddr, length) < 0) {
					syslog(LOG_ERR, "sendto: %m");
					exit(1);
				}
			}
			break;
		case TSP_MASTERUP:
			if (slavenet && fromnet != slavenet)
				break;
			makeslave(fromnet);
			setstatus();
			msg->tsp_type = TSP_SLAVEUP;
			msg->tsp_vers = TSPVERSION;
			(void)strcpy(msg->tsp_name, hostname);
			bytenetorder(msg);
			answerdelay();
			length = sizeof(struct sockaddr_in);
			if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, 
						&from, length) < 0) {
				syslog(LOG_ERR, "sendto: %m");
				exit(1);
			}
			backoff = 1;
			delay2 = casual((long)MINTOUT, (long)MAXTOUT);
			(void)gettimeofday(&time, (struct timezone *)0);
			electiontime = time.tv_sec + delay2;
			refusetime = 0;
			break;
		case TSP_MASTERREQ:
			if (fromnet->status != SLAVE)
				break;
			(void)gettimeofday(&time, (struct timezone *)0);
			electiontime = time.tv_sec + delay2;
			break;
		case TSP_SETDATE:
			saveaddr = from;
			msg->tsp_type = TSP_SETDATEREQ;
			msg->tsp_vers = TSPVERSION;
			(void)strcpy(msg->tsp_name, hostname);
			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
				if (ntp->status == SLAVE)
					break;
			}
			if (ntp == NULL)
				break;
			answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
			    TSP_DATEACK, ntp);
			if (answer != NULL) {
				msg->tsp_type = TSP_ACK;
				bytenetorder(msg);
				length = sizeof(struct sockaddr_in);
				if (sendto(sock, (char *)msg,
				    sizeof(struct tsp), 0, &saveaddr,
				    length) < 0) {
					syslog(LOG_ERR, "sendto: %m");
					exit(1);
				}
				senddateack = ON;
			}
			break;
		case TSP_SETDATEREQ:
			saveaddr = from;
			if (status != SUBMASTER || fromnet->status != MASTER)
				break;
			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
				if (ntp->status == SLAVE)
					break;
			}
			ind = findhost(msg->tsp_name);
			if (ind < 0) {
			    syslog(LOG_WARNING,
				"DATEREQ from uncontrolled machine");
			    break;
			}
			syslog(LOG_DEBUG,
			    "forwarding date change request for %s",
			    msg->tsp_name);
			(void)strcpy(msg->tsp_name, hostname);
			answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
			    TSP_DATEACK, ntp);
			if (answer != NULL) {
				msg->tsp_type = TSP_DATEACK;
				bytenetorder(msg);
				length = sizeof(struct sockaddr_in);
				if (sendto(sock, (char *)msg,
				    sizeof(struct tsp), 0, &saveaddr,
				    length) < 0) {
					syslog(LOG_ERR, "sendto: %m");
					exit(1);
				}
			}
			break;
		case TSP_TRACEON:
			if (!(trace)) {
				fd = fopen(tracefile, "w");
				setlinebuf(fd);
				fprintf(fd, "Tracing started on: %s\n\n", 
								date());
			}
			trace = ON;
			break;
		case TSP_TRACEOFF:
			if (trace) {
				fprintf(fd, "Tracing ended on: %s\n", date());
				(void)fclose(fd);
			}
#ifdef GPROF
			moncontrol(0);
			_mcleanup();
			moncontrol(1);
#endif
			trace = OFF;
			break;
		case TSP_SLAVEUP:
			if ((status & MASTER) && fromnet->status == MASTER) {
				ind = addmach(msg->tsp_name, &from);
				newslave(ind, msg->tsp_seq);
			}
			break;
		case TSP_ELECTION:
			if (fromnet->status == SLAVE) {
				(void)gettimeofday(&time, (struct timezone *)0);
				electiontime = time.tv_sec + delay2;
				seq = 0;            /* reset sequence number */
				if (time.tv_sec < refusetime)
					msg->tsp_type = TSP_REFUSE;
				else {
					msg->tsp_type = TSP_ACCEPT;
					refusetime = time.tv_sec + 30;
				}
				(void)strcpy(candidate, msg->tsp_name);
				(void)strcpy(msg->tsp_name, hostname);
				answerdelay();
				server = from;
				answer = acksend(msg, &server, candidate, TSP_ACK,
				    (struct netinfo *)NULL);
				if (answer == NULL)
					syslog(LOG_WARNING,
					   "no answer from master candidate\n");
			} else {	/* fromnet->status == MASTER */
				to.tsp_type = TSP_QUIT;
				(void)strcpy(to.tsp_name, hostname);
				server = from;
				answer = acksend(&to, &server, msg->tsp_name,
				    TSP_ACK, (struct netinfo *)NULL);
				if (answer == NULL) {
					syslog(LOG_WARNING,
					    "election error: no reply to QUIT");
				} else {
					(void) addmach(msg->tsp_name, &from);
				}
			}
			break;
                case TSP_CONFLICT:
			if (fromnet->status != MASTER)
				break;
                        /*
                         * After a network partition, there can be
                         * more than one master: the first slave to
                         * come up will notify here the situation.
                         */
                        (void)strcpy(to.tsp_name, hostname);

                        if (fromnet == NULL)
                                break;
                        for(;;) {
                                to.tsp_type = TSP_RESOLVE;
                                answer = acksend(&to, &fromnet->dest_addr,
                                    (char *)ANYADDR, TSP_MASTERACK, fromnet);
                                if (answer == NULL)
                                        break;
                                to.tsp_type = TSP_QUIT;
                                server = from;
                                msg = acksend(&to, &server, answer->tsp_name,
                                    TSP_ACK, (struct netinfo *)NULL);
                                if (msg == NULL) {
                                        syslog(LOG_WARNING,
					    "conflict error: no reply to QUIT");
				} else {
                                        (void) addmach(answer->tsp_name, &from);
				}
                        }
                        masterup(fromnet);
                        break;
		case TSP_MSITE:
			if (!slavenet)
				break;
			msaveaddr = from;
			msg->tsp_type = TSP_MSITEREQ;
			msg->tsp_vers = TSPVERSION;
			(void)strcpy(msg->tsp_name, hostname);
			answer = acksend(msg, &slavenet->dest_addr,
					 (char *)ANYADDR, TSP_ACK, slavenet);
			if (answer != NULL) {
				msg->tsp_type = TSP_ACK;
				length = sizeof(struct sockaddr_in);
				bytenetorder(msg);
				if (sendto(sock, (char *)msg, 
						sizeof(struct tsp), 0,
						&msaveaddr, length) < 0) {
					syslog(LOG_ERR, "sendto: %m");
					exit(1);
				}
			}
			break;
		case TSP_ACCEPT:
		case TSP_REFUSE:
			break;
		case TSP_RESOLVE:
			break;
		case TSP_QUIT:
			/* become slave */
#ifdef MEASURE
			if (fp != NULL) {
				(void)fclose(fp);
				fp = NULL;
			}
#endif
			longjmp(jmpenv, 2);
			break;
#ifdef TESTING
		case TSP_TEST:
			electiontime = 0;
			break;
#endif
		case TSP_MSITEREQ:
			if (status & MASTER)
				break;
			if (trace) {
				fprintf(fd, "garbage: ");
				print(msg, &from);
			}
			break;

		case TSP_LOOP:
			/* looking for loops of masters */
			if ( !(status & MASTER))
				break;
			if (fromnet->status == SLAVE) {
			    if ( !strcmp(msg->tsp_name, hostname)) {
				  for(;;) {
				    to.tsp_type = TSP_RESOLVE;
				    answer = acksend(&to, &fromnet->dest_addr,
					(char *)ANYADDR, TSP_MASTERACK,
					fromnet);
				    if (answer == NULL)
					    break;
				    to.tsp_type = TSP_QUIT;
				    (void)strcpy(to.tsp_name, hostname);
				    server = from;
				    answer = acksend(&to, &server,
					answer->tsp_name, TSP_ACK,
					(struct netinfo *)NULL);
				    if (answer == NULL) {
					syslog(LOG_ERR, "loop kill error");
				    } else {
					electiontime = 0;
				    }
				  }
			    } else {
				if (msg->tsp_hopcnt-- <= 0)
				    break;
				bytenetorder(msg);
				ntp = nettab;
				for (; ntp != NULL; ntp = ntp->next)
				    if (ntp->status == MASTER)
					if (sendto(sock, (char *)msg, 
					    sizeof(struct tsp), 0,
					    &ntp->dest_addr, length) < 0) {
						syslog(LOG_ERR, "sendto: %m");
						exit(1);
					}
			    }
			} else {
			    /*
			     * We should not have received this from a net
			     * we are master on.  There must be two masters
			     * in this case.
			     */
			    if (fromnet->my_addr.s_addr == from.sin_addr.s_addr)
				break;
			    for (;;) {
				to.tsp_type = TSP_RESOLVE;
				answer = acksend(&to, &fromnet->dest_addr,
				    (char *)ANYADDR, TSP_MASTERACK,
				    fromnet);
				if (answer == NULL)
					break;
				to.tsp_type = TSP_QUIT;
				(void)strcpy(to.tsp_name, hostname);
				server = from;
				answer = acksend(&to, &server, answer->tsp_name,
				    TSP_ACK, (struct netinfo *)NULL);
				if (answer == NULL) {
					syslog(LOG_ERR, "loop kill error2");
				} else {
					(void)addmach(msg->tsp_name, &from);
				}
			    }
			}
			break;
		default:
			if (trace) {
				fprintf(fd, "garbage: ");
				print(msg, &from);
			}
			break;
		}
	}
	goto loop;
}
Ejemplo n.º 7
0
/*
 * add a host to the list of controlled machines if not already there
 */
struct hosttbl *
addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp)
{
	struct hosttbl *ret, *p, *b, *f;

	ret = findhost(name);
	if (ret == 0) {
		if (slvcount >= NHOSTS) {
			if (trace) {
				fprintf(fd, "no more slots in host table\n");
				prthp(CLK_TCK);
			}
			syslog(LOG_ERR, "no more slots in host table");
			Mflag = 0;
			longjmp(jmpenv, 2); /* give up and be a slave */
		}

		/* if our home hash slot is occupied, find a free entry
		 * in the hash table
		 */
		if (newhost_hash->name[0] != '\0') {
			do {
				ret = lasthfree;
				if (++lasthfree > &hosttbl[NHOSTS])
					lasthfree = &hosttbl[1];
			} while (ret->name[0] != '\0');

			if (!newhost_hash->head) {
				/* Move an interloper using our home.  Use
				 * scratch pointers in case the new head is
				 * pointing to itself.
				 */
				f = newhost_hash->h_fwd;
				b = newhost_hash->h_bak;
				f->h_bak = ret;
				b->h_fwd = ret;
				f = newhost_hash->l_fwd;
				b = newhost_hash->l_bak;
				f->l_bak = ret;
				b->l_fwd = ret;
				bcopy(newhost_hash,ret,sizeof(*ret));
				ret = newhost_hash;
				ret->head = 1;
				ret->h_fwd = ret;
				ret->h_bak = ret;
			} else {
				/* link to an existing chain in our home
				 */
				ret->head = 0;
				p = newhost_hash->h_bak;
				ret->h_fwd = newhost_hash;
				ret->h_bak = p;
				p->h_fwd = ret;
				newhost_hash->h_bak = ret;
			}
		} else {
			ret = newhost_hash;
			ret->head = 1;
			ret->h_fwd = ret;
			ret->h_bak = ret;
		}
		ret->addr = *addr;
		ret->ntp = ntp;
		(void)strncpy(ret->name, name, sizeof(ret->name));
		ret->good = good_host_name(name);
		ret->l_fwd = &self;
		ret->l_bak = self.l_bak;
		self.l_bak->l_fwd = ret;
		self.l_bak = ret;
		slvcount++;

		ret->noanswer = 0;
		ret->need_set = 1;

	} else {
		ret->noanswer = (ret->noanswer != 0);
	}

	/* need to clear sequence number anyhow */
	ret->seq = 0;
	return(ret);
}
Ejemplo n.º 8
0
master()
{
	int ind;
	long pollingtime;
	struct timeval wait;
	struct timeval time;
	struct timezone tzone;
	struct tsp *msg, to;
	struct sockaddr_in saveaddr;
	int findhost();
	char *date();
	struct tsp *readmsg();
	struct tsp *answer, *acksend();
	char olddate[32];
	struct sockaddr_in server;
	register struct netinfo *ntp;

#ifdef MEASURE
	if (fp == NULL) {
		fp = fopen(_PATH_MASTERLOG, "w");
		setlinebuf(fp);
	}
#endif

	syslog(LOG_INFO, "This machine is master");
	if (trace)
		fprintf(fd, "THIS MACHINE IS MASTER\n");

	for (ntp = nettab; ntp != NULL; ntp = ntp->next)
		if (ntp->status == MASTER)
			masterup(ntp);
	pollingtime = 0;

loop:
	(void)gettimeofday(&time, (struct timezone *)0);
	if (time.tv_sec >= pollingtime) {
		pollingtime = time.tv_sec + SAMPLEINTVL;
		synch(0L);

		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
			to.tsp_type = TSP_LOOP;
			to.tsp_vers = TSPVERSION;
			to.tsp_seq = sequence++;
			to.tsp_hopcnt = 10;
			(void)strcpy(to.tsp_name, hostname);
			bytenetorder(&to);
			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
			    (struct sockaddr *)&ntp->dest_addr,
			    sizeof(struct sockaddr_in)) < 0) {
				syslog(LOG_ERR, "sendto: %m");
				exit(1);
			}
		}
	}

	wait.tv_sec = pollingtime - time.tv_sec;
	wait.tv_usec = 0;
	msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
	if (msg != NULL) {
		switch (msg->tsp_type) {

		case TSP_MASTERREQ:
			break;
		case TSP_SLAVEUP:
			ind = addmach(msg->tsp_name, &from);
			newslave(ind, msg->tsp_seq);
			break;
		case TSP_SETDATE:
			saveaddr = from;
			/*
			 * the following line is necessary due to syslog
			 * calling ctime() which clobbers the static buffer
			 */
			(void)strcpy(olddate, date());
			(void)gettimeofday(&time, &tzone);
			time.tv_sec = msg->tsp_time.tv_sec;
			time.tv_usec = msg->tsp_time.tv_usec;
			logwtmp("|", "date", "");
			(void)settimeofday(&time, &tzone);
			logwtmp("}", "date", "");
			syslog(LOG_NOTICE, "date changed from: %s", olddate);
			msg->tsp_type = TSP_DATEACK;
			msg->tsp_vers = TSPVERSION;
			(void)strcpy(msg->tsp_name, hostname);
			bytenetorder(msg);
			if (sendto(sock, (char *)msg, sizeof(struct tsp), 0,
			    (struct sockaddr *)&saveaddr,
			    sizeof(struct sockaddr_in)) < 0) {
				syslog(LOG_ERR, "sendto: %m");
				exit(1);
			}
			spreadtime();
			pollingtime = 0;
			break;
		case TSP_SETDATEREQ:
			ind = findhost(msg->tsp_name);
			if (ind < 0) { 
			    syslog(LOG_WARNING,
				"DATEREQ from uncontrolled machine");
			    break;
			}
			if (hp[ind].seq !=  msg->tsp_seq) {
				hp[ind].seq = msg->tsp_seq;
				/*
				 * the following line is necessary due to syslog
				 * calling ctime() which clobbers the static buffer
				 */
				(void)strcpy(olddate, date());
				(void)gettimeofday(&time, &tzone);
				time.tv_sec = msg->tsp_time.tv_sec;
				time.tv_usec = msg->tsp_time.tv_usec;
				logwtmp("|", "date", "");
				(void)settimeofday(&time, &tzone);
				logwtmp("{", "date", "");
				syslog(LOG_NOTICE,
				    "date changed by %s from: %s",
				    msg->tsp_name, olddate);
				spreadtime();
				pollingtime = 0;
			}
			break;
		case TSP_MSITE:
		case TSP_MSITEREQ:
			break;
		case TSP_TRACEON:
			if (!(trace)) {
				fd = fopen(tracefile, "w");
				setlinebuf(fd);
				fprintf(fd, "Tracing started on: %s\n\n", 
							date());
			}
			trace = ON;
			break;
		case TSP_TRACEOFF:
			if (trace) {
				fprintf(fd, "Tracing ended on: %s\n", date());
				(void)fclose(fd);
			}
#ifdef GPROF
			moncontrol(0);
			_mcleanup();
			moncontrol(1);
#endif
			trace = OFF;
			break;
		case TSP_ELECTION:
			to.tsp_type = TSP_QUIT;
			(void)strcpy(to.tsp_name, hostname);
			server = from;
			answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
			    (struct netinfo *)NULL);
			if (answer == NULL) {
				syslog(LOG_ERR, "election error");
			} else {
				(void) addmach(msg->tsp_name, &from);
			}
			pollingtime = 0;
			break;
		case TSP_CONFLICT:
			/*
			 * After a network partition, there can be 
			 * more than one master: the first slave to 
			 * come up will notify here the situation.
			 */

			(void)strcpy(to.tsp_name, hostname);

			if (fromnet == NULL)
				break;
			for(;;) {
				to.tsp_type = TSP_RESOLVE;
				answer = acksend(&to, &fromnet->dest_addr,
				    (char *)ANYADDR, TSP_MASTERACK, fromnet);
				if (answer == NULL)
					break;
				to.tsp_type = TSP_QUIT;
				server = from;
				msg = acksend(&to, &server, answer->tsp_name,
				    TSP_ACK, (struct netinfo *)NULL);
				if (msg == NULL) {
					syslog(LOG_ERR, "error on sending QUIT");
				} else {
					(void) addmach(answer->tsp_name, &from);
				}
			}
			masterup(fromnet);
			pollingtime = 0;
			break;
		case TSP_RESOLVE:
			/*
			 * do not want to call synch() while waiting
			 * to be killed!
			 */
			(void)gettimeofday(&time, (struct timezone *)0);
			pollingtime = time.tv_sec + SAMPLEINTVL;
			break;
		case TSP_QUIT:
			/* become slave */
#ifdef MEASURE
			if (fp != NULL) {
				(void)fclose(fp);
				fp = NULL;
			}
#endif
			longjmp(jmpenv, 2);
			break;
		case TSP_LOOP:
			/*
			 * We should not have received this from a net
			 * we are master on.  There must be two masters
			 * in this case.
			 */
			to.tsp_type = TSP_QUIT;
			(void)strcpy(to.tsp_name, hostname);
			server = from;
			answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
				(struct netinfo *)NULL);
			if (answer == NULL) {
				syslog(LOG_WARNING,
				    "loop breakage: no reply to QUIT");
			} else {
				(void)addmach(msg->tsp_name, &from);
			}
		default:
			if (trace) {
				fprintf(fd, "garbage: ");
				print(msg, &from);
			}
			break;
		}
	}
	goto loop;
}