chiark / gitweb /
REORG Delete everything that's not innduct or build system or changed for innduct
[innduct.git] / innfeed / host.c
diff --git a/innfeed/host.c b/innfeed/host.c
deleted file mode 100644 (file)
index aa4259c..0000000
+++ /dev/null
@@ -1,4046 +0,0 @@
-/*  $Id: host.c 7833 2008-05-18 20:04:35Z iulius $
-**
-**  The implementation of the innfeed Host class.
-**
-**  Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <float.h>
-#include <math.h>
-#include <netdb.h>
-#include <syslog.h>
-#include <sys/param.h>
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "configfile.h"
-#include "connection.h"
-#include "endpoint.h"
-#include "host.h"
-#include "innlistener.h"
-#include "tape.h"
-
-#define REQ 1
-#define NOTREQ 0
-#define NOTREQNOADD 2
-
-#define VALUE_OK 0
-#define VALUE_TOO_HIGH 1
-#define VALUE_TOO_LOW 2
-#define VALUE_MISSING 3
-#define VALUE_WRONG_TYPE 4
-
-#define METHOD_STATIC 0
-#define METHOD_APS 1
-#define METHOD_QUEUE 2
-#define METHOD_COMBINED 3
-
-/* the limit of number of connections open when a host is
-   set to 0 to mean "infinite" */
-#define MAXCON 500
-#define MAXCONLIMIT(xx) ((xx==0)?MAXCON:xx)
-
-#define BACKLOGFILTER 0.7
-#define BACKLOGLWM 20.0
-#define BACKLOGHWM 50.0
-
-/* time between retrying blocked hosts in seconds */
-#define TRYBLOCKEDHOSTPERIOD 120
-
-extern char *configFile ;
-#if defined(hpux) || defined(__hpux) || defined(_SCO_DS)
-extern int h_errno;
-#endif
-
-/* the host keeps a couple lists of these */
-typedef struct proc_q_elem 
-{
-    Article article ;
-    struct proc_q_elem *next ;
-    struct proc_q_elem *prev ;
-    time_t whenToRequeue ;
-} *ProcQElem ;
-
-typedef struct host_param_s
-{
-  char *peerName;
-  char *ipName;
-  struct sockaddr_in *bindAddr;
-#ifdef HAVE_INET6
-  struct sockaddr_in6 *bindAddr6;
-#endif
-  int family;
-  unsigned int articleTimeout;
-  unsigned int responseTimeout;
-  unsigned int initialConnections;
-  unsigned int absMaxConnections;
-  unsigned int maxChecks;
-  unsigned short portNum;
-  bool forceIPv4;
-  unsigned int closePeriod;
-  unsigned int dynamicMethod;
-  bool wantStreaming;
-  bool dropDeferred;
-  bool minQueueCxn;
-  double lowPassLow; /* as percentages */
-  double lowPassHigh;
-  double lowPassFilter;
-  unsigned int backlogLimit ;
-  unsigned int backlogLimitHigh ;
-  double backlogFactor ;
-  double dynBacklogFilter ;
-  double dynBacklogLowWaterMark ;
-  double dynBacklogHighWaterMark ;
-  bool backlogFeedFirst ;
-  char *username;
-  char *password;
-} *HostParams ;
-
-struct host_s 
-{
-    InnListener listener ;      /* who created me. */
-    struct sockaddr **ipAddrs ;        /* the ip addresses of the remote */
-    int nextIpAddr ;           /* the next ip address to hand out */
-
-    Connection *connections ;   /* NULL-terminated list of all connections */
-    bool *cxnActive ;           /* true if the corresponding cxn is active */
-    bool *cxnSleeping ;         /* true if the connection is sleeping */
-    unsigned int maxConnections;       /* maximum no of cxns controlled by method */
-    unsigned int activeCxns ;          /* number of connections currently active */
-    unsigned int sleepingCxns ;        /* number of connections currently sleeping */
-    Connection blockedCxn ;     /* the first connection to get the 400 banner*/
-    Connection notThisCxn ;    /* don't offer articles to this connection */
-
-    HostParams params;          /* Parameters from config file */
-
-    bool remoteStreams ;        /* true if remote supports streaming */
-    
-    ProcQElem queued ;          /* articles done nothing with yet. */
-    ProcQElem queuedTail ;
-
-    ProcQElem processed ;       /* articles given to a Connection */
-    ProcQElem processedTail ;
-
-    ProcQElem deferred ;       /* articles which have been deferred by */
-    ProcQElem deferredTail ;   /* a connection */
-    
-    TimeoutId statsId ;         /* timeout id for stats logging. */
-    TimeoutId ChkCxnsId ;      /* timeout id for dynamic connections */
-    TimeoutId deferredId ;     /* timeout id for deferred articles */
-
-    Tape myTape ;
-    
-    bool backedUp ;             /* set to true when all cxns are full */
-    unsigned int backlog ;             /* number of arts in `queued' queue */
-    unsigned int deferLen ;            /* number of arts in `deferred' queue */
-
-    bool loggedModeOn ;         /* true if we logged going into no-CHECK mode */
-    bool loggedModeOff ;        /* true if we logged going out of no-CHECK mode */
-
-    bool loggedBacklog ;        /* true if we already logged the fact */
-    bool notifiedChangedRemBlckd ; /* true if we logged a new response 400 */
-    bool removeOnReload ;      /* true if host should be removed at end of
-                                * config reload
-                                */
-    bool isDynamic;             /* true if host created dynamically */
-
-    /* these numbers get reset periodically (after a 'final' logging). */
-    unsigned int artsOffered ;         /* # of articles we offered to remote. */
-    unsigned int artsAccepted ;        /* # of articles succesfully transferred */
-    unsigned int artsNotWanted ;       /* # of articles remote already had */
-    unsigned int artsRejected ;        /* # of articles remote rejected */
-    unsigned int artsDeferred ;        /* # of articles remote asked us to retry */
-    unsigned int artsMissing ;         /* # of articles whose file was missing. */
-    unsigned int artsToTape ;          /* # of articles given to tape */
-    unsigned int artsQueueOverflow ;   /* # of articles that overflowed `queued' */
-    unsigned int artsCxnDrop ;         /* # of articles caught in dead cxn */
-    unsigned int artsHostSleep ;       /* # of articles spooled by sleeping host */
-    unsigned int artsHostClose ;       /* # of articles caught by closing host */
-    unsigned int artsFromTape ;        /* # of articles we pulled off tape */
-    double artsSizeAccepted ;  /* size of articles succesfully transferred */
-    double artsSizeRejected ;  /* size of articles remote rejected */
-
-    /* Dynamic Peerage - MGF */
-    unsigned int artsProcLastPeriod ;  /* # of articles processed in last period */
-    unsigned int secsInLastPeriod ;    /* Number of seconds in last period */
-    unsigned int lastCheckPoint ;      /* total articles at end of last period */
-    unsigned int lastSentCheckPoint ;  /* total articles sent end of last period */
-    unsigned int lastTotalCheckPoint ; /* total articles total end of last period */
-    bool maxCxnChk ;            /* check for maxConnections */
-    time_t lastMaxCxnTime ;     /* last time a maxConnections increased */
-    time_t lastChkTime;         /* last time a check was made for maxConnect */
-    unsigned int nextCxnTimeChk ;      /* next check for maxConnect */
-
-    double backlogFilter;        /* IIR filter for size of backlog */
-
-    /* These numbers are as above, but for the life of the process. */
-    unsigned int gArtsOffered ;        
-    unsigned int gArtsAccepted ;
-    unsigned int gArtsNotWanted ;
-    unsigned int gArtsRejected ;
-    unsigned int gArtsDeferred ;
-    unsigned int gArtsMissing ;
-    unsigned int gArtsToTape ;
-    unsigned int gArtsQueueOverflow ;
-    unsigned int gArtsCxnDrop ;
-    unsigned int gArtsHostSleep ;
-    unsigned int gArtsHostClose ;
-    unsigned int gArtsFromTape ;
-    double gArtsSizeAccepted ;
-    double gArtsSizeRejected ;
-    unsigned int gCxnQueue ;
-    unsigned int gNoQueue ;
-
-    time_t firstConnectTime ;   /* time of first connect. */
-    time_t connectTime ;        /* the time the first connection was fully
-                                   set up (MODE STREAM and everything
-                                   else). */
-    time_t spoolTime ;          /* the time the Host had to revert to
-                                   spooling articles to tape. */
-    time_t lastSpoolTime ;      /* the time the last time the Host had to
-                                   revert to spooling articles to tape. */
-    time_t nextIpLookup ;      /* time of last IP name resolution */
-
-    char *blockedReason ;       /* what the 400 from the remote says. */
-    
-    Host next ;                 /* for global list of hosts. */
-
-    unsigned long dlAccum ;            /* cumulative deferLen */
-    unsigned int blNone ;              /* number of times the backlog was 0 */
-    unsigned int blFull ;              /* number of times the backlog was full */
-    unsigned int blQuartile[4] ;       /* number of times in each quartile */
-    unsigned long blAccum ;            /* cumulative backlog for computing mean */
-    unsigned int blCount ;             /* the sample count */
-};
-
-/* A holder for the info we got out of the config file, but couldn't create
-   the Host object for (normally due to lock-file problems).*/
-
-typedef struct host_holder_s
-{
-  HostParams params;
-  struct host_holder_s *next ;
-} *HostHolder ;
-
-
-/* These numbers are as above, but for all hosts over
-   the life of the process. */
-long procArtsOffered ;        
-long procArtsAccepted ;
-long procArtsNotWanted ;
-long procArtsRejected ;
-long procArtsDeferred ;
-long procArtsMissing ;
-double procArtsSizeAccepted ;
-double procArtsSizeRejected ;
-long procArtsToTape ;
-long procArtsFromTape ;
-
-static HostParams defaultParams=NULL;
-
-static HostHolder blockedHosts ; /* lists of hosts we can't lock */
-static TimeoutId tryBlockedHostsId = 0 ;
-static time_t lastStatusLog ;
-
-  /*
-   * Host object private methods.
-   */
-static void articleGone (Host host, Connection cxn, Article article) ;
-static void hostStopSpooling (Host host) ;
-static void hostStartSpooling (Host host) ;
-static void hostLogStats (Host host, bool final) ;
-static void hostStatsTimeoutCbk (TimeoutId tid, void *data) ;
-static void hostDeferredArtCbk (TimeoutId tid, void *data) ;
-static void backlogToTape (Host host) ;
-static void queuesToTape (Host host) ;
-static bool amClosing (Host host) ;
-static void hostLogStatus (void) ;
-static void hostPrintStatus (Host host, FILE *fp) ;
-static int validateBool (FILE *fp, const char *name,
-                         int required, bool setval,
-                        scope * sc, unsigned int inh);
-static int validateReal (FILE *fp, const char *name, double low,
-                        double high, int required, double setval,
-                        scope * sc, unsigned int inh);
-static int validateInteger (FILE *fp, const char *name,
-                           long low, long high, int required, long setval,
-                           scope * sc, unsigned int inh);
-
-static HostParams newHostParams(HostParams p);
-static void freeHostParams(HostParams params);
-
-static HostHolder FindBlockedHost(const char *name);
-static void addBlockedHost(HostParams params);
-static void tryBlockedHosts(TimeoutId tid, void *data);
-static Host newHost (InnListener listener, HostParams p);
-
-static HostParams getHostInfo (void);
-static HostParams hostDetails (scope *s,
-                              char *name,
-                              bool isDefault,
-                              FILE *fp);
-
-static Host findHostByName (char *name) ;
-static void hostCleanup (void) ;
-static void hostAlterMaxConnections(Host host,
-                                   unsigned int absMaxCxns, unsigned int maxCxns,
-                                   bool makeConnect);
-
-/* article queue management functions */
-static Article remHead (ProcQElem *head, ProcQElem *tail) ;
-static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
-                         time_t when) ;
-static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail) ;
-
-
-
-
-
-/*
- * Host class data
- */
-
-/* if true then when a Host logs its stats, it has all its connections
-   log theirs too. */
-static bool logConnectionStats = (bool) LOG_CONNECTION_STATS ;
-
-/* The frequency in seconds with which a Host will log its stats. */
-static time_t statsPeriod = STATS_PERIOD ;
-static time_t statsResetPeriod = STATS_RESET_PERIOD ;
-
-static Host gHostList = NULL ;
-
-static unsigned int gHostCount = 0 ;
-
-static unsigned int maxIpNameLen = 0 ;
-static unsigned int maxPeerNameLen = 0 ;
-
-static unsigned int hostHighwater = HOST_HIGHWATER ;
-static time_t start ;
-static char startTime [30] ;    /* for ctime(3) */
-static pid_t myPid ;
-
-static char *statusFile = NULL ;
-static unsigned int dnsRetPeriod ;
-static unsigned int dnsExpPeriod ;
-
-bool genHtml = false ;
-
-/*******************************************************************/
-/*                  PUBLIC FUNCTIONS                               */
-/*******************************************************************/
-
-
-/* function called when the config file is loaded */
-int hostConfigLoadCbk (void *data)
-{
-  int rval = 1, bval ;
-  long iv ;
-  FILE *fp = (FILE *) data ;
-  char *p ;
-
-
-  d_printf(1,"hostConfigLoadCbk\n");
-
-  if (defaultParams)
-    {
-      freeHostParams(defaultParams);
-      defaultParams=NULL;
-    }
-   
-  /* get optional global defaults */
-  if (getInteger (topScope,"dns-retry",&iv,NO_INHERIT))
-    {
-      if (iv < 1)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 1. Using %ld","dns-retry",
-                      iv,"global scope",(long)DNS_RETRY_PERIOD) ;
-          iv = DNS_RETRY_PERIOD ;
-        }
-    }
-  else
-    iv = DNS_RETRY_PERIOD ;
-  dnsRetPeriod = (unsigned int) iv ;
-  
-  
-  if (getInteger (topScope,"dns-expire",&iv,NO_INHERIT))
-    {
-      if (iv < 1)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 1. Using %ld","dns-expire",iv,
-                      "global scope",(long)DNS_EXPIRE_PERIOD) ;
-          iv = DNS_EXPIRE_PERIOD ;
-        }
-    }
-  else
-    iv = DNS_EXPIRE_PERIOD ;
-  dnsExpPeriod = (unsigned int) iv ;
-
-  if (getBool (topScope,"gen-html",&bval,NO_INHERIT))
-    genHtml = (bval ? true : false) ;
-  else
-    genHtml = GEN_HTML ;
-  
-  if (getString (topScope,"status-file",&p,NO_INHERIT))
-    {
-      hostSetStatusFile (p) ;
-      free (p) ;
-    }
-  else
-    hostSetStatusFile (INNFEED_STATUS) ;
-  
-  
-  if (getBool (topScope,"connection-stats",&bval,NO_INHERIT))
-    logConnectionStats = (bval ? true : false) ;
-  else
-    logConnectionStats = (LOG_CONNECTION_STATS ? true : false) ;
-
-
-  if (getInteger (topScope,"host-queue-highwater", &iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld","host-queue-highwater",
-                      iv,"global scope",(long) HOST_HIGHWATER) ;
-          iv = HOST_HIGHWATER ;
-        }
-    }
-  else
-    iv = HOST_HIGHWATER ;
-  hostHighwater = (unsigned int) iv ;
-
-  if (getInteger (topScope,"stats-period",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld","stats-period",
-                      iv,"global scope",(long)STATS_PERIOD) ;
-          iv = STATS_PERIOD ;
-        }
-    }
-  else
-    iv = STATS_PERIOD ;
-  statsPeriod = (unsigned int) iv ;
-
-
-  if (getInteger (topScope,"stats-reset",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld","stats-reset",iv,
-                      "global scope",(long)STATS_RESET_PERIOD) ;
-          iv = STATS_RESET_PERIOD ;
-        }
-    }
-  else
-    iv = STATS_RESET_PERIOD ;
-  statsResetPeriod = (unsigned int) iv ;
-  
-  defaultParams=hostDetails(topScope, NULL, true, fp);
-  ASSERT(defaultParams!=NULL);
-
-  return rval ;
-}
-
-/*
- * make a new HostParams structure copying an existing one
- * or from compiled defaults
- */
-
-HostParams newHostParams(HostParams p)
-{
-  HostParams params;
-
-  params = xmalloc (sizeof(struct host_param_s)) ;
-
-  if (p != NULL)
-    {
-      /* Copy old stuff in */
-      memcpy ((char *) params, (char *) p, sizeof(struct host_param_s));
-      if (params->peerName)
-       params->peerName = xstrdup(params->peerName);
-      if (params->ipName)
-       params->ipName = xstrdup(params->ipName);
-      if (params->bindAddr)
-        {
-          struct sockaddr_in *s = params->bindAddr;
-          params->bindAddr = xmalloc(sizeof(*s));
-          memcpy(params->bindAddr, s, sizeof(*s));
-        }
-#ifdef HAVE_INET6
-      if (params->bindAddr6)
-        {
-          struct sockaddr_in6 *s = params->bindAddr6;
-          params->bindAddr6 = xmalloc(sizeof(*s));
-          memcpy(params->bindAddr6, s, sizeof(*s));
-        }
-#endif
-    }
-  else
-    {
-      /* Fill in defaults */
-      params->peerName=NULL;
-      params->ipName=NULL;
-      params->bindAddr=NULL;
-#ifdef HAVE_INET6
-      params->bindAddr6=NULL;
-#endif
-      params->family = 0;
-      params->articleTimeout=ARTTOUT;
-      params->responseTimeout=RESPTOUT;
-      params->initialConnections=INIT_CXNS;
-      params->absMaxConnections=MAX_CXNS;
-      params->maxChecks=MAX_Q_SIZE;
-      params->portNum=PORTNUM;
-      params->forceIPv4=FORCE_IPv4;
-      params->closePeriod=CLOSE_PERIOD;
-      params->dynamicMethod=METHOD_STATIC;
-      params->wantStreaming=STREAM;
-      params->dropDeferred=false;
-      params->minQueueCxn=false;
-      params->lowPassLow=NOCHECKLOW;
-      params->lowPassHigh=NOCHECKHIGH;
-      params->lowPassFilter=FILTERVALUE;
-      params->backlogLimit=BLOGLIMIT;
-      params->backlogLimitHigh=BLOGLIMIT_HIGH ;
-      params->backlogFactor=LIMIT_FUDGE ;
-      params->dynBacklogFilter = BACKLOGFILTER ;
-      params->dynBacklogLowWaterMark = BACKLOGLWM;
-      params->dynBacklogHighWaterMark = BACKLOGHWM;
-      params->backlogFeedFirst=false;
-      params->username=NULL;
-      params->password=NULL;
-    }
-  return (params);
-}
-            
-/*
- * Free up a param structure
- */
-
-void freeHostParams(HostParams params)
-{
-  ASSERT(params != NULL);
-  if (params->peerName)
-    free (params->peerName) ;
-  if (params->ipName)
-    free (params->ipName) ;
-  if (params->bindAddr)
-    free (params->bindAddr) ;
-#ifdef HAVE_INET6
-  if (params->bindAddr6)
-    free (params->bindAddr6) ;
-#endif
-  free (params) ;
-}  
-
-static void hostReconfigure(Host h, HostParams params)
-{
-  unsigned int i, absMaxCxns ;
-  double oldBacklogFilter ;
-  
-  if (strcmp(h->params->ipName, params->ipName) != 0)
-    {
-      free (h->params->ipName) ;
-      h->params->ipName = xstrdup (params->ipName) ;
-      h->nextIpLookup = theTime () ;
-    }
-  
-  /* Put in new parameters
-     Unfortunately we can't blat on top of absMaxConnections
-     as we need to do some resizing here
-     */
-  
-  ASSERT (h->params != NULL);
-  
-  oldBacklogFilter = h->params->dynBacklogFilter;
-  i = h->params->absMaxConnections; /* keep old value */
-  absMaxCxns = params->absMaxConnections;
-  /* Use this set of params and allocate, and free
-   * up the old
-   */
-  freeHostParams(h->params);
-  h->params = params;
-  h->params->absMaxConnections = i; /* restore old value */
-  
-  /* If the backlog filter value has changed, reset the
-   * filter as the value therein will be screwy
-   */
-  if (h->params->dynBacklogFilter != oldBacklogFilter)
-    h->backlogFilter = ((h->params->dynBacklogLowWaterMark
-                        + h->params->dynBacklogHighWaterMark)
-                       /200.0 /(1.0-h->params->dynBacklogFilter));
-  
-  /* We call this anyway - it does nothing if the values
-   * haven't changed. This is because doing things like
-   * just changing "dynamic-method" requires this call
-   * to be made
-   */
-  hostAlterMaxConnections(h, absMaxCxns, h->maxConnections, false);
-  
-  for ( i = 0 ; i < MAXCONLIMIT(h->params->absMaxConnections) ; i++ )
-    if (h->connections[i] != NULL)
-      cxnSetCheckThresholds (h->connections[i],
-                            h->params->lowPassLow,
-                            h->params->lowPassHigh,
-                            h->params->lowPassFilter) ;
-  
-  /* XXX how to handle initCxns change? */
-}
-
-
-void configHosts (bool talkSelf)
-{
-  Host nHost, h, q ;
-  HostHolder hh, hi ;
-  HostParams params;
-
-  /* Remove the current blocked host list */
-  for (hh = blockedHosts, hi = NULL ; hh != NULL ; hh = hi)
-    {
-      freeHostParams(hh->params);
-      hi = hh->next ;
-      free (hh) ;
-    }
-  blockedHosts = NULL ;
-
-  closeDroppedArticleFile () ;
-  openDroppedArticleFile () ;
-  
-  while ((params = getHostInfo ()) !=NULL )
-    {
-      h = findHostByName (params->peerName) ;
-      /* We know the host isn't blocked as we cleared the blocked list */
-      /* Have we already got this host up and running ?*/
-      if ( h != NULL )
-       {
-         hostReconfigure(h, params);
-         h->removeOnReload = false ; /* Don't remove at the end */
-       }
-      else
-        {
-           
-         /* It's a host we haven't seen from the config file before */
-         nHost = newHost (mainListener, params);
-
-         if (nHost == NULL)
-           {
-             addBlockedHost(params);
-
-              warn ("ME locked cannot setup peer %s", params->peerName) ;
-           }
-         else 
-           {
-             if (params->initialConnections == 0 && talkSelf)
-                notice ("%s config ignored batch mode with initial"
-                        " connection count of 0", params->peerName) ;
-
-             if ( !listenerAddPeer (mainListener,nHost) )
-               die ("failed to add a new peer\n") ;
-           }
-       }
-
-    }
-  
-
-  for (h = gHostList; h != NULL; h = q) 
-    {
-      q = h->next ;
-      if (h->removeOnReload)
-       {
-         if (h->isDynamic)
-           {
-             /* change to the new default parameters */
-             params = newHostParams(defaultParams);
-             ASSERT(params->peerName == NULL);
-             ASSERT(params->ipName == NULL);
-             ASSERT(h->params->peerName != NULL);
-             ASSERT(h->params->ipName != NULL);
-             params->peerName = xstrdup(h->params->peerName);
-             params->ipName = xstrdup(h->params->ipName);
-             hostReconfigure(h, params);
-             h->removeOnReload = true;
-           }
-         else
-           hostClose (h) ;         /* h may be deleted in here. */
-       }
-      else
-        /* prime it for the next config file read */
-        h->removeOnReload = true ;
-    }
-
-  hostLogStatus () ;
-}
-
-
-void hostAlterMaxConnections(Host host,
-                            unsigned int absMaxCxns, unsigned int maxCxns,
-                            bool makeConnect)
-{
-  unsigned int lAbsMaxCxns;
-  unsigned int i;
-  
-  /* Fix 0 unlimited case */
-  lAbsMaxCxns = MAXCONLIMIT(absMaxCxns);
-  
-  /* Don't accept 0 for maxCxns */
-  maxCxns=MAXCONLIMIT(maxCxns);
-  
-  if ( host->params->dynamicMethod == METHOD_STATIC)
-    {
-      /* If running static, ignore the maxCxns passed in, we'll
-        just use absMaxCxns
-        */
-      maxCxns = lAbsMaxCxns;
-    }
-  
-  if ( maxCxns > lAbsMaxCxns)
-    {
-      /* ensure maxCxns is of the correct form */
-      maxCxns = lAbsMaxCxns;
-    }
-
-  if ((maxCxns < host->maxConnections) && (host->connections != NULL))
-    {
-      /* We are going to have to nuke some connections, as the current
-         max is now greater than the new max
-        */
-      for ( i = host->maxConnections ; i > maxCxns ; i-- )
-       {
-         /* XXX this is harsh, and arguably there could be a
-            cleaner way of doing it.  the problem being addressed
-            by doing it this way is that eventually a connection
-            closed cleanly via cxnClose can end up ultimately
-            calling hostCxnDead after h->maxConnections has
-            been lowered and the relevant arrays downsized.
-            If trashing the old, unallocated space in
-            hostCxnDead doesn't kill the process, the
-            ASSERT against h->maxConnections surely will.
-            */
-         if (host->connections[i - 1] != NULL)
-           {
-             cxnLogStats (host->connections [i-1], true) ;
-             cxnNuke (host->connections[i-1]) ;
-             host->connections[i-1] = NULL;
-           }
-       }
-      host->maxConnections = maxCxns ;
-    }
-  
-  if (host->connections)
-    for (i = host->maxConnections ; i <= MAXCONLIMIT(host->params->absMaxConnections) ; i++)
-      {
-       /* Ensure we've got an empty values only beyond the maxConnection
-          water mark.
-          */
-       ASSERT (host->connections[i] == NULL);
-      }
-  
-  if ((lAbsMaxCxns != MAXCONLIMIT(host->params->absMaxConnections)) ||
-      (host->connections == NULL))
-    {
-      /* we need to change the size of the connection array */
-      if (host->connections == NULL)
-       {
-         /* not yet allocated */
-         
-         host->connections = xcalloc (lAbsMaxCxns + 1, sizeof(Connection)) ;
-         
-         ASSERT (host->cxnActive == NULL);
-         host->cxnActive = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
-         
-         ASSERT (host->cxnSleeping == NULL) ;
-         host->cxnSleeping = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
-         
-         for (i = 0 ; i < lAbsMaxCxns ; i++)
-           {
-             host->connections [i] = NULL ;
-             host->cxnActive[i] = false ;
-             host->cxnSleeping[i] = false ;
-           }
-         host->connections[lAbsMaxCxns] = NULL;
-       }
-      else
-       {
-         host->connections =
-            xrealloc (host->connections,
-                      sizeof(Connection) * (lAbsMaxCxns + 1));
-         host->cxnActive = xrealloc (host->cxnActive,
-                                      sizeof(bool) * lAbsMaxCxns) ;
-         host->cxnSleeping = xrealloc (host->cxnSleeping,
-                                        sizeof(bool) * lAbsMaxCxns) ;
-
-         if (lAbsMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
-           {
-             for (i = MAXCONLIMIT(host->params->absMaxConnections) ;
-                  i < lAbsMaxCxns ; i++)
-               {
-                 host->connections[i+1] = NULL; /* array always 1 larger */
-                 host->cxnActive[i] = false ;
-                 host->cxnSleeping[i] = false ;
-               }
-           }
-       }
-      host->params->absMaxConnections = absMaxCxns;
-    }    
-  /* if maximum was raised, establish the new connexions
-     (but don't start using them).
-     */
-  if ( maxCxns > host->maxConnections)
-    {
-      i = host->maxConnections ;
-      /* need to set host->maxConnections before cxnWait() */
-      host->maxConnections = maxCxns;
-
-      while ( i < maxCxns )
-       {
-         host->cxnActive [i] = false ;
-         host->cxnSleeping [i] = false ;
-         /* create a new connection */
-         host->connections [i] =
-           newConnection (host, i,
-                          host->params->ipName,
-                          host->params->articleTimeout,
-                          host->params->portNum,
-                          host->params->responseTimeout,
-                          host->params->closePeriod,
-                          host->params->lowPassLow,
-                          host->params->lowPassHigh,
-                          host->params->lowPassFilter) ;
-
-         /* connect if low enough numbered, or we were forced to */
-         if ((i < host->params->initialConnections) || makeConnect)
-           cxnConnect (host->connections [i]) ;
-         else
-           cxnWait (host->connections [i]) ;
-         i++ ;
-       }
-    }
-
-}
-
-/*
- * Find a host on the blocked host list
- */
-
-static HostHolder FindBlockedHost(const char *name)
-{
-  HostHolder hh = blockedHosts;
-  while (hh != NULL)
-    if ((hh->params) && (hh->params->peerName) &&
-       (strcmp(name,hh->params->peerName) == 0))
-      return hh;
-    else
-      hh=hh->next;
-  return NULL;
-}
-
-static void addBlockedHost(HostParams params)
-{
-  HostHolder hh;
-
-  hh = xmalloc (sizeof(struct host_holder_s)) ;
-  /* Use this set of params */
-         
-  hh->params = params;
-  
-  hh->next = blockedHosts ;
-  blockedHosts = hh ;
-}
-
-/*
- * We iterate through the blocked host list and try and reconnect ones
- * where we couldn't get a lock
- */
-static void tryBlockedHosts(TimeoutId tid UNUSED , void *data UNUSED )
-{
-  HostHolder hh,hi;
-  HostParams params;
-  
-  hh = blockedHosts; /* Get start of our queue */
-  blockedHosts = NULL ; /* remove them all from the queue of hosts */
-
-  while (hh != NULL)
-    {
-      params = hh->params;
-      hi= hh->next;
-      free(hh);
-      hh = hi;
-
-      if (params && params->peerName)
-       {
-         if (findHostByName(params->peerName)!=NULL)
-           {
-             /* Wierd, someone's managed to start it when it's on
-              * the blocked list. Just silently discard.
-              */
-             freeHostParams(params);
-           }
-         else
-           {
-             Host nHost;
-             nHost = newHost (mainListener, params);
-
-             if (nHost == NULL)
-               {
-                 addBlockedHost(params);
-
-                  warn ("ME locked cannot setup peer %s", params->peerName) ;
-               }
-             else 
-               {
-                 d_printf(1,"Unblocked host %s\n",params->peerName);
-
-                 if (params->initialConnections == 0 &&
-                     listenerIsDummy(mainListener) /*talk to self*/)
-                    notice ("%s config ignored batch mode with initial"
-                            " connection count of 0", params->peerName) ;
-
-                 if ( !listenerAddPeer (mainListener,nHost) )
-                   die ("failed to add a new peer\n") ;
-               }
-           }
-       }
-    }
-  tryBlockedHostsId = prepareSleep(tryBlockedHosts,
-                                  TRYBLOCKEDHOSTPERIOD, NULL);
-}
-
-
-/*
- * Create a new Host object with default parameters. Called by the
- * InnListener.
- */
-
-Host newDefaultHost (InnListener listener,
-                    const char *name) 
-{
-  HostParams p;
-  Host h = NULL;
-
-  if (FindBlockedHost(name)==NULL)
-    {
-
-      p=newHostParams(defaultParams);
-      ASSERT(p!=NULL);
-
-      /* relies on fact listener and names are null in default*/
-      p->peerName=xstrdup(name);
-      p->ipName=xstrdup(name);
-      
-      h=newHost (listener,p);
-      if (h==NULL)
-       {
-         /* Couldn't get a lock - add to list of blocked peers */
-         addBlockedHost(p);
-
-          warn ("ME locked cannot setup peer %s", p->peerName);
-
-         return NULL;
-       }
-
-      h->isDynamic = true;
-      h->removeOnReload = true;
-
-      notice ("ME unconfigured peer %s added", p->peerName) ;
-    }
-  return h;
-}
-
-/*
- * Create a new host and attach the supplied param structure
- */
-
-static bool inited = false ;
-Host newHost (InnListener listener, HostParams p)
-{
-  Host nh ; 
-
-  ASSERT (p->maxChecks > 0) ;
-
-  if (!inited)
-    {
-      inited = true ;
-      atexit (hostCleanup) ;
-    }
-
-  /*
-   * Once only, init the first blocked host check
-   */
-  if (tryBlockedHostsId==0)
-    tryBlockedHostsId = prepareSleep(tryBlockedHosts,
-                                    TRYBLOCKEDHOSTPERIOD, NULL);
-
-  nh =  xcalloc (1, sizeof(struct host_s)) ;
-
-  nh->params = p;
-  nh->listener = listener;
-
-  nh->connections = NULL; /* We'll get these allocated later */
-  nh->cxnActive = NULL;
-  nh->cxnSleeping = NULL;
-
-  nh->activeCxns = 0 ;
-  nh->sleepingCxns = 0 ;
-
-  nh->blockedCxn = NULL ;
-  nh->notThisCxn = NULL ;
-
-  nh->queued = NULL ;
-  nh->queuedTail = NULL ;
-
-  nh->processed = NULL ;
-  nh->processedTail = NULL ;
-
-  nh->deferred = NULL ;
-  nh->deferredTail = NULL ;
-  
-  nh->statsId = 0 ;
-  nh->ChkCxnsId = 0 ;
-  nh->deferredId = 0;
-
-  nh->myTape = newTape (nh->params->peerName,
-                       listenerIsDummy (nh->listener)) ;
-  if (nh->myTape == NULL)
-    {                           /* tape couldn't be locked, probably */
-      free (nh->connections) ;
-      free (nh->cxnActive) ;
-      free (nh->cxnSleeping) ;
-      
-      free (nh) ;
-      return NULL ; /* note we don't free up p */
-    }
-
-  nh->backedUp = false ;
-  nh->backlog = 0 ;
-  nh->deferLen = 0 ;
-
-  nh->loggedBacklog = false ;
-  nh->loggedModeOn = false ;
-  nh->loggedModeOff = false ;
-  nh->notifiedChangedRemBlckd = false ;
-  nh->removeOnReload = false ; /* ready for config file reload */
-  nh->isDynamic = false ;
-
-  nh->artsOffered = 0 ;
-  nh->artsAccepted = 0 ;
-  nh->artsNotWanted = 0 ;
-  nh->artsRejected = 0 ;
-  nh->artsDeferred = 0 ;
-  nh->artsMissing = 0 ;
-  nh->artsToTape = 0 ;
-  nh->artsQueueOverflow = 0 ;
-  nh->artsCxnDrop = 0 ;
-  nh->artsHostSleep = 0 ;
-  nh->artsHostClose = 0 ;
-  nh->artsFromTape = 0 ;
-  nh->artsSizeAccepted = 0 ;
-  nh->artsSizeRejected = 0 ;
-
-  nh->artsProcLastPeriod = 0;
-  nh->secsInLastPeriod = 0;
-  nh->lastCheckPoint = 0;
-  nh->lastSentCheckPoint = 0;
-  nh->lastTotalCheckPoint = 0;
-  nh->maxCxnChk = true;
-  nh->lastMaxCxnTime = time(0);
-  nh->lastChkTime = time(0);
-  nh->nextCxnTimeChk = 30;
-  nh->backlogFilter = ((nh->params->dynBacklogLowWaterMark
-                       + nh->params->dynBacklogHighWaterMark)
-                      /200.0 /(1.0-nh->params->dynBacklogFilter));
-
-  nh->gArtsOffered = 0 ;
-  nh->gArtsAccepted = 0 ;
-  nh->gArtsNotWanted = 0 ;
-  nh->gArtsRejected = 0 ;
-  nh->gArtsDeferred = 0 ;
-  nh->gArtsMissing = 0 ;
-  nh->gArtsToTape = 0 ;
-  nh->gArtsQueueOverflow = 0 ;
-  nh->gArtsCxnDrop = 0 ;
-  nh->gArtsHostSleep = 0 ;
-  nh->gArtsHostClose = 0 ;
-  nh->gArtsFromTape = 0 ;
-  nh->gArtsSizeAccepted = 0 ;
-  nh->gArtsSizeRejected = 0 ;
-  nh->gCxnQueue = 0 ;
-  nh->gNoQueue = 0 ;
-  
-  nh->firstConnectTime = 0 ;
-  nh->connectTime = 0 ;
-  
-  nh->spoolTime = 0 ;
-
-  nh->blNone = 0 ;
-  nh->blFull = 0 ;
-  nh->blQuartile[0] = nh->blQuartile[1] = nh->blQuartile[2] =
-                     nh->blQuartile[3] = 0 ;
-  nh->dlAccum = 0;
-  nh->blAccum = 0;
-  nh->blCount = 0;
-
-
-  nh->maxConnections = 0; /* we currently have no connections allocated */
-
-  /* Note that the following will override the initialCxns specified as
-     maxCxns if we are on non-dyamic feed
-   */
-  hostAlterMaxConnections(nh, nh->params->absMaxConnections,
-                         nh->params->initialConnections, false);
-
-  nh->next = gHostList ;
-  gHostList = nh ;
-  gHostCount++ ;
-
-  if (maxIpNameLen == 0)
-    {
-      start = theTime() ;
-      strlcpy (startTime,ctime (&start),sizeof (startTime)) ;
-      myPid = getpid() ;
-    }
-  
-  if (strlen (nh->params->ipName) > maxIpNameLen)
-    maxIpNameLen = strlen (nh->params->ipName) ;
-  if (strlen (nh->params->peerName) > maxPeerNameLen)
-    maxPeerNameLen = strlen (nh->params->peerName) ;
-  
-  return nh ;
-}
-
-struct sockaddr *hostIpAddr (Host host, int family)
-{
-  int i ;
-  struct sockaddr **newIpAddrPtrs = NULL;
-  struct sockaddr_storage *newIpAddrs = NULL;
-  struct sockaddr *returnAddr;
-
-  ASSERT(host->params != NULL);
-
-  /* check to see if need to look up the host name */
-  if (host->nextIpLookup <= theTime())
-    {
-#ifdef HAVE_INET6
-      int gai_ret;
-      struct addrinfo *res, *p;
-      struct addrinfo hints;
-
-      memset(&hints, 0, sizeof(hints));
-      hints.ai_family = family ? family : AF_UNSPEC;
-      hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
-      hints.ai_flags = AI_ADDRCONFIG;
-#endif
-      if((gai_ret = getaddrinfo(host->params->ipName, NULL, &hints, &res)) != 0
-        || res == NULL)
-       {
-          warn ("%s can't resolve hostname %s: %s", host->params->peerName,
-               host->params->ipName, gai_ret == 0 ? "no addresses returned"
-               : gai_strerror(gai_ret)) ;
-       }
-      else
-       {
-         /* figure number of pointers that need space */
-         i = 0;
-         for ( p = res ; p ; p = p->ai_next ) ++i;
-
-         newIpAddrPtrs = (struct sockaddr **)
-           xmalloc ( (i + 1) * sizeof(struct sockaddr *) );
-
-         newIpAddrs = (struct sockaddr_storage *)
-           xmalloc ( i * sizeof(struct sockaddr_storage) );
-
-         i = 0;
-         /* copy the addresses from the getaddrinfo linked list */
-         for( p = res ; p ; p = p->ai_next )
-           {
-             memcpy( &newIpAddrs[i], p->ai_addr, p->ai_addrlen );
-             newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
-             ++i;
-           }
-         newIpAddrPtrs[i] = NULL ;
-         freeaddrinfo( res );
-       }
-#else
-      struct hostent *hostEnt ;
-      struct in_addr ipAddr;
-
-      /* see if the ipName we're given is a dotted quad */
-      if ( !inet_aton (host->params->ipName,&ipAddr) )
-       {
-         if ((hostEnt = gethostbyname (host->params->ipName)) == NULL)
-           {
-              warn ("%s can't resolve hostname %s: %s", host->params->peerName,
-                   host->params->ipName, hstrerror(h_errno)) ;
-           }
-         else
-           {
-             /* figure number of pointers that need space */
-             for (i = 0 ; hostEnt->h_addr_list[i] ; i++)
-               ;
-
-             newIpAddrPtrs = xmalloc ((i + 1) * sizeof(struct sockaddr *));
-             newIpAddrs = xmalloc (i * sizeof(struct sockaddr_storage));
-
-             /* copy the addresses from gethostbyname() static space */
-             i = 0;
-             for (i = 0 ; hostEnt->h_addr_list[i] ; i++)
-               {
-                 make_sin( (struct sockaddr_in *)(&newIpAddrs[i]),
-                       (struct in_addr *)(hostEnt->h_addr_list[i]) );
-                 newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
-               }
-             newIpAddrPtrs[i] = NULL ;
-           }
-       }
-      else
-       {
-         newIpAddrPtrs = (struct sockaddr **)
-                 xmalloc ( 2 * sizeof( struct sockaddr * ) );
-         newIpAddrs = (struct sockaddr_storage *)
-                 xmalloc ( sizeof( struct sockaddr_storage ) );
-
-         make_sin( (struct sockaddr_in *)newIpAddrs, &ipAddr );
-         newIpAddrPtrs[0] = (struct sockaddr *)newIpAddrs;
-         newIpAddrPtrs[1] = NULL;
-       }
-#endif
-
-      if (newIpAddrs)
-       {
-         if (host->ipAddrs)
-         {
-           if(host->ipAddrs[0])
-             free (host->ipAddrs[0]);
-           free (host->ipAddrs) ;
-         }
-         host->ipAddrs = newIpAddrPtrs ;
-         host->nextIpAddr = 0 ;
-         host->nextIpLookup = theTime () + dnsExpPeriod ;
-       }
-      else
-       {
-         /* failed to setup new addresses */
-         host->nextIpLookup = theTime () + dnsRetPeriod ;
-       }
-    }
-
-  if (host->ipAddrs)
-    returnAddr = host->ipAddrs[host->nextIpAddr] ;
-  else
-    returnAddr = NULL ;
-
-  return returnAddr ;
-}
-
-
-#ifdef HAVE_INET6
-/*
- * Delete IPv4 addresses from the address list.
- */
-void hostDeleteIpv4Addr (Host host)
-{
-  int i, j;
-
-  if (!host->ipAddrs)
-    return;
-  for (i = 0, j = 0; host->ipAddrs[i]; i++) {
-    if (host->ipAddrs[i]->sa_family != AF_INET)
-      host->ipAddrs[j++] = host->ipAddrs[i];
-  }
-  host->ipAddrs[j] = 0;
-  if (host->nextIpAddr >= j)
-      host->nextIpAddr = 0;
-}
-#endif
-
-
-void hostIpFailed (Host host)
-{
-  if (host->ipAddrs)
-      if (host->ipAddrs[++host->nextIpAddr] == NULL)
-       host->nextIpAddr = 0 ;
-}
-
-
-void gPrintHostInfo (FILE *fp, unsigned int indentAmt)
-{
-  Host h ;
-  char indent [INDENT_BUFFER_SIZE] ;
-  unsigned int i ;
-  
-  for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
-    indent [i] = ' ' ;
-  indent [i] = '\0' ;
-  
-  fprintf (fp,"%sGlobal Host list : (count %d) {\n",indent,gHostCount) ;
-  
-  for (h = gHostList ; h != NULL ; h = h->next)
-    printHostInfo (h,fp,indentAmt + INDENT_INCR) ;
-  
-  fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void printHostInfo (Host host, FILE *fp, unsigned int indentAmt)
-{
-  char indent [INDENT_BUFFER_SIZE] ;
-  unsigned int i ;
-  ProcQElem qe ;
-  double cnt = (host->blCount) ? (host->blCount) : 1.0;
-  
-  for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
-    indent [i] = ' ' ;
-  indent [i] = '\0' ;
-
-  fprintf (fp,"%sHost : %p {\n",indent,(void *) host) ;
-
-  if (host == NULL)
-    {
-      fprintf (fp,"%s}\n",indent) ;
-      return ;
-    }
-  
-  fprintf (fp,"%s    peer-name : %s\n",indent,host->params->peerName) ;
-  fprintf (fp,"%s    ip-name : %s\n",indent,host->params->ipName) ;
-#ifdef HAVE_INET6
-  if (host->params->family == AF_INET6)
-    {
-      fprintf (fp,"%s    bindaddress : none\n",indent);
-    }
-  else
-#endif
-    {
-      fprintf (fp,"%s    bindaddress : %s\n",indent,
-      host->params->bindAddr == NULL ||
-      host->params->bindAddr->sin_addr.s_addr == 0 ? "any" :
-        inet_ntoa(host->params->bindAddr->sin_addr));
-    }
-#ifdef HAVE_INET6
-  if (host->params->family == AF_INET)
-    {
-      fprintf (fp,"%s    bindaddress6 : none\n",indent);
-    }
-  else
-    {
-      char buf[128];
-      fprintf (fp,"%s    bindaddress6 : %s\n",indent,
-        host->params->bindAddr6 == NULL ? "any" :
-          inet_ntop(AF_INET6, &host->params->bindAddr6->sin6_addr,
-            buf, sizeof(buf)));
-    }
-#endif
-  fprintf (fp,"%s    abs-max-connections : %d\n",indent,
-          host->params->absMaxConnections) ;
-  fprintf (fp,"%s    active-connections : %d\n",indent,host->activeCxns) ;
-  fprintf (fp,"%s    sleeping-connections : %d\n",indent,host->sleepingCxns) ;
-  fprintf (fp,"%s    initial-connections : %d\n",indent,
-          host->params->initialConnections) ;
-  fprintf (fp,"%s    want-streaming : %s\n",indent,
-           boolToString (host->params->wantStreaming)) ;
-  fprintf (fp,"%s    drop-deferred : %s\n",indent,
-           boolToString (host->params->dropDeferred)) ;
-  fprintf (fp,"%s    min-queue-connection : %s\n",indent,
-           boolToString (host->params->minQueueCxn)) ;
-  fprintf (fp,"%s    remote-streams : %s\n",indent,
-           boolToString (host->remoteStreams)) ;
-  fprintf (fp,"%s    max-checks : %d\n",indent,host->params->maxChecks) ;
-  fprintf (fp,"%s    article-timeout : %d\n",indent,
-          host->params->articleTimeout) ;
-  fprintf (fp,"%s    response-timeout : %d\n",indent,
-          host->params->responseTimeout) ;
-  fprintf (fp,"%s    close-period : %d\n",indent,
-          host->params->closePeriod) ;
-  fprintf (fp,"%s    port : %d\n",indent,host->params->portNum) ;
-  fprintf (fp,"%s    dynamic-method : %d\n",indent,
-          host->params->dynamicMethod) ;
-  fprintf (fp,"%s    dynamic-backlog-filter : %2.1f\n",indent,
-          host->params->dynBacklogFilter) ;
-  fprintf (fp,"%s    dynamic-backlog-lwm : %2.1f\n",indent,
-          host->params->dynBacklogLowWaterMark) ;
-  fprintf (fp,"%s    dynamic-backlog-hwm : %2.1f\n",indent,
-          host->params->dynBacklogHighWaterMark) ;
-  fprintf (fp,"%s    no-check on : %2.1f\n",indent,
-          host->params->lowPassHigh) ;
-  fprintf (fp,"%s    no-check off : %2.1f\n",indent,
-          host->params->lowPassLow) ;
-  fprintf (fp,"%s    no-check filter : %2.1f\n",indent,
-          host->params->lowPassFilter) ;
-  fprintf (fp,"%s    backlog-limit : %d\n",indent,
-          host->params->backlogLimit) ;
-  fprintf (fp,"%s    backlog-limit-high : %d\n",indent,
-          host->params->backlogLimitHigh) ;
-  fprintf (fp,"%s    backlog-factor : %2.1f\n",indent,
-          host->params->backlogFactor) ;
-  fprintf (fp,"%s    max-connections : %d\n",indent,
-          host->maxConnections) ;
-  fprintf (fp,"%s    backlog-feed-first : %s\n",indent,
-           boolToString (host->params->backlogFeedFirst)) ;
-
-
-  fprintf (fp,"%s    statistics-id : %d\n",indent,host->statsId) ;
-  fprintf (fp,"%s    ChkCxns-id : %d\n",indent,host->ChkCxnsId) ;
-  fprintf (fp,"%s    deferred-id : %d\n",indent,host->deferredId) ;
-  fprintf (fp,"%s    backed-up : %s\n",indent,boolToString (host->backedUp));
-  fprintf (fp,"%s    backlog : %d\n",indent,host->backlog) ;
-  fprintf (fp,"%s    deferLen : %d\n",indent,host->deferLen) ;
-  fprintf (fp,"%s    loggedModeOn : %s\n",indent,
-           boolToString (host->loggedModeOn)) ;
-  fprintf (fp,"%s    loggedModeOff : %s\n",indent,
-           boolToString (host->loggedModeOff)) ;
-  fprintf (fp,"%s    logged-backlog : %s\n",indent,
-           boolToString (host->loggedBacklog)) ;
-  fprintf (fp,"%s    streaming-type changed : %s\n",indent,
-           boolToString (host->notifiedChangedRemBlckd)) ;
-  fprintf (fp,"%s    articles offered : %d\n",indent,host->artsOffered) ;
-  fprintf (fp,"%s    articles accepted : %d\n",indent,host->artsAccepted) ;
-  fprintf (fp,"%s    articles not wanted : %d\n",indent,
-           host->artsNotWanted) ;
-  fprintf (fp,"%s    articles rejected : %d\n",indent,host->artsRejected);
-  fprintf (fp,"%s    articles deferred : %d\n",indent,host->artsDeferred) ;
-  fprintf (fp,"%s    articles missing : %d\n",indent,host->artsMissing) ;
-  fprintf (fp,"%s    articles spooled : %d\n",indent,host->artsToTape) ;
-  fprintf (fp,"%s      because of queue overflow : %d\n",indent,
-           host->artsQueueOverflow) ;
-  fprintf (fp,"%s      when the we closed the host : %d\n",indent,
-           host->artsHostClose) ;
-  fprintf (fp,"%s      because the host was asleep : %d\n",indent,
-           host->artsHostSleep) ;
-  fprintf (fp,"%s    articles unspooled : %d\n",indent,host->artsFromTape) ;
-  fprintf (fp,"%s    articles requeued from dropped connections : %d\n",indent,
-           host->artsCxnDrop) ;
-
-  fprintf (fp,"%s    process articles offered : %d\n",indent,
-           host->gArtsOffered) ;
-  fprintf (fp,"%s    process articles accepted : %d\n",indent,
-           host->gArtsAccepted) ;
-  fprintf (fp,"%s    process articles not wanted : %d\n",indent,
-           host->gArtsNotWanted) ;
-  fprintf (fp,"%s    process articles rejected : %d\n",indent,
-           host->gArtsRejected);
-  fprintf (fp,"%s    process articles deferred : %d\n",indent,
-           host->gArtsDeferred) ;
-  fprintf (fp,"%s    process articles missing : %d\n",indent,
-           host->gArtsMissing) ;
-  fprintf (fp,"%s    process articles spooled : %d\n",indent,
-           host->gArtsToTape) ;
-  fprintf (fp,"%s      because of queue overflow : %d\n",indent,
-           host->gArtsQueueOverflow) ;
-  fprintf (fp,"%s      when the we closed the host : %d\n",indent,
-           host->gArtsHostClose) ;
-  fprintf (fp,"%s      because the host was asleep : %d\n",indent,
-           host->gArtsHostSleep) ;
-  fprintf (fp,"%s    process articles unspooled : %d\n",indent,
-           host->gArtsFromTape) ;
-  fprintf (fp,"%s    process articles requeued from dropped connections : %d\n",
-           indent, host->gArtsCxnDrop) ;
-
-  fprintf (fp,"%s    average (mean) defer length : %.1f\n", indent,
-          (double) host->dlAccum / cnt) ;
-  fprintf (fp,"%s    average (mean) queue length : %.1f\n", indent,
-           (double) host->blAccum / cnt) ;
-  fprintf (fp,"%s      percentage of the time empty : %.1f\n", indent,
-           100.0 * host->blNone / cnt) ;
-  fprintf (fp,"%s      percentage of the time >0%%-25%% : %.1f\n", indent,
-           100.0 * host->blQuartile[0] / cnt) ;
-  fprintf (fp,"%s      percentage of the time 25%%-50%% : %.1f\n", indent,
-           100.0 * host->blQuartile[1] / cnt) ;
-  fprintf (fp,"%s      percentage of the time 50%%-75%% : %.1f\n", indent,
-           100.0 * host->blQuartile[2] / cnt) ;
-  fprintf (fp,"%s      percentage of the time 75%%-<100%% : %.1f\n", indent,
-           100.0 * host->blQuartile[3] / cnt) ;
-  fprintf (fp,"%s      percentage of the time full : %.1f\n", indent,
-           100.0 * host->blFull / cnt) ;
-  fprintf (fp,"%s      number of samples : %u\n", indent, host->blCount) ;
-
-  fprintf (fp,"%s    firstConnectTime : %s",indent,
-           ctime (&host->firstConnectTime));
-  fprintf (fp,"%s    connectTime : %s",indent,ctime (&host->connectTime));
-  fprintf (fp,"%s    spoolTime : %s",indent,ctime (&host->spoolTime)) ;
-  fprintf (fp,"%s    last-spool-time : %s",indent,
-           ctime (&host->lastSpoolTime)) ;
-  
-#if 0
-  fprintf (fp,"%s    tape {\n",indent) ;
-  printTapeInfo (host->myTape,fp,indentAmt + INDENT_INCR) ;
-  fprintf (fp,"%s    }\n",indent) ;
-#else
-  fprintf (fp,"%s    tape : %p\n",indent,(void *) host->myTape) ;
-#endif
-  
-  fprintf (fp,"%s    QUEUED articles {\n",indent) ;
-  for (qe = host->queued ; qe != NULL ; qe = qe->next)
-    {
-#if 0
-      printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
-      fprintf (fp,"%s    %p\n",indent,(void *) qe->article) ;
-#endif
-    }
-  
-  fprintf (fp,"%s    }\n",indent) ;
-  
-  fprintf (fp,"%s    IN PROCESS articles {\n",indent) ;
-  for (qe = host->processed ; qe != NULL ; qe = qe->next)
-    {
-#if 0
-      printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
-      fprintf (fp,"%s    %p\n",indent,(void *) qe->article) ;
-#endif
-    }
-  
-  fprintf (fp,"%s    }\n",indent) ;
-  fprintf (fp,"%s    DEFERRED articles {\n",indent) ;
-  for (qe = host->deferred ; qe != NULL ; qe = qe->next)
-    {
-#if 0
-       printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
-       fprintf (fp,"%s    %p\n",indent,(void *) qe->article) ;
-#endif
-    }
-
-  fprintf (fp,"%s    }\n",indent) ;
-  fprintf (fp,"%s    DEFERRED articles {\n",indent) ;
-  for (qe = host->deferred ; qe != NULL ; qe = qe->next)
-    {
-#if 0
-      printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
-      fprintf (fp,"%s    %p\n",indent,(void *) qe->article) ;
-#endif
-    }
-  
-  fprintf (fp,"%s    }\n",indent) ;
-
-  
-  
-  fprintf (fp,"%s    Connections {\n",indent) ;
-  for (i = 0 ; i < host->maxConnections ; i++)
-    {
-#if 0
-      if (host->connections[i] != NULL)
-        printCxnInfo (*cxn,fp,indentAmt + INDENT_INCR) ;
-#else
-      fprintf (fp,"%s        %p\n",indent,(void *) host->connections[i]) ;
-#endif
-    }
-  fprintf (fp,"%s    }\n",indent) ;
-
-  fprintf (fp,"%s    Active Connections {\n%s        ",indent,indent) ;
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->cxnActive[i])
-      fprintf (fp," [%d:%p]",i,(void *) host->connections[i]) ;
-  fprintf (fp,"\n%s    }\n",indent) ;
-
-  fprintf (fp,"%s    Sleeping Connections {\n%s        ",indent,indent) ;
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->cxnSleeping[i])
-      fprintf (fp," [%d:%p]",i,(void *) host->connections[i]) ;
-  fprintf (fp,"\n%s    }\n",indent) ;
-
-  fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-
-
-\f
-/* close down all the connections of the Host. All articles that are in
- * processes are still pushed out and then a QUIT is issued. The Host will
- * also spool all inprocess articles to tape incase the process is about to
- * be killed (they'll be refused next time around). When all Connections
- * report that they're gone, then the Host will delete itself.
- */
-void hostClose (Host host)
-{
-  unsigned int i ;
-  unsigned int cxnCount ;
-
-  d_printf (1,"Closing host %s\n",host->params->peerName) ;
-  
-  queuesToTape (host) ;
-  delTape (host->myTape) ;
-  host->myTape = NULL ;
-  
-  hostLogStats (host,true) ;
-
-  clearTimer (host->statsId) ;
-  clearTimer (host->ChkCxnsId) ;
-  clearTimer (host->deferredId) ;
-  
-  host->connectTime = 0 ;
-
-  /* when we call cxnTerminate() on the last Connection, the Host objects
-     will end up getting deleted out from under us (via hostCxnGone()). If
-     we are running with a malloc that scribbles over memory after freeing
-     it, then we'd fail in the second for loop test. Trying to access
-     host->maxConnections. */
-  for (i = 0, cxnCount = 0 ; i < host->maxConnections ; i++) 
-    cxnCount += (host->connections [i] != NULL ? 1 : 0) ;
-  for (i = 0 ; i < cxnCount ; i++)
-    if (host->connections[i] != NULL)
-      cxnTerminate (host->connections [i]) ;
-}
-
-\f
-/*
- * check if host should get more connections opened, or some closed...
- */
-void hostChkCxns(TimeoutId tid UNUSED, void *data) {
-  Host host = (Host) data;
-  unsigned int currArticles, currSentArticles, currTotalArticles, newMaxCxns ;
-  double lastAPS, currAPS, percentTaken, ratio ;
-  double backlogRatio, backlogMult;
-
-  if(!host->maxCxnChk)
-    return;
-
-  ASSERT(host->params != NULL);
-
-  if(host->secsInLastPeriod > 0) 
-    lastAPS = host->artsProcLastPeriod / (host->secsInLastPeriod * 1.0);
-  else
-    lastAPS = host->artsProcLastPeriod * 1.0;
-
-  newMaxCxns = host->maxConnections;
-
-  currArticles =        (host->gArtsAccepted + host->gArtsRejected +
-                        (host->gArtsNotWanted / 4)) - host->lastCheckPoint ;
-
-  host->lastCheckPoint = (host->gArtsAccepted + host->gArtsRejected +
-                        (host->gArtsNotWanted / 4));
-
-  currSentArticles = host->gArtsAccepted + host->gArtsRejected
-                      - host->lastSentCheckPoint ;
-
-  host->lastSentCheckPoint = host->gArtsAccepted + host->gArtsRejected;
-
-  currTotalArticles = host->gArtsAccepted + host->gArtsRejected
-                      + host->gArtsRejected + host->gArtsQueueOverflow
-                     - host->lastTotalCheckPoint ;
-
-  host->lastTotalCheckPoint = host->gArtsAccepted + host->gArtsRejected
-                      + host->gArtsRejected + host->gArtsQueueOverflow ;
-
-  currAPS = currArticles / (host->nextCxnTimeChk * 1.0) ;
-
-  percentTaken = currSentArticles * 1.0 /
-    ((currTotalArticles==0)?1:currTotalArticles);
-
-  /* Get how full the queue is currently */
-  backlogRatio = (host->backlog * 1.0 / hostHighwater);
-  backlogMult = 1.0/(1.0-host->params->dynBacklogFilter);
-
-  d_printf(1,"%s hostChkCxns - entry filter=%3.3f blmult=%3.3f blratio=%3.3f\n",host->params->peerName,host->backlogFilter, backlogMult, backlogRatio);
-
-  ratio = 0.0; /* ignore APS by default */
-
-  switch (host->params->dynamicMethod)
-    {
-      case METHOD_COMBINED:
-        /* When a high % of articles is being taken, take notice of the
-        * APS values. However for smaller %s, quickly start to ignore this
-        * and concentrate on queue sizes
-        */
-        ratio = percentTaken * percentTaken;
-       /* nobreak; */
-      case METHOD_QUEUE:
-        /* backlogFilter is an IIR filtered version of the backlogRatio.
-        */
-        host->backlogFilter *= host->params->dynBacklogFilter;
-       /* Penalise anything over the backlog HWM twice as severely
-        * (otherwise we end up feeding some sites constantly
-        * just below the HWM. This way random noise makes
-        * such sites jump to one more connection
-        *
-        * Use factor (1-ratio) so if ratio is near 1 we ignore this
-        */
-       if (backlogRatio>host->params->dynBacklogLowWaterMark/100.0)
-         host->backlogFilter += (backlogRatio+1.0)/2.0 * (1.0-ratio);
-       else
-         host->backlogFilter += backlogRatio * (1.0-ratio);
-
-       /*
-        * Now bump it around for APS too
-        */
-       if ((currAPS - lastAPS) >= 0.1)
-         host->backlogFilter += ratio*((currAPS - lastAPS) + 1.0);
-       else if ((currAPS - lastAPS) < -.2)
-         host->backlogFilter -= ratio;
-       
-       d_printf(1,"%s hostChkCxns - entry hwm=%3.3f lwm=%3.3f new=%3.3f [%3.3f,%3.3f]\n",
-              host->params->peerName,host->params->dynBacklogHighWaterMark,
-              host->params->dynBacklogLowWaterMark,host->backlogFilter, 
-              (host->params->dynBacklogLowWaterMark * backlogMult / 100.0),
-              (host->params->dynBacklogHighWaterMark * backlogMult / 100.0));
-
-        if (host->backlogFilter <
-           (host->params->dynBacklogLowWaterMark * backlogMult / 100.0))
-         newMaxCxns--;
-       else if (host->backlogFilter >
-                (host->params->dynBacklogHighWaterMark * backlogMult / 100.0))
-         newMaxCxns++;
-       break;
-      case METHOD_STATIC:
-       /* well not much to do, just check maxConnection = absMaxConnections */
-       ASSERT (host->maxConnections == MAXCONLIMIT(host->params->absMaxConnections));
-       break;
-      case METHOD_APS:
-       if ((currAPS - lastAPS) >= 0.1)
-         newMaxCxns += (int)(currAPS - lastAPS) + 1 ;
-       else if ((currAPS - lastAPS) < -.2)
-         newMaxCxns--;
-       break;
-    }
-
-  d_printf(1, "hostChkCxns: Chngs %f\n", currAPS - lastAPS);
-
-  if (newMaxCxns < 1) newMaxCxns=1;
-  if (newMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
-    newMaxCxns = MAXCONLIMIT(host->params->absMaxConnections);
-
-  if (newMaxCxns != host->maxConnections)
-    {
-      notice ("%s hostChkCxns - maxConnections was %d now %d",
-              host->params->peerName, host->maxConnections,newMaxCxns);
-      host->backlogFilter= ((host->params->dynBacklogLowWaterMark
-                            + host->params->dynBacklogHighWaterMark)
-                           /200.0 * backlogMult);
-      host->artsProcLastPeriod = currArticles ;
-      host->secsInLastPeriod = host->nextCxnTimeChk ;
-
-      /* Alter MaxConnections and in doing so ensure we connect new
-        cxns immediately if we are adding stuff
-       */
-      hostAlterMaxConnections(host, host->params->absMaxConnections,
-                             newMaxCxns, true);
-  }
-
-  if(host->nextCxnTimeChk <= 240) host->nextCxnTimeChk *= 2;
-  else host->nextCxnTimeChk = 300;
-  d_printf(1, "prepareSleep hostChkCxns, %d\n", host->nextCxnTimeChk);
-  host->ChkCxnsId = prepareSleep(hostChkCxns, host->nextCxnTimeChk, host);
-}
-
-\f
-/*
- * have the Host transmit the Article if possible.
- */
-void hostSendArticle (Host host, Article article)
-{
-  ASSERT(host->params != NULL);
-  if (host->spoolTime > 0)
-    {                           /* all connections are asleep */
-      host->artsHostSleep++ ;
-      host->gArtsHostSleep++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape, article) ;
-      return ;
-    }
-
-  /* at least one connection is feeding or waiting and there's no backlog */
-  if (host->queued == NULL)
-    {
-      unsigned int idx ;
-      Article extraRef ;
-      Connection cxn = NULL ;
-      
-      extraRef = artTakeRef (article) ; /* the referrence we give away */
-      
-      /* stick on the queue of articles we've handed off--we're hopeful. */
-      queueArticle (article,&host->processed,&host->processedTail, 0) ;
-
-      if (host->params->minQueueCxn) {
-        Connection x_cxn = NULL ;
-        unsigned int x_queue = host->params->maxChecks + 1 ;
-
-        for (idx = 0 ; x_queue > 0 && idx < host->maxConnections ; idx++)
-          if ((cxn = host->connections[idx]) != host->notThisCxn) {
-            if (!host->cxnActive [idx]) {
-              if (!host->cxnSleeping [idx]) {
-                if (cxnTakeArticle (cxn, extraRef)) {
-                  host->gNoQueue++ ;
-                  return ;
-                } else
-                  d_printf (1,"%s Inactive connection %d refused an article\n",
-                           host->params->peerName,idx) ;
-              }
-            } else {
-              unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) ;
-              if (queue < x_queue) {
-                x_queue = queue ;
-                x_cxn = cxn ;
-              }
-            }
-          }
-
-        if (x_cxn != NULL && cxnTakeArticle (x_cxn, extraRef)) {
-          if (x_queue == 0) host->gNoQueue++ ;
-          else              host->gCxnQueue += x_queue ;
-          return ;
-        }
-
-      } else {
-
-        /* first we try to give it to one of our active connections. We
-           simply start at the bottom and work our way up. This way
-           connections near the end of the list will get closed sooner from
-           idleness. */
-        for (idx = 0 ; idx < host->maxConnections ; idx++)
-          {
-            if (host->cxnActive [idx] &&
-                (cxn = host->connections[idx]) != host->notThisCxn &&
-                cxnTakeArticle (cxn, extraRef)) {
-              unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
-              if (queue == 0) host->gNoQueue++ ;
-              else            host->gCxnQueue += queue ;
-             return ;
-            }
-          }
-
-        /* Wasn't taken so try to give it to one of the waiting connections. */
-        for (idx = 0 ; idx < host->maxConnections ; idx++)
-          if (!host->cxnActive [idx] && !host->cxnSleeping [idx] &&
-              (cxn = host->connections[idx]) != host->notThisCxn)
-            {
-              if (cxnTakeArticle (cxn, extraRef)) {
-                unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
-                if (queue == 0) host->gNoQueue++ ;
-                else            host->gCxnQueue += queue ;
-                return ;
-              } else
-                d_printf (1,"%s Inactive connection %d refused an article\n",
-                         host->params->peerName,idx) ;
-            }
-      }
-
-      /* this'll happen if all connections are feeding and all
-         their queues are full, or if those not feeding are asleep. */
-      d_printf (1, "Couldn't give the article to a connection\n") ;
-      
-      delArticle (extraRef) ;
-          
-      remArticle (article,&host->processed,&host->processedTail) ;
-      if (!cxnCheckstate (cxn))
-        {
-          host->artsToTape++ ;
-          host->gArtsToTape++ ;
-          procArtsToTape++ ;
-          tapeTakeArticle (host->myTape,article) ;
-          return ;
-        }
-    }
-
-  /* either all the per connection queues were full or we already had
-     a backlog, so there was no sense in checking. */
-  queueArticle (article,&host->queued,&host->queuedTail, 0) ;
-    
-  host->backlog++ ;
-  backlogToTape (host) ;
-}
-
-
-
-
-
-
-\f
-/*
- * called by the Host's connection when the remote is refusing postings
- * from us becasue we're not allowed (banner code 400).
- */
-void hostCxnBlocked (Host host, Connection cxn, char *reason)
-{
-  ASSERT(host->params != NULL);
-#ifndef NDEBUG
-  {
-    unsigned int i ;
-    
-    for (i = 0 ; i < host->maxConnections ; i++)
-      if (host->connections [i] == cxn)
-        ASSERT (host->cxnActive [i] == false) ;
-  }
-#endif
-
-  if (host->blockedReason == NULL)
-    host->blockedReason = xstrdup (reason) ;
-  
-  if (host->activeCxns == 0 && host->spoolTime == 0)
-    {
-      host->blockedCxn = cxn ;  /* to limit log notices */
-      notice ("%s remote cannot accept articles initial: %s",
-              host->params->peerName, reason) ;
-    }
-  else if (host->activeCxns > 0 && !host->notifiedChangedRemBlckd)
-    {
-      notice ("%s remote cannot accept articles change: %s",
-              host->params->peerName, reason) ;
-      host->notifiedChangedRemBlckd = true ;
-    }
-  else if (host->spoolTime != 0 && host->blockedCxn == cxn)
-    {
-      notice ("%s remote cannot accept articles still: %s",
-              host->params->peerName, reason) ;
-    }
-  
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it gets a response back to the MODE
- * STREAM command. It's now that we consider the connection usable.
- */
-void hostRemoteStreams (Host host, Connection cxn, bool doesStreaming)
-{
-  unsigned int i ;
-
-  host->blockedCxn = NULL ;
-  if (host->blockedReason != NULL)
-    free (host->blockedReason) ;
-  host->blockedReason = NULL ;
-  
-  /* we may have told the connection to quit while it was in the middle
-     of connecting */
-  if (amClosing (host))
-    return ;
-  
-  if (host->connectTime == 0)   /* first connection for this cycle. */
-    {
-      if (doesStreaming && host->params->wantStreaming)
-        notice ("%s remote MODE STREAM", host->params->peerName) ;
-      else if (doesStreaming)
-        notice ("%s remote MODE STREAM disabled", host->params->peerName) ;
-      else
-        notice ("%s remote MODE STREAM failed", host->params->peerName) ;
-
-      if (host->spoolTime > 0)
-        hostStopSpooling (host) ;
-
-      /* set up the callback for statistics logging. */
-      if (host->statsId != 0)
-        clearTimer (host->statsId) ;
-      host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-
-      if (host->ChkCxnsId != 0)
-      clearTimer (host->ChkCxnsId);
-      host->ChkCxnsId = prepareSleep (hostChkCxns, 30, host) ;
-
-      host->remoteStreams = (host->params->wantStreaming ? doesStreaming : false) ;
-
-      host->connectTime = theTime() ;
-      if (host->firstConnectTime == 0)
-        host->firstConnectTime = host->connectTime ;
-    }
-  else if (host->remoteStreams != doesStreaming && host->params->wantStreaming)
-    notice ("%s remote MODE STREAM change", host->params->peerName) ;
-
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->connections [i] == cxn)
-      {
-        host->cxnActive [i] = true ;
-        if (host->cxnSleeping [i])
-          host->sleepingCxns-- ;
-        host->cxnSleeping [i] = false ;
-        break ;
-      }
-
-  ASSERT (i != host->maxConnections) ;
-
-  host->activeCxns++ ;
-
-  hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the connection when it is no longer connected to the
- * remote. Perhaps due to getting a code 400 to an IHAVE, or due to a
- * periodic close.
- */
-void hostCxnDead (Host host, Connection cxn)
-{
-  unsigned int i ;
-    
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->connections [i] == cxn)
-      {
-        if (host->cxnActive [i]) /* won't be active if got 400 on banner */
-          {
-            host->cxnActive [i] = false ;
-            host->activeCxns-- ;
-
-            if (!amClosing (host) && host->activeCxns == 0)
-              {
-                clearTimer (host->statsId) ;
-                clearTimer (host->ChkCxnsId) ;
-                hostLogStats (host,true) ;
-                host->connectTime = 0 ;
-              }
-          }
-        else if (host->cxnSleeping [i]) /* cxnNuke can be called on sleepers  */
-          {
-            host->cxnSleeping [i] = false ;
-            host->sleepingCxns-- ;
-          }
-
-        break ;
-      }
-
-  ASSERT (i < host->maxConnections) ;
-  hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it is going to sleep so the Host won't
- * bother trying to give it Articles
- */
-void hostCxnSleeping (Host host, Connection cxn)
-{
-  unsigned int i ;
-
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->connections [i] == cxn)
-      {
-        if (!host->cxnSleeping [i]) 
-          {
-            host->cxnSleeping [i] = true ;
-            host->sleepingCxns++ ;
-          }
-
-        if (host->spoolTime == 0 && host->sleepingCxns >= host->maxConnections)
-          hostStartSpooling (host) ;
-
-        break ;
-      }
-
-  ASSERT (i < host->maxConnections) ;
-
-  hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it goes into the waiting state.
- */
-void hostCxnWaiting (Host host, Connection cxn)
-{
-  unsigned int i ;
-
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->connections [i] == cxn)
-      {
-        if (host->cxnSleeping [i])
-          host->sleepingCxns-- ;
-        host->cxnSleeping [i] = false ;
-        break ;
-      }
-
-  ASSERT (i < host->maxConnections) ;
-
-  if (host->spoolTime > 0)
-    hostStopSpooling (host) ;
-
-  hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it is about to delete itself.
- */
-bool hostCxnGone (Host host, Connection cxn)
-{
-  unsigned int i;
-  bool oneThere = false ;
-  char msgstr[SMBUF] ;
-
-  /* forget about the Connection and see if we are still holding any live
-     connections still. */
-  for (i = 0 ; i < host->maxConnections ; i++)
-    if (host->connections [i] == cxn)
-      {
-        if (!amClosing (host))
-          {
-            warn ("%s:%d connection vanishing", host->params->peerName, i) ;
-          }
-        host->connections [i] = NULL ;
-        if (host->cxnActive [i])
-          {
-            host->cxnActive [i] = false ;
-            host->activeCxns-- ;
-          }
-        else if (host->cxnSleeping [i])
-          {
-            host->cxnSleeping [i] = false ;
-            host->sleepingCxns-- ;
-          }
-      }
-    else if (host->connections [i] != NULL)
-      oneThere = true ;
-
-  /* remove the host if it has no connexions */
-  if ( !oneThere )
-    {
-      time_t now = theTime() ;
-      unsigned int hostsLeft ;
-
-      if (host->firstConnectTime > 0) {
-        snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
-                 host->gArtsSizeAccepted, host->gArtsSizeRejected);
-        notice ("%s global seconds %ld offered %d accepted %d refused %d"
-                " rejected %d missing %d %s spooled %d unspooled %d",
-                host->params->peerName, (long) (now - host->firstConnectTime),
-                host->gArtsOffered, host->gArtsAccepted,
-                host->gArtsNotWanted, host->gArtsRejected,
-                host->gArtsMissing, msgstr,
-                host->gArtsToTape, host->gArtsFromTape) ;
-      }
-
-      hostsLeft = listenerHostGone (host->listener, host) ;
-      delHost (host) ;
-
-      if (hostsLeft == 0) {
-        snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
-                 procArtsSizeAccepted, procArtsSizeRejected);
-        notice ("ME global seconds %ld offered %ld accepted %ld refused %ld"
-                " rejected %ld missing %ld %s spooled %ld unspooled %ld",
-                (long) (now - start),
-                procArtsOffered, procArtsAccepted,
-                procArtsNotWanted,procArtsRejected,
-                procArtsMissing, msgstr,
-                procArtsToTape, procArtsFromTape) ;
-      }
-      
-      /* return true if that was the last host */
-      return (hostsLeft == 0 ? true : false) ;
-    }
-
-  /* return false because there is still at least one host (this one) */
-  return false ;
-}
-
-
-
-
-
-
-\f
-/*
- * The connections has offered an article to the remote.
- */
-void hostArticleOffered (Host host, Connection cxn UNUSED)
-{
-  host->artsOffered++ ;
-  host->gArtsOffered++ ;
-  procArtsOffered++ ;
-}
-
-
-
-
-
-
-\f
-/*
- * Article was succesfully transferred.
- */
-void hostArticleAccepted (Host host, Connection cxn, Article article)
-{
-  const char *filename = artFileName (article) ;
-  const char *msgid = artMsgId (article) ;
-  double len = artSize (article);
-
-  d_printf (5,"Article %s (%s) was transferred\n", msgid, filename) ;
-  
-  host->artsAccepted++ ;
-  host->gArtsAccepted++ ;
-  procArtsAccepted++ ;
-  host->artsSizeAccepted += len ;
-  host->gArtsSizeAccepted += len ;
-  procArtsSizeAccepted += len ;
-
-  /* host has two references to the article here... the parameter `article'
-     and the queue */
-
-  delArticle (article) ;        /* drop the parameter reference */
-
-  if (!amClosing (host))
-    articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/*
- * remote said no thanks to an article.
- */
-void hostArticleNotWanted (Host host, Connection cxn, Article article)
-{
-  const char *filename = artFileName (article) ;
-  const char *msgid = artMsgId (article) ;
-
-  d_printf (5,"Article %s (%s) was not wanted\n", msgid, filename) ;
-  
-  host->artsNotWanted++ ;
-  host->gArtsNotWanted++ ;
-  procArtsNotWanted++ ;
-  
-  
-  /* host has two references to the article here... `article' and the
-     queue */
-
-  delArticle (article) ;        /* drop the `article' reference */
-  
-  if (!amClosing (host)) 
-    articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/*
- * remote rejected the article after it was was transferred
- */
-void hostArticleRejected (Host host, Connection cxn, Article article) 
-{
-  const char *filename = artFileName (article) ;
-  const char *msgid = artMsgId (article) ;
-  double len = artSize (article);
-
-  d_printf (5,"Article %s (%s) was rejected\n", msgid, filename) ;
-  
-  host->artsRejected++ ;
-  host->gArtsRejected++ ;
-  procArtsRejected++ ;
-  host->artsSizeRejected += len ;
-  host->gArtsSizeRejected += len ;
-  procArtsSizeRejected += len ;
-
-  /* host has two references to the article here... `article' and the queue */
-
-  delArticle (article) ;        /* drop the `article' reference */
-
-  if (!amClosing (host))
-    articleGone (host,cxn,article) ;
-}
-
-
-
-
-
-
-\f
-/*
- * The remote wants us to retry the article later.
- */
-void hostArticleDeferred (Host host, Connection cxn, Article article) 
-{
-  host->artsDeferred++ ;
-  host->gArtsDeferred++ ;
-  procArtsDeferred++ ;
-
-
-  if (!amClosing (host))
-    {
-      Article extraRef ;
-      int deferTimeout = 5 ; /* XXX - should be tunable */
-      time_t now = theTime() ;
-
-      extraRef = artTakeRef (article) ; /* hold a reference until requeued */
-      articleGone (host,cxn,article) ; /* drop from the queue */
-
-      if (host->deferred == NULL)
-       {
-           if (host->deferredId != 0)
-             clearTimer (host->deferredId) ;
-           host->deferredId = prepareSleep (hostDeferredArtCbk, deferTimeout,
-                                            host) ;
-        }
-
-      queueArticle (article,&host->deferred,&host->deferredTail,
-                   now + deferTimeout) ;
-      host->deferLen++ ;
-      backlogToTape (host) ;
-      delArticle (extraRef) ;
-    }
-  else
-    delArticle(article); /*drop parameter reference if not sent to tape*/
-}
-
-
-
-
-
-
-\f
-/*
- * The Connection is giving the article back to the Host, but it doesn't
- * want a new one in return.
- */
-void hostTakeBackArticle (Host host, Connection cxn UNUSED, Article article) 
-{
-  if (!amClosing (host)) 
-    {
-      Article extraRef ;
-
-      host->artsCxnDrop++ ;
-      host->gArtsCxnDrop++ ;
-      extraRef = artTakeRef (article) ; /* hold a reference until requeued */
-      articleGone (host,NULL,article) ; /* drop from the queue */
-      host->notThisCxn = cxn;
-      hostSendArticle (host, article) ; /* requeue it */
-      host->notThisCxn = NULL;
-      delArticle (extraRef) ;
-    }
-  else
-    delArticle(article); /*drop parameter reference if not sent to tape*/
-
-}
-
-
-
-
-
-
-\f
-/*
- * The disk file for the article is no longer valid
- */
-void hostArticleIsMissing (Host host, Connection cxn, Article article)
-{
-  const char *filename = artFileName (article) ;
-  const char *msgid = artMsgId (article) ;
-
-  d_printf (5, "%s article is missing %s %s\n", host->params->peerName, msgid, filename) ;
-    
-  host->artsMissing++ ;
-  host->gArtsMissing++ ;
-  procArtsMissing++ ;
-
-  /* host has two references to the article here... `article' and the
-     queue */
-
-  delArticle (article) ;        /* drop the `article' reference */
-
-  if (!amClosing (host))
-    articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/* The Connection wants something to do. This is called by the Connection
- * after it has transferred an article. This is what keeps the pipes full
- * of data off the tapes if the input from inn is idle.
- */
-bool hostGimmeArticle (Host host, Connection cxn)
-{
-  Article article = NULL ;
-  bool gaveSomething = false ;
-  size_t amtToGive = cxnQueueSpace (cxn) ; /* may be more than one */
-  int feed = 0 ;
-
-  if (amClosing (host))
-    {
-      d_printf (5,"%s no article to give due to closing\n",host->params->peerName) ;
-
-      return false ;
-    }
-
-  if (amtToGive == 0)
-    d_printf (5,"%s Queue space is zero....\n",host->params->peerName) ;
-  
-  while (amtToGive > 0)
-    {
-      bool tookIt ;
-      unsigned int queue = host->params->maxChecks - amtToGive ;
-
-      if (host->params->backlogFeedFirst) {
-       if ((article = getArticle (host->myTape)) != NULL)
-         feed = 2;
-       else if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
-         feed = 1;
-       else
-         feed = 3;
-      }
-      else {
-       if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
-         feed = 1;
-       else if ((article = getArticle (host->myTape)) != NULL)
-         feed = 2;
-       else
-         feed = 3;
-      }
-
-      switch (feed) {
-      case 1:
-          host->backlog-- ;
-          tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
-
-          ASSERT (tookIt == true) ;
-
-          if (queue == 0) host->gNoQueue++ ;
-          else            host->gCxnQueue += queue ;
-
-          queueArticle (article,&host->processed,&host->processedTail, 0) ;
-          amtToGive-- ;
-
-          gaveSomething = true ;
-          break ;
-
-      case 2:
-          /* go to the tapes */
-          tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
-
-          ASSERT (tookIt == true) ;
-
-          if (queue == 0) host->gNoQueue++ ;
-          else            host->gCxnQueue += queue ;
-
-          host->artsFromTape++ ;
-          host->gArtsFromTape++ ;
-          procArtsFromTape++ ;
-          queueArticle (article,&host->processed,&host->processedTail, 0) ;
-          amtToGive-- ;
-
-          gaveSomething = true ;
-
-          break ;
-
-      case 3:
-          /* we had nothing left to give... */
-          
-          if (host->processed == NULL) /* and if nothing outstanding... */
-            listenerHostIsIdle (host->listener,host) ; /* tell our owner */
-  
-          amtToGive = 0 ;
-
-          break ;
-      }
-    }
-
-  return gaveSomething ;
-}
-
-
-
-
-
-
-\f
-/*
- * get the name that INN uses for this host
- */
-const char *hostPeerName (Host host)
-{
-  ASSERT (host != NULL) ;
-    
-  return host->params->peerName ;
-}
-
-/*
- * get the IPv4 bindaddress
- */
-const struct sockaddr_in *hostBindAddr (Host host)
-{
-  ASSERT (host != NULL) ;
-    
-  return host->params->bindAddr ;
-}
-
-#ifdef HAVE_INET6
-/*
- * get the IPv6 bindaddress
- */
-const struct sockaddr_in6 *hostBindAddr6 (Host host)
-{
-  ASSERT (host != NULL) ;
-    
-  return host->params->bindAddr6 ;
-}
-
-/*
- * get the address family
- */
-int hostAddrFamily (Host host)
-{
-  ASSERT (host != NULL) ;
-
-  return host->params->family ;
-}
-#endif
-
-/*
- * get the username and password for authentication
- */
-const char *hostUsername (Host host)
-{
-  ASSERT (host != NULL) ;
-
-  return host->params->username ;
-}
-const char *hostPassword (Host host)
-{
-  ASSERT (host != NULL) ;
-
-  return host->params->password ;
-}
-
-
-/* return true if the Connections for this host should attempt to do
-   streaming. */
-bool hostWantsStreaming (Host host)
-{
-  return host->params->wantStreaming ;
-}
-
-unsigned int hostMaxChecks (Host host)
-{
-  return host->params->maxChecks ;
-}
-
-bool hostDropDeferred (Host host)
-{
-  return host->params->dropDeferred ;
-}
-
-
-
-
-
-
-\f
-/**********************************************************************/
-/**                       CLASS FUNCTIONS                            **/
-/**********************************************************************/
-
-/*
- * Set the state of whether each Connection is told to log its stats when
- * its controlling Host logs its stats.
- */
-void hostLogConnectionStats (bool val)
-{
-  logConnectionStats = val ;
-}
-
-
-bool hostLogConnectionStatsP (void)
-{
-  return logConnectionStats ;
-}
-
-
-
-/*
- * Called by one of the Host's Connection's when it (the Connection)
- * switches into or out of no-CHECK mode.
- */
-void hostLogNoCheckMode (Host host, bool on, double low, double cur, double high)
-{
-  if (on && host->loggedModeOn == false)
-    {
-      notice ("%s mode no-CHECK entered [%.2f,%.2f,%.2f]",
-              host->params->peerName, low, cur, high) ;
-      host->loggedModeOn = true ;
-    }
-  else if (!on && host->loggedModeOff == false) 
-    {
-      notice ("%s mode no-CHECK exited [%.2f,%.2f,%.2f]",
-              host->params->peerName, low, cur, high) ;
-      host->loggedModeOff = true ;
-    }
-}
-
-
-
-void hostSetStatusFile (const char *filename)
-{
-  FILE *fp ;
-  
-  if (filename == NULL)
-    die ("Can't set status file name with a NULL filename\n") ;
-  else if (*filename == '\0')
-    die ("Can't set status file name with a empty string\n") ;
-
-  if (*filename == '/')
-    statusFile = xstrdup (filename) ;
-  else
-    statusFile = concatpath (innconf->pathlog,filename) ;
-
-  if ((fp = fopen (statusFile,"w")) == NULL)
-    {
-      syslog (LOG_ERR,"Status file is not a valid pathname: %s",
-              statusFile) ;
-      free (statusFile) ;
-      statusFile = NULL ;
-    }
-  else
-    fclose (fp) ;
-}
-
-void gHostStats (void)
-{
-  Host h ;
-  time_t now = theTime() ;
-  char msgstr[SMBUF] ;
-
-  for (h = gHostList ; h != NULL ; h = h->next)
-      if (h->firstConnectTime > 0) {
-        snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
-                 h->gArtsSizeAccepted, h->gArtsSizeRejected);
-        notice ("%s global seconds %ld offered %d accepted %d refused %d"
-                " rejected %d missing %d %s spooled %d unspooled %d",
-                h->params->peerName,
-                (long) (now - h->firstConnectTime),
-                h->gArtsOffered, h->gArtsAccepted,
-                h->gArtsNotWanted, h->gArtsRejected,
-                h->gArtsMissing, msgstr,
-                h->gArtsToTape, h->gArtsFromTape) ;
-      }
-}
-
-
-
-/**********************************************************************/
-/**                      PRIVATE FUNCTIONS                           **/
-/**********************************************************************/
-
-
-
-
-#define INHERIT        1
-#define NO_INHERIT 0
-
-\f
-static HostParams hostDetails (scope *s,
-                              char *name,
-                              bool isDefault,
-                              FILE *fp)
-{
-  long iv ;
-  int bv, vival, inherit ;
-  HostParams p;
-  char * q;
-  double rv, l, h ;
-  value * v;
-
-  p=newHostParams(isDefault?NULL:defaultParams);
-
-  if (isDefault)
-    {
-      ASSERT (name==NULL);
-    }
-  else
-    {
-      if (name)
-       {
-         p->peerName=xstrdup(name);
-       }
-  
-      if (s != NULL)
-        {
-         if (getString (s,IP_NAME,&q,NO_INHERIT))
-           p->ipName = q ;
-         else
-           p->ipName = xstrdup (name) ;
-        }
-
-      if (getString (s,"username",&q,NO_INHERIT))
-       p->username = q;
-      if (getString (s,"password",&q,NO_INHERIT))
-       p->password = q;
-
-      if (p->username != NULL && p->password == NULL)
-       logOrPrint (LOG_ERR,fp,"cannot find password for %s",p->peerName);
-      if (p->username == NULL && p->password != NULL)
-       logOrPrint (LOG_ERR,fp,"cannot find username for %s",p->peerName);
-
-    }
-
-#ifdef HAVE_INET6
-  if (getString(s,"bindaddress6",&q,isDefault?NO_INHERIT:INHERIT))
-    {
-      struct addrinfo *res, hints;
-
-      if (strcmp(q, "none") == 0)
-        p->family = AF_INET;
-      else if (p->family == AF_INET)
-        p->family = 0;
-
-      if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
-        strcmp(q, "none") != 0)
-        {
-          memset( &hints, 0, sizeof( hints ) );
-          hints.ai_flags = AI_NUMERICHOST;
-          if( getaddrinfo( q, NULL, &hints, &res ) )
-     {
-       logOrPrint (LOG_ERR, fp, 
-                      "unable to determine IPv6 bind address for %s",
-                      p->peerName) ;
-            }
-          else
-            {
-              p->bindAddr6 = (struct sockaddr_in6 *) xmalloc (res->ai_addrlen);
-              memcpy( p->bindAddr6, res->ai_addr, res->ai_addrlen );
-            }
- }
-    }
-#endif
-
-    if (getString(s,"bindaddress",&q,isDefault?NO_INHERIT:INHERIT))
-    {
-      struct in_addr addr ;
-
-#ifdef HAVE_INET6
-      if (strcmp(q, "none") == 0) {
-        if (p->family) {
-          logOrPrint (LOG_ERR,fp,"cannot set both bindaddress and bindaddress6"
-                      " to \"none\" -- ignoring them for %s",p->peerName);
-          p->family = 0;
-        } else {
-          p->family = AF_INET6;
-        }
-      } else if (p->family == AF_INET6)
-        p->family = 0;
-#endif
-
-      if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
-           strcmp(q, "none") != 0)
-        {
-          if (!inet_aton(q,&addr))
-            {
-              logOrPrint (LOG_ERR, fp,
-                      "unable to determine IPv4 bind address for %s",
-                      p->peerName) ;
-            }
-          else
-            {
-              p->bindAddr = (struct sockaddr_in *)
-                              xmalloc (sizeof(struct sockaddr_in));
-              make_sin( (struct sockaddr_in *)p->bindAddr, &addr );
-            }
-        }
-    }
-
-  /* check required global defaults are there and have good values */
-  
-
-#define GETINT(sc,f,n,min,max,req,val,inh)              \
-  vival = validateInteger(f,n,min,max,req,val,sc,inh);  \
-  if (isDefault) do{                                    \
-    if(vival==VALUE_WRONG_TYPE)                         \
-      {                                                 \
-        logOrPrint(LOG_CRIT,fp,"cannot continue");      \
-        exit(1);                                        \
-      }                                                 \
-    else if(vival != VALUE_OK)                          \
-      val = 0;                                          \
-  } while(0);                                           \
-  iv = 0 ;                                              \
-  getInteger (sc,n,&iv,inh) ;                           \
-  val = (unsigned int) iv ;
-
-#define GETREAL(sc,f,n,min,max,req,val,inh)             \
-  vival = validateReal(f,n,min,max,req,val,sc,inh);     \
-  if (isDefault) do{                                    \
-    if(vival==VALUE_WRONG_TYPE)                         \
-      {                                                 \
-        logOrPrint(LOG_CRIT,fp,"cannot continue");      \
-        exit(1);                                        \
-      }                                                 \
-    else if(vival != VALUE_OK)                          \
-      rv = 0;                                           \
-  } while(0);                                           \
-  rv = 0 ;                                              \
-  getReal (sc,n,&rv,inh) ;                              \
-  val = rv ;
-
-#define GETBOOL(sc,f,n,req,val,inh)                     \
-  vival = validateBool(f,n,req,val,sc,inh);             \
-  if (isDefault) do{                                    \
-    if(vival==VALUE_WRONG_TYPE)                         \
-      {                                                 \
-        logOrPrint(LOG_CRIT,fp,"cannot continue");      \
-        exit(1);                                        \
-      }                                                 \
-    else if(vival != VALUE_OK)                          \
-      bv = 0;                                           \
-  } while(0);                                           \
-  bv = 0 ;                                              \
-  getBool (sc,n,&bv,inh)  ;                             \
-  val = (bv ? true : false);
-
-  inherit = isDefault?NO_INHERIT:INHERIT;
-  GETINT(s,fp,"article-timeout",0,LONG_MAX,REQ,p->articleTimeout, inherit);
-  GETINT(s,fp,"response-timeout",0,LONG_MAX,REQ,p->responseTimeout, inherit);
-  GETINT(s,fp,"close-period",0,LONG_MAX,REQ,p->closePeriod, inherit);
-  GETINT(s,fp,"initial-connections",0,LONG_MAX,REQ,p->initialConnections, inherit);
-  GETINT(s,fp,"max-connections",0,LONG_MAX,REQ,p->absMaxConnections, inherit);
-  GETINT(s,fp,"max-queue-size",1,LONG_MAX,REQ,p->maxChecks, inherit);
-  GETBOOL(s,fp,"streaming",REQ,p->wantStreaming, inherit);
-  GETBOOL(s,fp,"drop-deferred",REQ,p->dropDeferred, inherit);
-  GETBOOL(s,fp,"min-queue-connection",REQ,p->minQueueCxn, inherit);
-  GETREAL(s,fp,"no-check-high",0.0,100.0,REQ,p->lowPassHigh, inherit);
-  GETREAL(s,fp,"no-check-low",0.0,100.0,REQ,p->lowPassLow, inherit);
-  GETREAL(s,fp,"no-check-filter",0.1,DBL_MAX,REQ,p->lowPassFilter, inherit);
-  GETINT(s,fp,"port-number",0,LONG_MAX,REQ,p->portNum, inherit);
-  GETINT(s,fp,"backlog-limit",0,LONG_MAX,REQ,p->backlogLimit, inherit);
-
-#ifdef HAVE_INET6
-  GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
-  if (p->forceIPv4)
-    p->family = AF_INET;
-#endif
-
-  if (findValue (s,"backlog-factor",inherit) == NULL &&
-      findValue (s,"backlog-limit-high",inherit) == NULL)
-    {
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: must define at least one of backlog-factor"
-                  " and backlog-limit-high. Adding %s: %f", "backlog-factor",
-                  LIMIT_FUDGE) ;
-      addReal (s,"backlog-factor",LIMIT_FUDGE) ;
-      rv = 0 ;
-    }
-
-  GETBOOL(s,fp,"backlog-feed-first",NOTREQ,p->backlogFeedFirst, inherit);
-
-  /* Innfeed should emit a warning if backlog-feed-first is set
-     to "true" for any peer that doesn't have max-connections and
-     initial-connections both set to "1" */
-  if ((p->backlogFeedFirst)
-      && ((p->initialConnections <= 1) || (p->absMaxConnections != 1)))
-    {
-      if (p->peerName != NULL)
-       logOrPrint (LOG_WARNING,fp,
-                   "ME config: innfeed will make more than one connection"
-                   " to peer %s, but backlog-feed-first is set", p->peerName);
-      else
-       logOrPrint (LOG_WARNING,fp,
-                   "ME config: innfeed will make more than one connection"
-                   " to peer, but backlog-feed-first is set");
-    }
-
-  GETINT(s,fp,"backlog-limit-high",0,LONG_MAX,NOTREQNOADD,p->backlogLimitHigh, inherit);
-  GETREAL(s,fp,"backlog-factor",1.0,DBL_MAX,NOTREQNOADD,p->backlogFactor, inherit);
-
-  GETINT(s,fp,"dynamic-method",0,3,REQ,p->dynamicMethod, inherit);
-  GETREAL(s,fp,"dynamic-backlog-filter",0.0,DBL_MAX,REQ,p->dynBacklogFilter, inherit);
-  GETREAL(s,fp,"dynamic-backlog-low",0.0,100.0,REQ,p->dynBacklogLowWaterMark, inherit);
-  GETREAL(s,fp,"dynamic-backlog-high",0.0,100.0,REQ,p->dynBacklogHighWaterMark, inherit);
-
-  l=p->lowPassLow;
-  h=p->lowPassHigh;
-  if (l > h)
-    {
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: no-check-low value greater than no-check-high"
-                  " (%f vs %f). Setting to %f and %f", l, h, NOCHECKLOW,
-                  NOCHECKHIGH) ;
-      rv = 0 ;
-      v = findValue (s,"no-check-low",NO_INHERIT) ;
-      v->v.real_val = p->lowPassLow = NOCHECKLOW ;
-      v = findValue (s,"no-check-high",NO_INHERIT) ;
-      v->v.real_val = p->lowPassHigh = NOCHECKHIGH ;
-    }
-  else if (h - l < 5.0)
-    logOrPrint (LOG_WARNING,fp,
-                "ME config: no-check-low and no-check-high are close"
-                " together (%f vs %f)",l,h) ;
-
-  return p;
-}
-
-
-
-
-static HostParams getHostInfo (void)
-{
-  static int idx = 0 ;
-  value *v ;
-  scope *s ;
-  HostParams p=NULL;
-
-  bool isGood = false ;
-
-  if (topScope == NULL)
-    return p;
-  
-  while ((v = getNextPeer (&idx)) != NULL) 
-    {
-      if (!ISPEER (v))
-        continue ;
-
-      s = v->v.scope_val ;
-
-      p=hostDetails(s,v->name,false,NULL);
-
-      isGood = true ;
-      
-      break ;
-    }
-
-  if (v == NULL)
-    idx = 0 ;                   /* start over next time around */
-
-  return p;
-}
-
-
-/*
- * fully delete and clean up the Host object.
- */
-void delHost (Host host)
-{
-  Host h,q ;
-
-  for (h = gHostList, q = NULL ; h != NULL ; q = h, h = h->next)
-    if (h == host)
-      {
-        if (gHostList == h)
-          gHostList = gHostList->next ;
-        else
-          q->next = h->next ;
-        break ;
-      }
-
-  ASSERT (h != NULL) ;
-        
-  delTape (host->myTape) ;
-  
-  free (host->connections) ;
-  free (host->cxnActive) ;
-  free (host->cxnSleeping) ;
-  free (host->params->peerName) ;
-  free (host->params->ipName) ;
-
-  if (host->ipAddrs)
-  {
-    if(host->ipAddrs[0])
-      free (host->ipAddrs[0]);
-    free (host->ipAddrs) ;
-  }
-
-  free (host) ;
-  gHostCount-- ;
-}
-
-
-\f
-static Host findHostByName (char *name) 
-{
-  Host h;
-
-  for (h = gHostList; h != NULL; h = h->next)
-    if ( strcmp(h->params->peerName, name) == 0 )
-      return h;
-
-  return NULL;
-}
-
-
-\f
-/* 
- * the article can be dropped from the process queue and the connection can
- * take a new article if there are any to be had.
- */
-static void articleGone (Host host, Connection cxn, Article article)
-{
-  if ( !remArticle (article,&host->processed,&host->processedTail) )
-    die ("remArticle in articleGone failed") ;
-
-  delArticle (article) ;
-
-  if (cxn != NULL)
-    hostGimmeArticle (host,cxn) ; /* may not give anything over */
-}
-
-
-
-
-
-
-\f
-/*
- * One of the Connections for this Host has reestablished itself, so stop
- * spooling article info to disk.
- */
-static void hostStopSpooling (Host host)
-{
-  ASSERT (host->spoolTime != 0) ;
-  
-  clearTimer (host->statsId) ;
-  hostLogStats (host,true) ;
-  host->spoolTime = 0 ;
-}
-
-
-
-
-
-
-\f
-/*
- * No connections are active and we're getting response 201 or 400 (or some
- * such) so that we need to start spooling article info to disk.
- */
-static void hostStartSpooling (Host host)
-{
-  ASSERT (host->spoolTime == 0) ;
-
-  queuesToTape (host) ;
-
-  hostLogStats (host,true) ;
-  
-  host->spoolTime = theTime() ;
-  if (host->firstConnectTime == 0)
-    host->firstConnectTime = host->spoolTime ;
-
-  /* don't want to log too frequently */
-  if (SPOOL_LOG_PERIOD > 0 &&
-      (host->spoolTime - host->lastSpoolTime) > SPOOL_LOG_PERIOD)
-    {
-      notice ("%s spooling no active connections", host->params->peerName) ;
-      host->lastSpoolTime = host->spoolTime ;
-    }
-  
-  host->connectTime = 0 ;
-
-  host->notifiedChangedRemBlckd = false ;
-
-  clearTimer (host->statsId) ;
-  host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-}
-
-
-
-
-
-
-\f
-/*
- * Time to log the statistics for the Host. If FINAL is true then the
- * counters will be reset.
- */
-static void hostLogStats (Host host, bool final)
-{
-  time_t now = theTime() ;
-  time_t *startPeriod ;
-  double cnt = (host->blCount) ? (host->blCount) : 1.0;
-  char msgstr[SMBUF] ;
-
-  if (host->spoolTime == 0 && host->connectTime == 0)
-    return ;        /* host has never connected and never started spooling*/
-
-  startPeriod = (host->spoolTime != 0 ? &host->spoolTime : &host->connectTime);
-
-  if (now - *startPeriod >= statsResetPeriod)
-    final = true ;
-  
-  if (host->spoolTime != 0)
-    notice ("%s %s seconds %ld spooled %d on_close %d sleeping %d",
-            host->params->peerName, (final ? "final" : "checkpoint"),
-            (long) (now - host->spoolTime), host->artsToTape,
-            host->artsHostClose, host->artsHostSleep) ;
-  else {
-    snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
-             host->artsSizeAccepted, host->artsSizeRejected);
-    notice ("%s %s seconds %ld offered %d accepted %d refused %d rejected %d"
-            " missing %d %s spooled %d on_close %d unspooled %d"
-            " deferred %d/%.1f requeued %d"
-            " queue %.1f/%d:%.0f,%.0f,%.0f,%.0f,%.0f,%.0f",
-            host->params->peerName, (final ? "final" : "checkpoint"),
-            (long) (now - host->connectTime),
-            host->artsOffered, host->artsAccepted,
-            host->artsNotWanted, host->artsRejected,
-            host->artsMissing, msgstr,
-            host->artsToTape,
-            host->artsHostClose, host->artsFromTape,
-            host->artsDeferred, (double)host->dlAccum/cnt,
-            host->artsCxnDrop,
-            (double)host->blAccum/cnt, hostHighwater,
-            (100.0*host->blNone)/cnt,
-            (100.0*host->blQuartile[0])/cnt, (100.0*host->blQuartile[1])/cnt,
-            (100.0*host->blQuartile[2])/cnt, (100.0*host->blQuartile[3])/cnt,
-            (100.0*host->blFull)/cnt) ;
-  }
-
-  if (logConnectionStats) 
-    {
-      unsigned int i ;
-      
-      for (i = 0 ; i < host->maxConnections ; i++)
-        if (host->connections [i] != NULL && host->cxnActive [i])
-          cxnLogStats (host->connections [i],final) ;
-    }
-
-  /* one 'spooling backlog' message per stats logging period */
-  host->loggedBacklog = false ;
-  host->loggedModeOn = host->loggedModeOff = false ;
-
-  if (final)
-    {
-      host->artsOffered = 0 ;
-      host->artsAccepted = 0 ;
-      host->artsNotWanted = 0 ;
-      host->artsRejected = 0 ;
-      host->artsDeferred = 0 ;
-      host->artsMissing = 0 ;
-      host->artsToTape = 0 ;
-      host->artsQueueOverflow = 0 ;
-      host->artsCxnDrop = 0 ;
-      host->artsHostSleep = 0 ;
-      host->artsHostClose = 0 ;
-      host->artsFromTape = 0 ;
-      host->artsSizeAccepted = 0 ;
-      host->artsSizeRejected = 0 ;
-      
-      *startPeriod = theTime () ; /* in of case STATS_RESET_PERIOD */
-    }
-
-    /* reset these each log period */
-    host->blNone = 0 ;
-    host->blFull = 0 ;
-    host->blQuartile[0] = host->blQuartile[1] = host->blQuartile[2] =
-                          host->blQuartile[3] = 0;
-    host->dlAccum = 0;
-    host->blAccum = 0;
-    host->blCount = 0;
-
-#if 0
-  /* XXX turn this section on to get a snapshot at each log period. */
-  if (gPrintInfo != NULL)
-    gPrintInfo () ;
-#endif
-}
-
-
-
-
-
-
-\f
-
-static double
-convsize(double size, char **tsize)
-{
-    double dsize;
-    static char tTB[]="TB";
-    static char tGB[]="GB";
-    static char tMB[]="MB";
-    static char tKB[]="KB";
-    static char tB []="B";
-
-    if (size/((double)1024*1024*1024*1000)>=1.) {
-       dsize=size/((double)1024*1024*1024*1024);
-       *tsize=tTB;
-    } else if (size/(1024*1024*1000)>=1.) {
-       dsize=size/(1024*1024*1024);
-       *tsize=tGB;
-    } else if (size/(1024*1000)>=1.) {
-       dsize=size/(1024*1024);
-       *tsize=tMB;
-    } else if (size/1000>=1.) {
-       dsize=size/1024;
-       *tsize=tKB;
-    } else {
-       dsize=size;
-       *tsize=tB;
-    }
-    return dsize;
-}
-
-
-/*
- * Log the status of the Hosts.
- */
-extern char *versionInfo ;
-static void hostLogStatus (void)
-{
-  FILE *fp = NULL ;
-  Host h ;
-  bool anyToLog = false ;
-  unsigned int peerNum = 0, actConn = 0, slpConn = 0, maxcon = 0 ;
-  static bool logged = false ;
-  static bool flogged = false ;
-
-  if (statusFile == NULL && !logged)
-    {
-      syslog (LOG_ERR,"No status file to write to") ;
-      logged = true ;
-      return ;
-    }
-
-  logged = false ;
-    
-  for (h = gHostList ; h != NULL ; h = h->next)
-    if (h->myTape != NULL)   /* the host deletes its tape when it's closing */
-      {
-        anyToLog = true ;
-        peerNum++ ;
-        actConn += h->activeCxns ;
-        slpConn += h->sleepingCxns ;
-        maxcon += h->maxConnections ;
-      }
-
-  if (!anyToLog)
-    return ;
-
-  lastStatusLog = theTime() ;
-  
-  TMRstart(TMR_STATUSFILE);
-  if ((fp = fopen (statusFile,"w")) == NULL)
-    {
-      if ( !flogged )
-        syswarn ("ME oserr status file open: %s", statusFile) ;
-      flogged = true ;
-    }
-  else
-    {
-      char timeString [30] ;
-      time_t now ;
-      long sec ;
-      long offered ;        
-      double size, totalsize;
-      char *tsize;
-
-      flogged = false ;
-      
-      now = time (NULL) ;
-      sec = (long) (now - start) ;
-      strlcpy (timeString,ctime (&now),sizeof (timeString)) ;
-
-      if (genHtml)
-        {
-          fprintf (fp, "<HTML>\n"
-                      "<HEAD>\n"
-                      "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"300;\">\n"
-                      "</HEAD>\n"
-                      "<BODY>\n") ;
-         fprintf (fp, "\n");
-         fprintf (fp, "<PRE>\n");
-       }
-
-      fprintf (fp,"%s\npid %d started %s\nUpdated: %s",
-               versionInfo,(int) myPid,startTime,timeString) ;
-      fprintf (fp,"(peers: %d active-cxns: %d sleeping-cxns: %d idle-cxns: %d)\n\n",
-               peerNum, actConn, slpConn,(maxcon - (actConn + slpConn))) ;
-
-      fprintf (fp,"Configuration file: %s\n\n",configFile) ;
-      
-      if (genHtml)
-      {
-        fprintf (fp, "</PRE>\n");
-        fprintf (fp,"<UL>\n");
-        for (h = gHostList ; h != NULL ; h = h->next)
-          fprintf (fp,"<LI><A href=\"#%s\">%s</A></LI>\n",
-                   h->params->peerName, h->params->peerName);
-        fprintf (fp,"</UL>\n\n");
-        fprintf (fp,"<PRE>\n");
-      }
-
-      mainLogStatus (fp) ;
-      listenerLogStatus (fp) ;
-
-/*
-Default peer configuration parameters:
-    article timeout: 600       initial connections: 1
-   response timeout: 300           max connections: 5
-       close period: 6000               max checks: 25
-     want streaming: true           dynamic method: 1
-        no-check on: 95.0%     dynamic backlog low: 25%
-       no-check off: 90.0%    dynamic backlog high: 50%
-    no-check filter: 50.0   dynamic backlog filter: 0.7
-  backlog low limit: 1024                 port num: 119
- backlog high limit: 1280       backlog feed first: false
-     backlog factor: 1.1
-*/
-      fprintf(fp,"%sDefault peer configuration parameters:%s\n",
-              genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
-      fprintf(fp,"    article timeout: %-5d     initial connections: %d\n",
-           defaultParams->articleTimeout,
-           defaultParams->initialConnections) ;
-      fprintf(fp,"   response timeout: %-5d         max connections: %d\n",
-           defaultParams->responseTimeout,
-           defaultParams->absMaxConnections) ;
-      fprintf(fp,"       close period: %-5d              max checks: %d\n",
-           defaultParams->closePeriod,
-           defaultParams->maxChecks) ;
-      fprintf(fp,"     want streaming: %-5s          dynamic method: %d\n",
-           defaultParams->wantStreaming ? "true " : "false",
-           defaultParams->dynamicMethod) ;
-      fprintf(fp,"        no-check on: %-2.1f%%     dynamic backlog low: %-2.1f%%\n",
-           defaultParams->lowPassHigh,
-           defaultParams->dynBacklogLowWaterMark) ;
-      fprintf(fp,"       no-check off: %-2.1f%%    dynamic backlog high: %-2.1f%%\n",
-           defaultParams->lowPassLow,
-           defaultParams->dynBacklogHighWaterMark) ;
-      fprintf(fp,"    no-check filter: %-2.1f   dynamic backlog filter: %-2.1f\n",
-           defaultParams->lowPassFilter,
-           defaultParams->dynBacklogFilter) ;
-      fprintf(fp,"  backlog limit low: %-7d         drop-deferred: %s\n",
-           defaultParams->backlogLimit,
-           defaultParams->dropDeferred ? "true " : "false");
-      fprintf(fp," backlog limit high: %-7d         min-queue-cxn: %s\n",
-           defaultParams->backlogLimitHigh,
-           defaultParams->minQueueCxn ? "true " : "false");
-      fprintf(fp,"  backlog feed first: %s\n",
-           defaultParams->backlogFeedFirst ? "true " : "false");
-      fprintf(fp,"     backlog factor: %1.1f\n\n",
-           defaultParams->backlogFactor);
-
-      tapeLogGlobalStatus (fp) ;
-
-      fprintf (fp,"\n") ;
-      fprintf(fp,"%sglobal (process)%s\n",
-              genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
-      
-      fprintf (fp, "   seconds: %ld\n", sec) ;
-      if (sec == 0) sec = 1 ;
-      offered = procArtsOffered ? procArtsOffered : 1 ;
-      totalsize = procArtsSizeAccepted+procArtsSizeRejected ;
-      if (totalsize == 0) totalsize = 1. ;
-
-      fprintf (fp, "   offered: %-5ld\t%6.2f art/s\n",
-               procArtsOffered,
-               (double)procArtsOffered/sec) ;
-      fprintf (fp, "  accepted: %-5ld\t%6.2f art/s\t%5.1f%%\n",
-               procArtsAccepted,
-               (double)procArtsAccepted/sec,
-               (double)procArtsAccepted*100./offered) ;
-      fprintf (fp, "   refused: %-5ld\t%6.2f art/s\t%5.1f%%\n",
-               procArtsNotWanted,
-               (double)procArtsNotWanted/sec,
-               (double)procArtsNotWanted*100./offered) ;
-      fprintf (fp, "  rejected: %-5ld\t%6.2f art/s\t%5.1f%%\n",
-               procArtsRejected,
-               (double)procArtsRejected/sec,
-               (double)procArtsRejected*100./offered) ;
-      fprintf (fp, "   missing: %-5ld\t%6.2f art/s\t%5.1f%%\n",
-               procArtsMissing,
-               (double)procArtsMissing/sec,
-               (double)procArtsMissing*100./offered) ;
-      fprintf (fp, "  deferred: %-5ld\t%6.2f art/s\t%5.1f%%\n",
-               procArtsDeferred,
-               (double)procArtsDeferred/sec,
-               (double)procArtsDeferred*100./offered) ;
-
-      size=convsize(procArtsSizeAccepted, &tsize);
-      fprintf (fp, "accpt size: %.3g %s", size, tsize) ;
-      size=convsize(procArtsSizeAccepted/sec, &tsize);
-      fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
-               size, tsize,
-               procArtsSizeAccepted*100./totalsize) ;
-
-      size=convsize(procArtsSizeRejected, &tsize);
-      fprintf (fp, "rejct size: %.3g %s", size, tsize) ;
-      size=convsize(procArtsSizeRejected/sec, &tsize);
-      fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
-               size, tsize,
-               procArtsSizeRejected*100./totalsize) ;
-
-      fprintf (fp, "\n");
-
-      for (h = gHostList ; h != NULL ; h = h->next)
-        hostPrintStatus (h,fp) ;
-
-      if (genHtml) 
-       {
-          fprintf (fp,"</PRE>\n") ;
-          fprintf (fp,"</BODY>\n") ;
-          fprintf (fp,"</HTML>\n") ;
-       }
-      
-      fclose (fp) ;
-    }
-    TMRstop(TMR_STATUSFILE);
-}
-
-/*
- * This prints status information for each host.  An example of the
- * format of the output is:
- *
- * sitename
- *   seconds: 351       art. timeout: 400          ip name: foo.bar
- *   offered: 1194     resp. timeout: 240             port: 119
- *  accepted: 178     want streaming: yes      active cxns: 6
- *   refused: 948       is streaming: yes    sleeping cxns: 0
- *  rejected: 31          max checks: 25      initial cxns: 5
- *   missing: 0          no-check on: 95.0%      idle cxns: 4
- *  deferred: 0         no-check off: 95.0%       max cxns: 8/10
- *  requeued: 0        no-check fltr: 50.0    queue length: 0.0/200
- *   spooled: 0       dynamic method: 0              empty: 100.0%
- *[overflow]: 0        dyn b'log low: 25%          >0%-25%: 0.0%
- *[on_close]: 0       dyn b'log high: 50%          25%-50%: 0.0%
- *[sleeping]: 0       dyn b'log stat: 37%          50%-75%: 0.0%
- * unspooled: 0       dyn b'log fltr: 0.7        75%-<100%: 0.0%
- *  no queue: 1234    avr.cxns queue: 0.0             full: 0.0%
- *accpt size: 121.1 MB drop-deferred: false   defer length: 0
- *rejct size: 27.1 MB  min-queue-cxn: false
- *                 backlog low limit: 1000000
- *                backlog high limit: 2000000     (factor 2.0)
- *                 backlog shrinkage: 0 bytes (from current file)
- *   offered:  1.13 art/s   accepted:  0.69 art/s (101.71 KB/s)
- *   refused:  0.01 art/s   rejected:  0.42 art/s (145.11 KB/s)
- *   missing 0 spooled 0
- *
- */
-static void hostPrintStatus (Host host, FILE *fp)
-{
-  time_t now = theTime() ;
-  double cnt = (host->blCount) ? (host->blCount) : 1.0;
-  double size;
-  char *tsize;
-  char buf[]="1234.1 MB";
-
-  ASSERT (host != NULL) ;
-  ASSERT (fp != NULL) ;
-
-  if (genHtml)
-    fprintf (fp,"<A name=\"%s\"><B>%s</B></A>",host->params->peerName,
-             host->params->peerName);
-  else
-    fprintf (fp,"%s",host->params->peerName);
-
-  if (host->blockedReason != NULL)
-    fprintf (fp,"  (remote status: ``%s'')",host->blockedReason) ;
-
-  fputc ('\n',fp) ;
-
-  fprintf (fp, "   seconds: %-7ld   art. timeout: %-5d        ip name: %s\n",
-          host->firstConnectTime > 0 ? (long)(now - host->firstConnectTime) : 0,
-          host->params->articleTimeout, host->params->ipName) ;
-           
-  fprintf (fp, "   offered: %-7ld  resp. timeout: %-5d           port: %d\n",
-          (long) host->gArtsOffered, host->params->responseTimeout,
-          host->params->portNum);
-
-  fprintf (fp, "  accepted: %-7ld want streaming: %s      active cxns: %d\n",
-          (long) host->gArtsAccepted, 
-           (host->params->wantStreaming ? "yes" : "no "),
-          host->activeCxns) ;
-
-  fprintf (fp, "   refused: %-7ld   is streaming: %s    sleeping cxns: %d\n",
-          (long) host->gArtsNotWanted,
-           (host->remoteStreams ? "yes" : "no "),
-          host->sleepingCxns) ;
-
-  fprintf (fp, "  rejected: %-7ld     max checks: %-5d   initial cxns: %d\n",
-          (long) host->gArtsRejected, host->params->maxChecks,
-          host->params->initialConnections) ;
-
-  fprintf (fp, "   missing: %-7ld    no-check on: %-3.1f%%      idle cxns: %d\n",
-          (long) host->gArtsMissing, host->params->lowPassHigh,
-           host->maxConnections - (host->activeCxns + host->sleepingCxns)) ;
-
-  fprintf (fp, "  deferred: %-7ld   no-check off: %-3.1f%%       max cxns: %d/%d\n",
-          (long) host->gArtsDeferred, host->params->lowPassLow,
-          host->maxConnections, host->params->absMaxConnections) ;
-
-  fprintf (fp, "  requeued: %-7ld  no-check fltr: %-3.1f    queue length: %-3.1f/%d\n",
-          (long) host->gArtsCxnDrop, host->params->lowPassFilter,
-          (double)host->blAccum / cnt, hostHighwater) ;
-
-  fprintf (fp, "   spooled: %-7ld dynamic method: %-5d          empty: %-3.1f%%\n",
-          (long) host->gArtsToTape,
-          host->params->dynamicMethod,
-          100.0 * host->blNone / cnt) ;
-
-  fprintf (fp, "[overflow]: %-7ld  dyn b'log low: %-3.1f%%        >0%%-25%%: %-3.1f%%\n",
-          (long) host->gArtsQueueOverflow, 
-          host->params->dynBacklogLowWaterMark,
-          100.0 * host->blQuartile[0] / cnt) ;
-
-  fprintf (fp, "[on_close]: %-7ld dyn b'log high: %-3.1f%%        25%%-50%%: %-3.1f%%\n",
-          (long) host->gArtsHostClose,
-          host->params->dynBacklogHighWaterMark,
-          100.0 * host->blQuartile[1] / cnt) ;
-
-  fprintf (fp, "[sleeping]: %-7ld dyn b'log stat: %-3.1f%%        50%%-75%%: %-3.1f%%\n",
-          (long) host->gArtsHostSleep,
-          host->backlogFilter*100.0*(1.0-host->params->dynBacklogFilter),
-          100.0 * host->blQuartile[2] / cnt) ;
-
-  fprintf (fp, " unspooled: %-7ld dyn b'log fltr: %-3.1f       75%%-<100%%: %-3.1f%%\n",
-          (long) host->gArtsFromTape,
-          host->params->dynBacklogLowWaterMark,
-          100.0 * host->blQuartile[3] / cnt) ;
-
-  fprintf (fp, "  no queue: %-7ld avr.cxns queue: %-3.1f             full: %-3.1f%%\n",
-          (long) host->gNoQueue,
-          (double) host->gCxnQueue / (host->gArtsOffered ? host->gArtsOffered :1) ,
-          100.0 * host->blFull / cnt) ;
-  size=convsize(host->gArtsSizeAccepted, &tsize);
-  snprintf(buf,sizeof(buf),"%.3g %s", size, tsize);
-  fprintf (fp, "accpt size: %-8s drop-deferred: %-5s   defer length: %-3.1f\n",
-          buf, host->params->dropDeferred ? "true " : "false",
-           (double)host->dlAccum / cnt) ;
-  size=convsize(host->gArtsSizeRejected, &tsize);
-  snprintf(buf,sizeof(buf),"%.3g %s", size, tsize);
-  fprintf (fp, "rejct size: %-8s min-queue-cxn: %s\n",
-          buf, host->params->minQueueCxn ? "true " : "false");
-
-  tapeLogStatus (host->myTape,fp) ;
-
-  {
-  time_t      sec = (time_t) (now - host->connectTime);
-  double      or, ar, rr, jr;
-  double      ars, jrs;
-  char       *tars, *tjrs;
-  if (sec != 0) {
-      or = (double) host->artsOffered / (double) sec;
-      ar = (double) host->artsAccepted / (double) sec;
-      rr = (double) host->artsNotWanted / (double) sec;
-      jr = (double) host->artsRejected / (double) sec;
-      ars = convsize (host->artsSizeAccepted/sec, &tars);
-      jrs = convsize (host->artsSizeRejected/sec, &tjrs);
-      fprintf(fp, "   offered: %5.2f art/s   accepted: %5.2f art/s, %.3g %s/s\n",
-             or, ar, ars, tars);
-      fprintf(fp, "   refused: %5.2f art/s   rejected: %5.2f art/s, %.3g %s/s\n",
-             rr, jr, jrs, tjrs);
-  }
-  fprintf(fp, "   missing %d spooled %d\n",
-         host->artsMissing, host->artsToTape);
-  }
-
-#ifdef        XXX_STATSHACK
-  {
-  time_t      now = time(NULL), sec = (long) (now - host->connectTime);
-  float               or, ar, rr, jr;
-
-  if (sec != 0) {
-      or = (float) host->artsOffered / (float) sec;
-      ar = (float) host->artsAccepted / (float) sec;
-      rr = (float) host->artsNotWanted / (float) sec;
-      jr = (float) host->artsRejected / (float) sec;
-      fprintf(fp, "\t\tor %02.2f ar %02.2f rr %02.2f jr %02.2f\n",
-              or, ar, rr, jr);
-  }
-  fprintf(fp, "\tmissing %d spooled %d\n",
-      host->artsMissing,host->backlogSpooled);
-  }
-#endif        /* XXX_STATSHACK */
-  
-  fprintf (fp, "\n\n");
-}
-
-
-
-
-
-
-\f
-/*
- * The callback function for the statistics timer to call.
- */
-static void hostStatsTimeoutCbk (TimeoutId tid UNUSED, void *data)
-{
-  Host host = (Host) data ;
-  time_t now = theTime () ;
-
-  ASSERT (tid == host->statsId) ;
-  
-  if (!amClosing (host))
-    hostLogStats (host, false) ;
-
-  if (now - lastStatusLog >= statsPeriod)
-    hostLogStatus () ;
-  
-  host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-}
-
-
-/*
- * The callback function for the deferred article timer to call.
- */
-static void hostDeferredArtCbk (TimeoutId tid UNUSED, void *data)
-{
-  Host host = (Host) data ;
-  time_t now = theTime () ;
-  Article article ;
-
-  ASSERT (tid == host->deferredId) ;
-
-  while (host->deferred && host->deferred->whenToRequeue <= now)
-    {
-      article = remHead (&host->deferred,&host->deferredTail) ;
-      host->deferLen-- ;
-      hostSendArticle (host, article) ; /* requeue it */
-    }
-
-  if (host->deferred)
-    host->deferredId = prepareSleep (hostDeferredArtCbk,
-                                    host->deferred->whenToRequeue - now,
-                                    host) ;
-  else
-    host->deferredId = 0;
-}
-
-
-/* if the host has too many unprocessed articles so we send some to the tape. */
-static void backlogToTape (Host host)
-{
-  Article article ;
-
-  while ((host->backlog + host->deferLen) > hostHighwater)
-    {
-      if (!host->loggedBacklog)
-       {
-         host->loggedBacklog = true ;
-       }
-  
-      if (host->deferred != NULL)
-       {
-         article = remHead (&host->deferred,&host->deferredTail) ;
-          host->deferLen--;
-       }
-      else
-       {
-         article = remHead (&host->queued,&host->queuedTail) ;
-          host->backlog--;
-       }
-
-      ASSERT(article != NULL);
-
-      host->artsQueueOverflow++ ;
-      host->gArtsQueueOverflow++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape,article) ;
-    }
-}
-
-
-
-
-
-
-\f
-/*
- * Returns true of the Host is in the middle of closing down.
- */
-static bool amClosing (Host host)
-{
-  return (host->myTape == NULL ? true : false) ;
-}
-
-
-
-
-
-
-\f
-/*
- * flush all queued articles all the way out to disk.
- */
-static void queuesToTape (Host host)
-{
-  Article art ;
-  
-  while ((art = remHead (&host->processed,&host->processedTail)) != NULL)
-    {
-      host->artsHostClose++ ;
-      host->gArtsHostClose++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape,art) ;
-    }
-  
-  while ((art = remHead (&host->queued,&host->queuedTail)) != NULL)
-    {
-      host->backlog-- ;
-      host->artsHostClose++ ;
-      host->gArtsHostClose++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape,art) ;
-    }
-
-  while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
-    {
-      host->deferLen-- ;
-      host->artsHostClose++ ;
-      host->gArtsHostClose++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape,art) ;
-    }
-
-  while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
-    {
-      host->deferLen-- ;
-      host->artsHostClose++ ;
-      host->gArtsHostClose++ ;
-      host->artsToTape++ ;
-      host->gArtsToTape++ ;
-      procArtsToTape++ ;
-      tapeTakeArticle (host->myTape,art) ;
-    }
-}
-
-
-
-
-
-
-\f
-#define QUEUE_ELEM_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (struct proc_q_elem)))
-
-static ProcQElem queueElemPool ;
-
-/*
- * Add an article to the given queue.
- */
-static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
-                         time_t when)
-{
-  ProcQElem elem ;
-
-  if (queueElemPool == NULL)
-    {
-      unsigned int i ;
-
-      queueElemPool =
-        xmalloc (sizeof(struct proc_q_elem) * QUEUE_ELEM_POOL_SIZE) ;
-
-      for (i = 0; i < QUEUE_ELEM_POOL_SIZE - 1; i++)
-        queueElemPool[i] . next = &(queueElemPool [i + 1]) ;
-      queueElemPool [QUEUE_ELEM_POOL_SIZE-1] . next = NULL ;
-    }
-
-  elem = queueElemPool ;
-  ASSERT (elem != NULL) ;
-  queueElemPool = queueElemPool->next ;
-
-  elem->article = article ;
-  elem->next = NULL ;
-  elem->prev = *tail ;
-  elem->whenToRequeue = when ;
-  if (*tail != NULL)
-    (*tail)->next = elem ;
-  else
-    *head = elem ;
-  *tail = elem ;  
-}
-
-
-
-
-
-
-\f
-/*
- * remove the article from the queue
- */
-static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail)
-{
-  ProcQElem elem ;
-
-  ASSERT (head != NULL) ;
-  ASSERT (tail != NULL) ;
-
-  /* we go backwards down the list--probably faster */
-  elem = *tail ;
-  while (elem != NULL && elem->article != article)
-    elem = elem->prev ;
-
-  if (elem != NULL)
-    {
-      if (elem->prev != NULL)
-        elem->prev->next = elem->next ;
-      if (elem->next != NULL)
-        elem->next->prev = elem->prev ;
-      if (*head == elem)
-        *head = elem->next ;
-      if (*tail == elem)
-        *tail = elem->prev ;
-
-      elem->next = queueElemPool ;
-      queueElemPool = elem ;
-      
-      return true ;
-    }
-  else
-    return false ;
-}
-
-
-
-
-
-
-\f
-/*
- * remove the article that's at the head of the queue and return
- * it. Returns NULL if the queue is empty.
- */
-static Article remHead (ProcQElem *head, ProcQElem *tail)
-{
-  ProcQElem elem ;
-  Article art ;
-
-  ASSERT (head != NULL) ;
-  ASSERT (tail != NULL) ;
-  ASSERT ((*head == NULL && *tail == NULL) ||
-          (*head != NULL && *tail != NULL)) ;
-
-  if (*head == NULL)
-    return NULL ;
-
-  elem = *head ;
-  art = elem->article ;
-  *head = elem->next ;
-  if (elem->next != NULL)
-    elem->next->prev = NULL ;
-
-  if (*tail == elem)
-    *tail = NULL ;
-
-  elem->next = queueElemPool ;
-  queueElemPool = elem ;
-
-  return art ;
-}
-
-
-
-static int validateInteger (FILE *fp, const char *name,
-                     long low, long high, int required, long setval,
-                    scope * sc, unsigned int inh)
-{
-  int rval = VALUE_OK ;
-  value *v ;
-  scope *s ;
-  char *p = strrchr (name,':') ;
-  
-  v = findValue (sc,name,inh) ;
-  if (v == NULL && required != NOTREQNOADD)
-    {
-      s = findScope (sc,name,0) ;
-      addInteger (s,p ? p + 1 : name,setval) ;
-      if (required == REQ)
-        {
-          rval = VALUE_MISSING ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: no definition for required key %s",name) ;
-        }
-      else if (required)
-        logOrPrint (LOG_INFO,fp,
-                    "ME config: adding missing key/value %s: %ld",name
-                    ,setval) ;
-    }
-  else if (v != NULL && v->type != intval)
-    {
-      rval = VALUE_WRONG_TYPE ;
-      logOrPrint (LOG_ERR,fp,"ME config: value of %s is not an integer",name) ;
-    }
-  else if (v != NULL && low != LONG_MIN && v->v.int_val < low)
-    {
-      rval = VALUE_TOO_LOW ;
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: value of %s (%ld) in %s is lower than minimum"
-                  " of %ld. Using %ld",name,v->v.int_val,
-                  "global scope",low,low) ;
-      v->v.int_val = low ;
-    }
-  else if (v != NULL && high != LONG_MAX && v->v.int_val > high)
-    {
-      rval = VALUE_TOO_HIGH ;
-      logOrPrint(LOG_ERR,fp,
-                 "ME config: value of %s (%ld) in %s is higher than maximum"
-                 " of %ld. Using %ld",name,v->v.int_val,
-                 "global scope",high,high);
-      v->v.int_val = high ;
-    }
-  
-  return rval ;
-}
-
-
-
-static int validateReal (FILE *fp, const char *name, double low,
-                         double high, int required, double setval,
-                        scope * sc, unsigned int inh)
-{
-  int rval = VALUE_OK ;
-  value *v ;
-  scope *s ;
-  char *p = strrchr (name,':') ;
-  
-  v = findValue (sc,name,inh) ;
-  if (v == NULL && required != NOTREQNOADD)
-    {
-      s = findScope (sc,name,0) ;
-      addReal (s,p ? p + 1 : name,setval) ;
-      if (required == REQ)
-        {
-          rval = VALUE_MISSING ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: no definition for required key %s",name) ;
-        }
-      else
-        logOrPrint (LOG_INFO,fp,
-                    "ME config: adding missing key/value %s: %f",name,
-                    setval) ;
-    }
-  else if (v != NULL && v->type != realval)
-    {
-      rval = VALUE_WRONG_TYPE ;
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: value of %s is not a floating point number",
-                  name) ;
-    }
-  else if (v != NULL && low != -DBL_MAX && v->v.real_val < low)
-    {
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: value of %s (%f) is lower than minimum of %f",
-                  name,v->v.real_val,low) ;
-      v->v.real_val = setval ;
-    }
-  else if (v != NULL && high != DBL_MAX && v->v.real_val > high)
-    {
-      logOrPrint (LOG_ERR,fp,
-                  "ME config: value of %s (%f) is higher than maximum of %f",
-                  name,v->v.real_val,high) ;
-      v->v.real_val = setval ;
-    }
-    
-  return rval ;
-}
-
-
-
-static int validateBool (FILE *fp, const char *name, int required, bool setval,
-                        scope * sc, unsigned int inh)
-{
-  int rval = VALUE_OK ;
-  value *v ;
-  scope *s ;
-  char *p = strrchr (name,':') ;
-  
-  v = findValue (sc,name,inh) ;
-  if (v == NULL && required != NOTREQNOADD)
-    {
-      s = findScope (sc,name,0) ;
-      addBoolean (s,p ? p + 1 : name, setval ? 1 : 0)  ;
-      if (required == REQ)
-        {
-          rval = VALUE_MISSING ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: no definition for required key %s",name) ;
-        }
-      else
-        logOrPrint (LOG_INFO,fp,
-                    "ME config: adding missing key/value %s: %s",name,
-                    (setval ? "true" : "false")) ;
-    }
-  else if (v != NULL && v->type != boolval)
-    {
-      rval = VALUE_WRONG_TYPE ;
-      logOrPrint (LOG_ERR,fp,"ME config: value of %s is not a boolean",name) ;
-    }
-  
-  return rval ;
-}
-
-
-void gCalcHostBlStat (void)
-{
-  Host h ;
-  
-  for (h = gHostList ; h != NULL ; h = h->next)
-    {
-      h->dlAccum += h->deferLen ;
-      h->blAccum += h->backlog ;
-      if (h->backlog == 0)
-          h->blNone++ ;
-      else if (h->backlog >= (hostHighwater - h->deferLen))
-          h->blFull++ ;
-      else
-          h->blQuartile[(4*h->backlog) / (hostHighwater - h->deferLen)]++ ;
-      h->blCount++ ;
-    }
-}
-static void hostCleanup (void)
-{
-  if (statusFile != NULL)
-    free (statusFile) ;
-  statusFile = NULL ;
-}