1 /* $Id: host.c 10305 2018-12-02 14:21:56Z iulius $
2 **
3 ** The implementation of the innfeed Host class.
4 **
5 ** Written by James Brister <brister@vix.com>
6 */
7
8 #include "innfeed.h"
9 #include "config.h"
10 #include "clibrary.h"
11 #include "portable/socket.h"
12
13 #include <assert.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <float.h>
17 #include <math.h>
18 #include <netdb.h>
19 #include <syslog.h>
20 #include <sys/param.h>
21
22 #ifdef HAVE_LIMITS_H
23 # include <limits.h>
24 #endif
25
26 #include "inn/innconf.h"
27 #include "inn/messages.h"
28 #include "inn/network.h"
29 #include "inn/version.h"
30 #include "inn/libinn.h"
31
32 #include "article.h"
33 #include "buffer.h"
34 #include "configfile.h"
35 #include "connection.h"
36 #include "endpoint.h"
37 #include "host.h"
38 #include "innlistener.h"
39 #include "tape.h"
40
41 #define REQ 1
42 #define NOTREQ 0
43 #define NOTREQNOADD 2
44
45 #define VALUE_OK 0
46 #define VALUE_TOO_HIGH 1
47 #define VALUE_TOO_LOW 2
48 #define VALUE_MISSING 3
49 #define VALUE_WRONG_TYPE 4
50
51 #define METHOD_STATIC 0
52 #define METHOD_APS 1
53 #define METHOD_QUEUE 2
54 #define METHOD_COMBINED 3
55
56 /* the limit of number of connections open when a host is
57 set to 0 to mean "infinite" */
58 #define MAXCON 500
59 #define MAXCONLIMIT(xx) ((xx==0)?MAXCON:xx)
60
61 #define BACKLOGFILTER 0.7
62 #define BACKLOGLWM 20.0
63 #define BACKLOGHWM 50.0
64
65 /* time between retrying blocked hosts in seconds */
66 #define TRYBLOCKEDHOSTPERIOD 120
67
68 extern char *configFile ;
69
70 extern unsigned int init_reconnect_period;
71 extern unsigned int max_reconnect_period;
72
73 /* the host keeps a couple lists of these */
74 typedef struct proc_q_elem
75 {
76 Article article ;
77 struct proc_q_elem *next ;
78 struct proc_q_elem *prev ;
79 time_t whenToRequeue ;
80 } *ProcQElem ;
81
82 typedef struct host_param_s
83 {
84 char *peerName;
85 char *ipName;
86 char *bindAddr;
87 char *bindAddr6;
88 unsigned int articleTimeout;
89 unsigned int responseTimeout;
90 unsigned int initialConnections;
91 unsigned int absMaxConnections;
92 unsigned int maxChecks;
93 unsigned short portNum;
94 bool forceIPv4;
95 unsigned int closePeriod;
96 unsigned int dynamicMethod;
97 bool wantStreaming;
98 bool dropDeferred;
99 bool minQueueCxn;
100 double lowPassLow; /* as percentages */
101 double lowPassHigh;
102 double lowPassFilter;
103 unsigned int backlogLimit ;
104 unsigned int backlogLimitHigh ;
105 double backlogFactor ;
106 double dynBacklogFilter ;
107 double dynBacklogLowWaterMark ;
108 double dynBacklogHighWaterMark ;
109 bool backlogFeedFirst ;
110 char *username;
111 char *password;
112 } *HostParams ;
113
114 struct host_s
115 {
116 InnListener listener ; /* who created me. */
117 struct sockaddr **ipAddrs ; /* the ip addresses of the remote */
118 int nextIpAddr ; /* the next ip address to hand out */
119
120 Connection *connections ; /* NULL-terminated list of all connections */
121 bool *cxnActive ; /* true if the corresponding cxn is active */
122 bool *cxnSleeping ; /* true if the connection is sleeping */
123 unsigned int maxConnections; /* maximum no of cxns controlled by method */
124 unsigned int activeCxns ; /* number of connections currently active */
125 unsigned int sleepingCxns ; /* number of connections currently sleeping */
126 Connection blockedCxn ; /* the first connection to get the 400 banner*/
127 Connection notThisCxn ; /* don't offer articles to this connection */
128
129 HostParams params; /* Parameters from config file */
130
131 bool remoteStreams ; /* true if remote supports streaming */
132
133 ProcQElem queued ; /* articles done nothing with yet. */
134 ProcQElem queuedTail ;
135
136 ProcQElem processed ; /* articles given to a Connection */
137 ProcQElem processedTail ;
138
139 ProcQElem deferred ; /* articles which have been deferred by */
140 ProcQElem deferredTail ; /* a connection */
141
142 TimeoutId statsId ; /* timeout id for stats logging. */
143 TimeoutId ChkCxnsId ; /* timeout id for dynamic connections */
144 TimeoutId deferredId ; /* timeout id for deferred articles */
145
146 Tape myTape ;
147
148 bool backedUp ; /* set to true when all cxns are full */
149 unsigned int backlog ; /* number of arts in `queued' queue */
150 unsigned int deferLen ; /* number of arts in `deferred' queue */
151
152 bool loggedModeOn ; /* true if we logged going into no-CHECK mode */
153 bool loggedModeOff ; /* true if we logged going out of no-CHECK mode */
154
155 bool loggedBacklog ; /* true if we already logged the fact */
156 bool notifiedChangedRemBlckd ; /* true if we logged a new response 400 */
157 bool removeOnReload ; /* true if host should be removed at end of
158 * config reload
159 */
160 bool isDynamic; /* true if host created dynamically */
161
162 /* these numbers get reset periodically (after a 'final' logging). */
163 unsigned int artsOffered ; /* # of articles we offered to remote. */
164 unsigned int artsOffered_checkpoint ;
165 unsigned int artsAccepted ; /* # of articles succesfully transferred */
166 unsigned int artsAccepted_checkpoint ;
167 unsigned int artsNotWanted ; /* # of articles remote already had */
168 unsigned int artsNotWanted_checkpoint ;
169 unsigned int artsRejected ; /* # of articles remote rejected */
170 unsigned int artsRejected_checkpoint ;
171 unsigned int artsDeferred ; /* # of articles remote asked us to retry */
172 unsigned int artsDeferred_checkpoint ;
173 unsigned int artsMissing ; /* # of articles whose file was missing. */
174 unsigned int artsMissing_checkpoint ;
175 unsigned int artsToTape ; /* # of articles given to tape */
176 unsigned int artsToTape_checkpoint ;
177 unsigned int artsQueueOverflow ; /* # of articles that overflowed `queued' */
178 unsigned int artsCxnDrop ; /* # of articles caught in dead cxn */
179 unsigned int artsCxnDrop_checkpoint ;
180 unsigned int artsHostSleep ; /* # of articles spooled by sleeping host */
181 unsigned int artsHostSleep_checkpoint ;
182 unsigned int artsHostClose ; /* # of articles caught by closing host */
183 unsigned int artsHostClose_checkpoint ;
184 unsigned int artsFromTape ; /* # of articles we pulled off tape */
185 unsigned int artsFromTape_checkpoint ;
186 double artsSizeAccepted ; /* size of articles succesfully transferred */
187 double artsSizeAccepted_checkpoint ;
188 double artsSizeRejected ; /* size of articles remote rejected */
189 double artsSizeRejected_checkpoint ;
190
191 /* Dynamic Peerage - MGF */
192 unsigned int artsProcLastPeriod ; /* # of articles processed in last period */
193 unsigned int secsInLastPeriod ; /* Number of seconds in last period */
194 unsigned int lastCheckPoint ; /* total articles at end of last period */
195 unsigned int lastSentCheckPoint ; /* total articles sent end of last period */
196 unsigned int lastTotalCheckPoint ; /* total articles total end of last period */
197 bool maxCxnChk ; /* check for maxConnections */
198 time_t lastMaxCxnTime ; /* last time a maxConnections increased */
199 time_t lastChkTime; /* last time a check was made for maxConnect */
200 unsigned int nextCxnTimeChk ; /* next check for maxConnect */
201
202 double backlogFilter; /* IIR filter for size of backlog */
203
204 /* These numbers are as above, but for the life of the process. */
205 unsigned int gArtsOffered ;
206 unsigned int gArtsAccepted ;
207 unsigned int gArtsNotWanted ;
208 unsigned int gArtsRejected ;
209 unsigned int gArtsDeferred ;
210 unsigned int gArtsMissing ;
211 unsigned int gArtsToTape ;
212 unsigned int gArtsQueueOverflow ;
213 unsigned int gArtsCxnDrop ;
214 unsigned int gArtsHostSleep ;
215 unsigned int gArtsHostClose ;
216 unsigned int gArtsFromTape ;
217 double gArtsSizeAccepted ;
218 double gArtsSizeRejected ;
219 unsigned int gCxnQueue ;
220 unsigned int gNoQueue ;
221
222 time_t firstConnectTime ; /* time of first connect. */
223 time_t connectTime ; /* the time the first connection was fully
224 set up (MODE STREAM and everything
225 else). */
226 time_t connectTime_checkpoint ;
227
228 time_t spoolTime ; /* the time the Host had to revert to
229 spooling articles to tape. */
230 time_t spoolTime_checkpoint ;
231
232 time_t lastSpoolTime ; /* the time the last time the Host had to
233 revert to spooling articles to tape. */
234 time_t nextIpLookup ; /* time of last IP name resolution */
235
236 char *blockedReason ; /* what the 400 from the remote says. */
237
238 Host next ; /* for global list of hosts. */
239
240 unsigned long dlAccum ; /* cumulative deferLen */
241 unsigned int blNone ; /* number of times the backlog was 0 */
242 unsigned int blFull ; /* number of times the backlog was full */
243 unsigned int blQuartile[4] ; /* number of times in each quartile */
244 unsigned long blAccum ; /* cumulative backlog for computing mean */
245 unsigned int blCount ; /* the sample count */
246 };
247
248 /* A holder for the info we got out of the config file, but couldn't create
249 the Host object for (normally due to lock-file problems).*/
250
251 typedef struct host_holder_s
252 {
253 HostParams params;
254 struct host_holder_s *next ;
255 } *HostHolder ;
256
257
258 /* These numbers are as above, but for all hosts over
259 the life of the process. */
260 long procArtsOffered ;
261 long procArtsAccepted ;
262 long procArtsNotWanted ;
263 long procArtsRejected ;
264 long procArtsDeferred ;
265 long procArtsMissing ;
266 double procArtsSizeAccepted ;
267 double procArtsSizeRejected ;
268 long procArtsToTape ;
269 long procArtsFromTape ;
270
271 static HostParams defaultParams=NULL;
272
273 static HostHolder blockedHosts ; /* lists of hosts we can't lock */
274 static TimeoutId tryBlockedHostsId = 0 ;
275 static time_t lastStatusLog ;
276
277 /*
278 * Host object private methods.
279 */
280 static void articleGone (Host host, Connection cxn, Article article) ;
281 static void hostStopSpooling (Host host) ;
282 static void hostStartSpooling (Host host) ;
283 static void hostLogStats (Host host, bool final) ;
284 static void hostStatsTimeoutCbk (TimeoutId tid, void *data) ;
285 static void hostDeferredArtCbk (TimeoutId tid, void *data) ;
286 static void backlogToTape (Host host) ;
287 static void queuesToTape (Host host) ;
288 static bool amClosing (Host host) ;
289 static void hostLogStatus (void) ;
290 static void hostPrintStatus (Host host, FILE *fp) ;
291 static int validateBool (FILE *fp, const char *name,
292 int required, bool setval,
293 scope * sc, unsigned int inh);
294 static int validateReal (FILE *fp, const char *name, double low,
295 double high, int required, double setval,
296 scope * sc, unsigned int inh);
297 static int validateInteger (FILE *fp, const char *name,
298 long low, long high, int required, long setval,
299 scope * sc, unsigned int inh);
300
301 static HostParams newHostParams(HostParams p);
302 static void freeHostParams(HostParams params);
303
304 static HostHolder FindBlockedHost(const char *name);
305 static void addBlockedHost(HostParams params);
306 static void tryBlockedHosts(TimeoutId tid, void *data);
307 static Host newHost (InnListener listener, HostParams p);
308
309 static HostParams getHostInfo (void);
310 static HostParams hostDetails (scope *s,
311 char *name,
312 bool isDefault,
313 FILE *fp);
314
315 static Host findHostByName (char *name) ;
316 static void hostCleanup (void) ;
317 static void hostAlterMaxConnections(Host host,
318 unsigned int absMaxCxns, unsigned int maxCxns,
319 bool makeConnect);
320
321 /* article queue management functions */
322 static Article remHead (ProcQElem *head, ProcQElem *tail) ;
323 static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
324 time_t when) ;
325 static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail) ;
326
327
328
329
330
331 /*
332 * Host class data
333 */
334
335 /* if true then when a Host logs its stats, it has all its connections
336 log theirs too. */
337 static bool logConnectionStats = (bool) LOG_CONNECTION_STATS ;
338
339 /* The frequency in seconds with which a Host will log its stats. */
340 static time_t statsPeriod = STATS_PERIOD ;
341 static time_t statsResetPeriod = STATS_RESET_PERIOD ;
342
343 static Host gHostList = NULL ;
344
345 static unsigned int gHostCount = 0 ;
346
347 static unsigned int maxIpNameLen = 0 ;
348 static unsigned int maxPeerNameLen = 0 ;
349
350 unsigned int hostHighwater = HOST_HIGHWATER ;
351 static time_t start ;
352 static char startTime [30] ; /* for timeToString */
353 static pid_t myPid ;
354
355 static char *statusFile = NULL ;
356 static unsigned int dnsRetPeriod ;
357 static unsigned int dnsExpPeriod ;
358
359 bool genHtml = false ;
360
361 /*******************************************************************/
362 /* PUBLIC FUNCTIONS */
363 /*******************************************************************/
364
365
366 /* function called when the config file is loaded */
hostConfigLoadCbk(void * data)367 int hostConfigLoadCbk (void *data)
368 {
369 int rval = 1, bval ;
370 long iv ;
371 FILE *fp = (FILE *) data ;
372 char *p ;
373
374
375 d_printf(1,"hostConfigLoadCbk\n");
376
377 if (defaultParams)
378 {
379 freeHostParams(defaultParams);
380 defaultParams=NULL;
381 }
382
383 /* get optional global defaults */
384 if (getInteger (topScope,"dns-retry",&iv,NO_INHERIT))
385 {
386 if (iv < 1)
387 {
388 rval = 0 ;
389 logOrPrint (LOG_ERR,fp,
390 "ME config: value of %s (%ld) in %s cannot be less"
391 " than 1. Using %ld","dns-retry",
392 iv,"global scope",(long)DNS_RETRY_PERIOD) ;
393 iv = DNS_RETRY_PERIOD ;
394 }
395 }
396 else
397 iv = DNS_RETRY_PERIOD ;
398 dnsRetPeriod = (unsigned int) iv ;
399
400
401 if (getInteger (topScope,"dns-expire",&iv,NO_INHERIT))
402 {
403 if (iv < 1)
404 {
405 rval = 0 ;
406 logOrPrint (LOG_ERR,fp,
407 "ME config: value of %s (%ld) in %s cannot be less"
408 " than 1. Using %ld","dns-expire",iv,
409 "global scope",(long)DNS_EXPIRE_PERIOD) ;
410 iv = DNS_EXPIRE_PERIOD ;
411 }
412 }
413 else
414 iv = DNS_EXPIRE_PERIOD ;
415 dnsExpPeriod = (unsigned int) iv ;
416
417 if (getBool (topScope,"gen-html",&bval,NO_INHERIT))
418 genHtml = (bval ? true : false) ;
419 else
420 genHtml = GEN_HTML ;
421
422 if (getString (topScope,"status-file",&p,NO_INHERIT))
423 {
424 hostSetStatusFile (p) ;
425 free (p) ;
426 }
427 else
428 hostSetStatusFile (INNFEED_STATUS) ;
429
430 if (getBool (topScope,"connection-stats",&bval,NO_INHERIT))
431 logConnectionStats = (bval ? true : false) ;
432 else
433 logConnectionStats = (LOG_CONNECTION_STATS ? true : false) ;
434
435 if (getInteger (topScope,"host-queue-highwater", &iv,NO_INHERIT))
436 {
437 if (iv < 0)
438 {
439 rval = 0 ;
440 logOrPrint (LOG_ERR,fp,
441 "ME config: value of %s (%ld) in %s cannot be less"
442 " than 0. Using %ld","host-queue-highwater",
443 iv,"global scope",(long) HOST_HIGHWATER) ;
444 iv = HOST_HIGHWATER ;
445 }
446 }
447 else
448 iv = HOST_HIGHWATER ;
449 hostHighwater = (unsigned int) iv ;
450
451 if (getInteger (topScope,"stats-period",&iv,NO_INHERIT))
452 {
453 if (iv < 0)
454 {
455 rval = 0 ;
456 logOrPrint (LOG_ERR,fp,
457 "ME config: value of %s (%ld) in %s cannot be less"
458 " than 0. Using %ld","stats-period",
459 iv,"global scope",(long)STATS_PERIOD) ;
460 iv = STATS_PERIOD ;
461 }
462 }
463 else
464 iv = STATS_PERIOD ;
465 statsPeriod = (unsigned int) iv ;
466
467
468 if (getInteger (topScope,"stats-reset",&iv,NO_INHERIT))
469 {
470 if (iv < 0)
471 {
472 rval = 0 ;
473 logOrPrint (LOG_ERR,fp,
474 "ME config: value of %s (%ld) in %s cannot be less"
475 " than 0. Using %ld","stats-reset",iv,
476 "global scope",(long)STATS_RESET_PERIOD) ;
477 iv = STATS_RESET_PERIOD ;
478 }
479 }
480 else
481 iv = STATS_RESET_PERIOD ;
482 statsResetPeriod = (unsigned int) iv ;
483
484 defaultParams=hostDetails(topScope, NULL, true, fp);
485 ASSERT(defaultParams!=NULL);
486
487 return rval ;
488 }
489
490 /*
491 * make a new HostParams structure copying an existing one
492 * or from compiled defaults
493 */
494
newHostParams(HostParams p)495 static HostParams newHostParams(HostParams p)
496 {
497 HostParams params;
498
499 params = xmalloc (sizeof(struct host_param_s)) ;
500
501 if (p != NULL)
502 {
503 /* Copy old stuff in */
504 memcpy ((char *) params, (char *) p, sizeof(struct host_param_s));
505 if (params->peerName)
506 params->peerName = xstrdup(params->peerName);
507 if (params->ipName)
508 params->ipName = xstrdup(params->ipName);
509 if (params->bindAddr)
510 params->bindAddr = xstrdup(params->bindAddr);
511 if (params->bindAddr6)
512 params->bindAddr6 = xstrdup(params->bindAddr6);
513 }
514 else
515 {
516 /* Fill in defaults */
517 params->peerName=NULL;
518 params->ipName=NULL;
519 params->bindAddr=NULL;
520 params->bindAddr6=NULL;
521 params->articleTimeout=ARTTOUT;
522 params->responseTimeout=RESPTOUT;
523 params->initialConnections=INIT_CXNS;
524 params->absMaxConnections=MAX_CXNS;
525 params->maxChecks=MAX_Q_SIZE;
526 params->portNum=PORTNUM;
527 params->forceIPv4=FORCE_IPv4;
528 params->closePeriod=CLOSE_PERIOD;
529 params->dynamicMethod=METHOD_COMBINED;
530 params->wantStreaming=STREAM;
531 params->dropDeferred=false;
532 params->minQueueCxn=false;
533 params->lowPassLow=NOCHECKLOW;
534 params->lowPassHigh=NOCHECKHIGH;
535 params->lowPassFilter=FILTERVALUE;
536 params->backlogLimit=BLOGLIMIT;
537 params->backlogLimitHigh=BLOGLIMIT_HIGH ;
538 params->backlogFactor=LIMIT_FUDGE ;
539 params->dynBacklogFilter = BACKLOGFILTER ;
540 params->dynBacklogLowWaterMark = BACKLOGLWM;
541 params->dynBacklogHighWaterMark = BACKLOGHWM;
542 params->backlogFeedFirst=false;
543 params->username=NULL;
544 params->password=NULL;
545 }
546 return (params);
547 }
548
549 /*
550 * Free up a param structure
551 */
552
freeHostParams(HostParams params)553 static void freeHostParams(HostParams params)
554 {
555 ASSERT(params != NULL);
556 if (params->peerName)
557 free (params->peerName) ;
558 if (params->ipName)
559 free (params->ipName) ;
560 if (params->bindAddr)
561 free (params->bindAddr) ;
562 if (params->bindAddr6)
563 free (params->bindAddr6) ;
564 free (params) ;
565 }
566
hostReconfigure(Host h,HostParams params)567 static void hostReconfigure(Host h, HostParams params)
568 {
569 unsigned int i;
570 double oldBacklogFilter ;
571
572 if (strcmp(h->params->ipName, params->ipName) != 0)
573 {
574 free (h->params->ipName) ;
575 h->params->ipName = xstrdup (params->ipName) ;
576 h->nextIpLookup = theTime () ;
577 }
578
579 /* Put in new parameters
580 Unfortunately we can't blat on top of absMaxConnections
581 as we need to do some resizing here
582 */
583
584 ASSERT (h->params != NULL);
585
586 oldBacklogFilter = h->params->dynBacklogFilter;
587 i = h->params->absMaxConnections; /* keep old value */
588 /* Use this set of params and allocate, and free
589 * up the old
590 */
591 freeHostParams(h->params);
592 h->params = params;
593 h->params->absMaxConnections = i; /* restore old value */
594
595 /* If the backlog filter value has changed, reset the
596 * filter as the value therein will be screwy
597 */
598 if (h->params->dynBacklogFilter != oldBacklogFilter)
599 h->backlogFilter = ((h->params->dynBacklogLowWaterMark
600 + h->params->dynBacklogHighWaterMark)
601 /200.0 /(1.0-h->params->dynBacklogFilter));
602
603 /* We call this anyway - it does nothing if the values
604 * haven't changed. This is because doing things like
605 * just changing "dynamic-method" requires this call
606 * to be made
607 */
608 hostAlterMaxConnections(h, h->params->absMaxConnections,
609 h->params->absMaxConnections, false);
610
611 for ( i = 0 ; i < MAXCONLIMIT(h->params->absMaxConnections) ; i++ )
612 if (h->connections[i] != NULL)
613 cxnSetCheckThresholds (h->connections[i],
614 h->params->lowPassLow,
615 h->params->lowPassHigh,
616 h->params->lowPassFilter) ;
617
618 /* XXX how to handle initCxns change? */
619 }
620
621
configHosts(bool talkSelf)622 void configHosts (bool talkSelf)
623 {
624 Host nHost, h, q ;
625 HostHolder hh, hi ;
626 HostParams params;
627
628 /* Remove the current blocked host list */
629 for (hh = blockedHosts, hi = NULL ; hh != NULL ; hh = hi)
630 {
631 freeHostParams(hh->params);
632 hi = hh->next ;
633 free (hh) ;
634 }
635 blockedHosts = NULL ;
636
637 closeDroppedArticleFile () ;
638 openDroppedArticleFile () ;
639
640 while ((params = getHostInfo ()) !=NULL )
641 {
642 h = findHostByName (params->peerName) ;
643 /* We know the host isn't blocked as we cleared the blocked list */
644 /* Have we already got this host up and running ?*/
645 if ( h != NULL )
646 {
647 hostReconfigure(h, params);
648 h->removeOnReload = false ; /* Don't remove at the end */
649 }
650 else
651 {
652
653 /* It's a host we haven't seen from the config file before */
654 nHost = newHost (mainListener, params);
655
656 if (nHost == NULL)
657 {
658 addBlockedHost(params);
659
660 warn ("ME locked cannot setup peer %s", params->peerName) ;
661 }
662 else
663 {
664 if (params->initialConnections == 0 && talkSelf)
665 notice ("%s config ignored batch mode with initial"
666 " connection count of 0", params->peerName) ;
667
668 if ( !listenerAddPeer (mainListener,nHost) )
669 die ("failed to add a new peer\n") ;
670 }
671 }
672
673 }
674
675
676 for (h = gHostList; h != NULL; h = q)
677 {
678 q = h->next ;
679 if (h->removeOnReload)
680 {
681 if (h->isDynamic)
682 {
683 /* change to the new default parameters */
684 params = newHostParams(defaultParams);
685 ASSERT(params->peerName == NULL);
686 ASSERT(params->ipName == NULL);
687 ASSERT(h->params->peerName != NULL);
688 ASSERT(h->params->ipName != NULL);
689 params->peerName = xstrdup(h->params->peerName);
690 params->ipName = xstrdup(h->params->ipName);
691 hostReconfigure(h, params);
692 h->removeOnReload = true;
693 }
694 else
695 hostClose (h) ; /* h may be deleted in here. */
696 }
697 else
698 /* prime it for the next config file read */
699 h->removeOnReload = true ;
700 }
701
702 hostLogStatus () ;
703 }
704
705
706 static void
hostAlterMaxConnections(Host host,unsigned int absMaxCxns,unsigned int maxCxns,bool makeConnect)707 hostAlterMaxConnections(Host host, unsigned int absMaxCxns,
708 unsigned int maxCxns, bool makeConnect)
709 {
710 unsigned int lAbsMaxCxns;
711 unsigned int i;
712
713 /* Fix 0 unlimited case */
714 lAbsMaxCxns = MAXCONLIMIT(absMaxCxns);
715
716 /* Don't accept 0 for maxCxns */
717 maxCxns=MAXCONLIMIT(maxCxns);
718
719 if ( host->params->dynamicMethod == METHOD_STATIC)
720 {
721 /* If running static, ignore the maxCxns passed in, we'll
722 just use absMaxCxns
723 */
724 maxCxns = lAbsMaxCxns;
725 }
726
727 if ( maxCxns > lAbsMaxCxns)
728 {
729 /* ensure maxCxns is of the correct form */
730 maxCxns = lAbsMaxCxns;
731 }
732
733 if ((maxCxns < host->maxConnections) && (host->connections != NULL))
734 {
735 /* We are going to have to nuke some connections, as the current
736 max is now greater than the new max
737 */
738 for ( i = host->maxConnections ; i > maxCxns ; i-- )
739 {
740 /* XXX this is harsh, and arguably there could be a
741 cleaner way of doing it. the problem being addressed
742 by doing it this way is that eventually a connection
743 closed cleanly via cxnClose can end up ultimately
744 calling hostCxnDead after h->maxConnections has
745 been lowered and the relevant arrays downsized.
746 If trashing the old, unallocated space in
747 hostCxnDead doesn't kill the process, the
748 ASSERT against h->maxConnections surely will.
749 */
750 if (host->connections[i - 1] != NULL)
751 {
752 cxnLogStats (host->connections [i-1], true) ;
753 cxnNuke (host->connections[i-1]) ;
754 host->connections[i-1] = NULL;
755 }
756 }
757 host->maxConnections = maxCxns ;
758 }
759
760 if (host->connections)
761 for (i = host->maxConnections ; i <= MAXCONLIMIT(host->params->absMaxConnections) ; i++)
762 {
763 /* Ensure we've got an empty values only beyond the maxConnection
764 water mark.
765 */
766 ASSERT (host->connections[i] == NULL);
767 }
768
769 if ((lAbsMaxCxns != MAXCONLIMIT(host->params->absMaxConnections)) ||
770 (host->connections == NULL))
771 {
772 /* we need to change the size of the connection array */
773 if (host->connections == NULL)
774 {
775 /* not yet allocated */
776
777 host->connections = xcalloc (lAbsMaxCxns + 1, sizeof(Connection)) ;
778
779 ASSERT (host->cxnActive == NULL);
780 host->cxnActive = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
781
782 ASSERT (host->cxnSleeping == NULL) ;
783 host->cxnSleeping = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
784
785 for (i = 0 ; i < lAbsMaxCxns ; i++)
786 {
787 host->connections [i] = NULL ;
788 host->cxnActive[i] = false ;
789 host->cxnSleeping[i] = false ;
790 }
791 host->connections[lAbsMaxCxns] = NULL;
792 }
793 else
794 {
795 host->connections =
796 xrealloc (host->connections,
797 sizeof(Connection) * (lAbsMaxCxns + 1));
798 host->cxnActive = xrealloc (host->cxnActive,
799 sizeof(bool) * lAbsMaxCxns) ;
800 host->cxnSleeping = xrealloc (host->cxnSleeping,
801 sizeof(bool) * lAbsMaxCxns) ;
802
803 if (lAbsMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
804 {
805 for (i = MAXCONLIMIT(host->params->absMaxConnections) ;
806 i < lAbsMaxCxns ; i++)
807 {
808 host->connections[i+1] = NULL; /* array always 1 larger */
809 host->cxnActive[i] = false ;
810 host->cxnSleeping[i] = false ;
811 }
812 }
813 }
814 host->params->absMaxConnections = absMaxCxns;
815 }
816 /* if maximum was raised, establish the new connexions
817 (but don't start using them).
818 */
819 if ( maxCxns > host->maxConnections)
820 {
821 i = host->maxConnections ;
822 /* need to set host->maxConnections before cxnWait() */
823 host->maxConnections = maxCxns;
824
825 while ( i < maxCxns )
826 {
827 host->cxnActive [i] = false ;
828 host->cxnSleeping [i] = false ;
829 /* create a new connection */
830 host->connections [i] =
831 newConnection (host, i,
832 host->params->ipName,
833 host->params->articleTimeout,
834 host->params->portNum,
835 host->params->responseTimeout,
836 host->params->closePeriod,
837 host->params->lowPassLow,
838 host->params->lowPassHigh,
839 host->params->lowPassFilter) ;
840
841 /* connect if low enough numbered, or we were forced to */
842 if ((i < host->params->initialConnections) || makeConnect)
843 cxnConnect (host->connections [i]) ;
844 else
845 cxnWait (host->connections [i]) ;
846 i++ ;
847 }
848 }
849
850 }
851
852 /*
853 * Find a host on the blocked host list
854 */
855
FindBlockedHost(const char * name)856 static HostHolder FindBlockedHost(const char *name)
857 {
858 HostHolder hh = blockedHosts;
859 while (hh != NULL)
860 if ((hh->params) && (hh->params->peerName) &&
861 (strcmp(name,hh->params->peerName) == 0))
862 return hh;
863 else
864 hh=hh->next;
865 return NULL;
866 }
867
addBlockedHost(HostParams params)868 static void addBlockedHost(HostParams params)
869 {
870 HostHolder hh;
871
872 hh = xmalloc (sizeof(struct host_holder_s)) ;
873 /* Use this set of params */
874
875 hh->params = params;
876
877 hh->next = blockedHosts ;
878 blockedHosts = hh ;
879 }
880
881 /*
882 * We iterate through the blocked host list and try and reconnect ones
883 * where we couldn't get a lock
884 */
tryBlockedHosts(TimeoutId tid UNUSED,void * data UNUSED)885 static void tryBlockedHosts(TimeoutId tid UNUSED , void *data UNUSED )
886 {
887 HostHolder hh,hi;
888 HostParams params;
889
890 hh = blockedHosts; /* Get start of our queue */
891 blockedHosts = NULL ; /* remove them all from the queue of hosts */
892
893 while (hh != NULL)
894 {
895 params = hh->params;
896 hi= hh->next;
897 free(hh);
898 hh = hi;
899
900 if (params && params->peerName)
901 {
902 if (findHostByName(params->peerName)!=NULL)
903 {
904 /* Wierd, someone's managed to start it when it's on
905 * the blocked list. Just silently discard.
906 */
907 freeHostParams(params);
908 }
909 else
910 {
911 Host nHost;
912 nHost = newHost (mainListener, params);
913
914 if (nHost == NULL)
915 {
916 addBlockedHost(params);
917
918 warn ("ME locked cannot setup peer %s", params->peerName) ;
919 }
920 else
921 {
922 d_printf(1,"Unblocked host %s\n",params->peerName);
923
924 if (params->initialConnections == 0 &&
925 listenerIsDummy(mainListener) /*talk to self*/)
926 notice ("%s config ignored batch mode with initial"
927 " connection count of 0", params->peerName) ;
928
929 if ( !listenerAddPeer (mainListener,nHost) )
930 die ("failed to add a new peer\n") ;
931 }
932 }
933 }
934 }
935 tryBlockedHostsId = prepareSleep(tryBlockedHosts,
936 TRYBLOCKEDHOSTPERIOD, NULL);
937 }
938
939
940 /*
941 * Create a new Host object with default parameters. Called by the
942 * InnListener.
943 */
944
newDefaultHost(InnListener listener,const char * name)945 Host newDefaultHost (InnListener listener,
946 const char *name)
947 {
948 HostParams p;
949 Host h = NULL;
950
951 if (FindBlockedHost(name)==NULL)
952 {
953
954 p=newHostParams(defaultParams);
955 ASSERT(p!=NULL);
956
957 /* relies on fact listener and names are null in default*/
958 p->peerName=xstrdup(name);
959 p->ipName=xstrdup(name);
960
961 h=newHost (listener,p);
962 if (h==NULL)
963 {
964 /* Couldn't get a lock - add to list of blocked peers */
965 addBlockedHost(p);
966
967 warn ("ME locked cannot setup peer %s", p->peerName);
968
969 return NULL;
970 }
971
972 h->isDynamic = true;
973 h->removeOnReload = true;
974
975 notice ("ME unconfigured peer %s added", p->peerName) ;
976 }
977 return h;
978 }
979
980 /*
981 * Create a new host and attach the supplied param structure
982 */
983
984 static bool inited = false ;
newHost(InnListener listener,HostParams p)985 static Host newHost (InnListener listener, HostParams p)
986 {
987 Host nh ;
988
989 ASSERT (p->maxChecks > 0) ;
990
991 if (!inited)
992 {
993 inited = true ;
994 atexit (hostCleanup) ;
995 }
996
997 /*
998 * Once only, init the first blocked host check
999 */
1000 if (tryBlockedHostsId==0)
1001 tryBlockedHostsId = prepareSleep(tryBlockedHosts,
1002 TRYBLOCKEDHOSTPERIOD, NULL);
1003
1004 nh = xcalloc (1, sizeof(struct host_s)) ;
1005
1006 nh->params = p;
1007 nh->listener = listener;
1008
1009 nh->connections = NULL; /* We'll get these allocated later */
1010 nh->cxnActive = NULL;
1011 nh->cxnSleeping = NULL;
1012
1013 nh->activeCxns = 0 ;
1014 nh->sleepingCxns = 0 ;
1015
1016 nh->blockedCxn = NULL ;
1017 nh->notThisCxn = NULL ;
1018
1019 nh->queued = NULL ;
1020 nh->queuedTail = NULL ;
1021
1022 nh->processed = NULL ;
1023 nh->processedTail = NULL ;
1024
1025 nh->deferred = NULL ;
1026 nh->deferredTail = NULL ;
1027
1028 nh->statsId = 0 ;
1029 nh->ChkCxnsId = 0 ;
1030 nh->deferredId = 0;
1031
1032 nh->myTape = newTape (nh->params->peerName,
1033 listenerIsDummy (nh->listener)) ;
1034 if (nh->myTape == NULL)
1035 { /* tape couldn't be locked, probably */
1036 free (nh->connections) ;
1037 free (nh->cxnActive) ;
1038 free (nh->cxnSleeping) ;
1039
1040 free (nh) ;
1041 return NULL ; /* note we don't free up p */
1042 }
1043
1044 nh->backedUp = false ;
1045 nh->backlog = 0 ;
1046 nh->deferLen = 0 ;
1047
1048 nh->loggedBacklog = false ;
1049 nh->loggedModeOn = false ;
1050 nh->loggedModeOff = false ;
1051 nh->notifiedChangedRemBlckd = false ;
1052 nh->removeOnReload = false ; /* ready for config file reload */
1053 nh->isDynamic = false ;
1054
1055 nh->artsOffered = 0 ;
1056 nh->artsOffered_checkpoint = 0 ;
1057 nh->artsAccepted = 0 ;
1058 nh->artsAccepted_checkpoint = 0 ;
1059 nh->artsNotWanted = 0 ;
1060 nh->artsNotWanted_checkpoint = 0 ;
1061 nh->artsRejected = 0 ;
1062 nh->artsRejected_checkpoint = 0 ;
1063 nh->artsDeferred = 0 ;
1064 nh->artsDeferred_checkpoint = 0 ;
1065 nh->artsMissing = 0 ;
1066 nh->artsMissing_checkpoint = 0 ;
1067 nh->artsToTape = 0 ;
1068 nh->artsToTape_checkpoint = 0 ;
1069 nh->artsQueueOverflow = 0 ;
1070 nh->artsCxnDrop = 0 ;
1071 nh->artsCxnDrop_checkpoint = 0 ;
1072 nh->artsHostSleep = 0 ;
1073 nh->artsHostSleep_checkpoint = 0 ;
1074 nh->artsHostClose = 0 ;
1075 nh->artsHostClose_checkpoint = 0 ;
1076 nh->artsFromTape = 0 ;
1077 nh->artsFromTape_checkpoint = 0 ;
1078 nh->artsSizeAccepted = 0 ;
1079 nh->artsSizeAccepted_checkpoint = 0 ;
1080 nh->artsSizeRejected = 0 ;
1081 nh->artsSizeRejected_checkpoint = 0 ;
1082
1083 nh->artsProcLastPeriod = 0;
1084 nh->secsInLastPeriod = 0;
1085 nh->lastCheckPoint = 0;
1086 nh->lastSentCheckPoint = 0;
1087 nh->lastTotalCheckPoint = 0;
1088 nh->maxCxnChk = true;
1089 nh->lastMaxCxnTime = time(0);
1090 nh->lastChkTime = time(0);
1091 nh->nextCxnTimeChk = 30;
1092 nh->backlogFilter = ((nh->params->dynBacklogLowWaterMark
1093 + nh->params->dynBacklogHighWaterMark)
1094 /200.0 /(1.0-nh->params->dynBacklogFilter));
1095
1096 nh->gArtsOffered = 0 ;
1097 nh->gArtsAccepted = 0 ;
1098 nh->gArtsNotWanted = 0 ;
1099 nh->gArtsRejected = 0 ;
1100 nh->gArtsDeferred = 0 ;
1101 nh->gArtsMissing = 0 ;
1102 nh->gArtsToTape = 0 ;
1103 nh->gArtsQueueOverflow = 0 ;
1104 nh->gArtsCxnDrop = 0 ;
1105 nh->gArtsHostSleep = 0 ;
1106 nh->gArtsHostClose = 0 ;
1107 nh->gArtsFromTape = 0 ;
1108 nh->gArtsSizeAccepted = 0 ;
1109 nh->gArtsSizeRejected = 0 ;
1110 nh->gCxnQueue = 0 ;
1111 nh->gNoQueue = 0 ;
1112
1113 nh->firstConnectTime = 0 ;
1114 nh->connectTime = 0 ;
1115 nh->connectTime_checkpoint = 0 ;
1116
1117 nh->spoolTime = 0 ;
1118 nh->spoolTime_checkpoint = 0 ;
1119
1120 nh->blNone = 0 ;
1121 nh->blFull = 0 ;
1122 nh->blQuartile[0] = nh->blQuartile[1] = nh->blQuartile[2] =
1123 nh->blQuartile[3] = 0 ;
1124 nh->dlAccum = 0;
1125 nh->blAccum = 0;
1126 nh->blCount = 0;
1127
1128
1129 nh->maxConnections = 0; /* we currently have no connections allocated */
1130
1131 /* Note that the following will override the initialCxns specified as
1132 maxCxns if we are on non-dyamic feed
1133 */
1134 hostAlterMaxConnections(nh, nh->params->absMaxConnections,
1135 nh->params->initialConnections, false);
1136
1137 nh->next = gHostList ;
1138 gHostList = nh ;
1139 gHostCount++ ;
1140
1141 if (maxIpNameLen == 0)
1142 {
1143 start = theTime() ;
1144 timeToString (start, startTime, sizeof (startTime)) ;
1145 myPid = getpid() ;
1146 }
1147
1148 if (strlen (nh->params->ipName) > maxIpNameLen)
1149 maxIpNameLen = strlen (nh->params->ipName) ;
1150 if (strlen (nh->params->peerName) > maxPeerNameLen)
1151 maxPeerNameLen = strlen (nh->params->peerName) ;
1152
1153 return nh ;
1154 }
1155
hostIpAddr(Host host)1156 struct sockaddr *hostIpAddr (Host host)
1157 {
1158 int i ;
1159 struct sockaddr **newIpAddrPtrs = NULL;
1160 struct sockaddr_storage *newIpAddrs = NULL;
1161 struct sockaddr *returnAddr;
1162
1163 ASSERT(host->params != NULL);
1164
1165 /* check to see if need to look up the host name */
1166 if (host->nextIpLookup <= theTime())
1167 {
1168 int gai_ret;
1169 struct addrinfo *res, *p;
1170 struct addrinfo hints;
1171 char port[20];
1172
1173 memset(&hints, 0, sizeof(hints));
1174 hints.ai_family = AF_UNSPEC;
1175 #ifdef HAVE_INET6
1176 if (host->params->bindAddr && strcmp(host->params->bindAddr, "none") == 0)
1177 hints.ai_family = AF_INET6;
1178 if (host->params->bindAddr6 && strcmp(host->params->bindAddr6, "none") == 0)
1179 hints.ai_family = AF_INET;
1180 #endif
1181 hints.ai_socktype = SOCK_STREAM;
1182 hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
1183 snprintf(port, sizeof(port), "%hu", host->params->portNum);
1184 gai_ret = getaddrinfo(host->params->ipName, port, &hints, &res);
1185 if (gai_ret != 0 || res == NULL)
1186 {
1187 warn ("%s can't resolve hostname %s: %s", host->params->peerName,
1188 host->params->ipName, gai_ret == 0 ? "no addresses returned"
1189 : gai_strerror(gai_ret)) ;
1190 }
1191 else
1192 {
1193 /* figure number of pointers that need space */
1194 i = 0;
1195 for ( p = res ; p ; p = p->ai_next ) ++i;
1196
1197 newIpAddrPtrs = (struct sockaddr **)
1198 xmalloc ( (i + 1) * sizeof(struct sockaddr *) );
1199
1200 newIpAddrs = (struct sockaddr_storage *)
1201 xmalloc ( i * sizeof(struct sockaddr_storage) );
1202
1203 i = 0;
1204 /* copy the addresses from the getaddrinfo linked list */
1205 for( p = res ; p ; p = p->ai_next )
1206 {
1207 memcpy( &newIpAddrs[i], p->ai_addr, p->ai_addrlen );
1208 newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
1209 ++i;
1210 }
1211 newIpAddrPtrs[i] = NULL ;
1212 freeaddrinfo( res );
1213 }
1214
1215 if (newIpAddrs)
1216 {
1217 if (host->ipAddrs)
1218 {
1219 if(host->ipAddrs[0])
1220 free (host->ipAddrs[0]);
1221 free (host->ipAddrs) ;
1222 }
1223 host->ipAddrs = newIpAddrPtrs ;
1224 host->nextIpAddr = 0 ;
1225 host->nextIpLookup = theTime () + dnsExpPeriod ;
1226 }
1227 else
1228 {
1229 /* failed to setup new addresses */
1230 host->nextIpLookup = theTime () + dnsRetPeriod ;
1231 }
1232 }
1233
1234 if (host->ipAddrs)
1235 returnAddr = host->ipAddrs[host->nextIpAddr] ;
1236 else
1237 returnAddr = NULL ;
1238
1239 return returnAddr ;
1240 }
1241
1242
1243 /*
1244 * Delete IPv4 addresses from the address list.
1245 */
hostDeleteIpv4Addr(Host host)1246 void hostDeleteIpv4Addr (Host host)
1247 {
1248 int i, j;
1249
1250 if (!host->ipAddrs)
1251 return;
1252 for (i = 0, j = 0; host->ipAddrs[i]; i++) {
1253 if (host->ipAddrs[i]->sa_family != AF_INET)
1254 host->ipAddrs[j++] = host->ipAddrs[i];
1255 }
1256 host->ipAddrs[j] = 0;
1257 if (host->nextIpAddr >= j)
1258 host->nextIpAddr = 0;
1259 }
1260
1261
hostIpFailed(Host host)1262 void hostIpFailed (Host host)
1263 {
1264 if (host->ipAddrs)
1265 if (host->ipAddrs[++host->nextIpAddr] == NULL)
1266 host->nextIpAddr = 0 ;
1267 }
1268
1269
gPrintHostInfo(FILE * fp,unsigned int indentAmt)1270 void gPrintHostInfo (FILE *fp, unsigned int indentAmt)
1271 {
1272 Host h ;
1273 char indent [INDENT_BUFFER_SIZE] ;
1274 unsigned int i ;
1275
1276 for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
1277 indent [i] = ' ' ;
1278 indent [i] = '\0' ;
1279
1280 fprintf (fp,"%sGlobal Host list : (count %u) {\n",indent,gHostCount) ;
1281
1282 for (h = gHostList ; h != NULL ; h = h->next)
1283 printHostInfo (h,fp,indentAmt + INDENT_INCR) ;
1284
1285 fprintf (fp,"%s}\n",indent) ;
1286 }
1287
1288
printHostInfo(Host host,FILE * fp,unsigned int indentAmt)1289 void printHostInfo (Host host, FILE *fp, unsigned int indentAmt)
1290 {
1291 char dateString [30] ;
1292 char indent [INDENT_BUFFER_SIZE] ;
1293 unsigned int i ;
1294 ProcQElem qe ;
1295 double cnt ;
1296
1297 for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
1298 indent [i] = ' ' ;
1299 indent [i] = '\0' ;
1300
1301 if (host == NULL) {
1302 fprintf(fp, "%sHost : NULL {\n%s}\n", indent, indent);
1303 return;
1304 }
1305
1306 cnt = (host->blCount) ? (host->blCount) : 1.0;
1307
1308 fprintf (fp,"%sHost : %p {\n", indent, (void *) host) ;
1309 fprintf (fp,"%s peer-name : %s\n",indent,host->params->peerName) ;
1310 fprintf (fp,"%s ip-name : %s\n",indent,host->params->ipName) ;
1311 fprintf (fp,"%s bindaddress : %s\n",indent,
1312 host->params->bindAddr ? host->params->bindAddr : "any") ;
1313 fprintf (fp,"%s bindaddress6 : %s\n",indent,
1314 host->params->bindAddr6 ? host->params->bindAddr6 : "any") ;
1315 fprintf (fp,"%s abs-max-connections : %u\n",indent,
1316 host->params->absMaxConnections) ;
1317 fprintf (fp,"%s active-connections : %u\n",indent,host->activeCxns) ;
1318 fprintf (fp,"%s sleeping-connections : %u\n",indent,host->sleepingCxns) ;
1319 fprintf (fp,"%s initial-connections : %u\n",indent,
1320 host->params->initialConnections) ;
1321 fprintf (fp,"%s want-streaming : %s\n",indent,
1322 boolToString (host->params->wantStreaming)) ;
1323 fprintf (fp,"%s drop-deferred : %s\n",indent,
1324 boolToString (host->params->dropDeferred)) ;
1325 fprintf (fp,"%s min-queue-connection : %s\n",indent,
1326 boolToString (host->params->minQueueCxn)) ;
1327 fprintf (fp,"%s remote-streams : %s\n",indent,
1328 boolToString (host->remoteStreams)) ;
1329 fprintf (fp,"%s max-checks : %u\n",indent,host->params->maxChecks) ;
1330 fprintf (fp,"%s article-timeout : %u\n",indent,
1331 host->params->articleTimeout) ;
1332 fprintf (fp,"%s response-timeout : %u\n",indent,
1333 host->params->responseTimeout) ;
1334 fprintf (fp,"%s close-period : %u\n",indent,
1335 host->params->closePeriod) ;
1336 fprintf (fp,"%s port : %u\n",indent,host->params->portNum) ;
1337 fprintf (fp,"%s dynamic-method : %u\n",indent,
1338 host->params->dynamicMethod) ;
1339 fprintf (fp,"%s dynamic-backlog-filter : %2.1f\n",indent,
1340 host->params->dynBacklogFilter) ;
1341 fprintf (fp,"%s dynamic-backlog-lwm : %2.1f\n",indent,
1342 host->params->dynBacklogLowWaterMark) ;
1343 fprintf (fp,"%s dynamic-backlog-hwm : %2.1f\n",indent,
1344 host->params->dynBacklogHighWaterMark) ;
1345 fprintf (fp,"%s no-check on : %2.1f\n",indent,
1346 host->params->lowPassHigh) ;
1347 fprintf (fp,"%s no-check off : %2.1f\n",indent,
1348 host->params->lowPassLow) ;
1349 fprintf (fp,"%s no-check filter : %2.1f\n",indent,
1350 host->params->lowPassFilter) ;
1351 fprintf (fp,"%s backlog-limit : %u\n",indent,
1352 host->params->backlogLimit) ;
1353 fprintf (fp,"%s backlog-limit-highwater : %u\n",indent,
1354 host->params->backlogLimitHigh) ;
1355 fprintf (fp,"%s backlog-factor : %2.1f\n",indent,
1356 host->params->backlogFactor) ;
1357 fprintf (fp,"%s max-connections : %u\n",indent,
1358 host->maxConnections) ;
1359 fprintf (fp,"%s backlog-feed-first : %s\n",indent,
1360 boolToString (host->params->backlogFeedFirst)) ;
1361
1362
1363 fprintf (fp,"%s statistics-id : %d\n",indent,host->statsId) ;
1364 fprintf (fp,"%s ChkCxns-id : %d\n",indent,host->ChkCxnsId) ;
1365 fprintf (fp,"%s deferred-id : %d\n",indent,host->deferredId) ;
1366 fprintf (fp,"%s backed-up : %s\n",indent,boolToString (host->backedUp));
1367 fprintf (fp,"%s backlog : %u\n",indent,host->backlog) ;
1368 fprintf (fp,"%s deferLen : %u\n",indent,host->deferLen) ;
1369 fprintf (fp,"%s loggedModeOn : %s\n",indent,
1370 boolToString (host->loggedModeOn)) ;
1371 fprintf (fp,"%s loggedModeOff : %s\n",indent,
1372 boolToString (host->loggedModeOff)) ;
1373 fprintf (fp,"%s logged-backlog : %s\n",indent,
1374 boolToString (host->loggedBacklog)) ;
1375 fprintf (fp,"%s streaming-type changed : %s\n",indent,
1376 boolToString (host->notifiedChangedRemBlckd)) ;
1377 fprintf (fp,"%s articles offered : %u\n",indent,host->artsOffered) ;
1378 fprintf (fp,"%s articles accepted : %u\n",indent,host->artsAccepted) ;
1379 fprintf (fp,"%s articles not wanted : %u\n",indent,
1380 host->artsNotWanted) ;
1381 fprintf (fp,"%s articles rejected : %u\n",indent,host->artsRejected);
1382 fprintf (fp,"%s articles deferred : %u\n",indent,host->artsDeferred) ;
1383 fprintf (fp,"%s articles missing : %u\n",indent,host->artsMissing) ;
1384 fprintf (fp,"%s articles spooled : %u\n",indent,host->artsToTape) ;
1385 fprintf (fp,"%s because of queue overflow : %u\n",indent,
1386 host->artsQueueOverflow) ;
1387 fprintf (fp,"%s when the we closed the host : %u\n",indent,
1388 host->artsHostClose) ;
1389 fprintf (fp,"%s because the host was asleep : %u\n",indent,
1390 host->artsHostSleep) ;
1391 fprintf (fp,"%s articles unspooled : %u\n",indent,host->artsFromTape) ;
1392 fprintf (fp,"%s articles requeued from dropped connections : %u\n",indent,
1393 host->artsCxnDrop) ;
1394
1395 fprintf (fp,"%s process articles offered : %u\n",indent,
1396 host->gArtsOffered) ;
1397 fprintf (fp,"%s process articles accepted : %u\n",indent,
1398 host->gArtsAccepted) ;
1399 fprintf (fp,"%s process articles not wanted : %u\n",indent,
1400 host->gArtsNotWanted) ;
1401 fprintf (fp,"%s process articles rejected : %u\n",indent,
1402 host->gArtsRejected);
1403 fprintf (fp,"%s process articles deferred : %u\n",indent,
1404 host->gArtsDeferred) ;
1405 fprintf (fp,"%s process articles missing : %u\n",indent,
1406 host->gArtsMissing) ;
1407 fprintf (fp,"%s process articles spooled : %u\n",indent,
1408 host->gArtsToTape) ;
1409 fprintf (fp,"%s because of queue overflow : %u\n",indent,
1410 host->gArtsQueueOverflow) ;
1411 fprintf (fp,"%s when the we closed the host : %u\n",indent,
1412 host->gArtsHostClose) ;
1413 fprintf (fp,"%s because the host was asleep : %u\n",indent,
1414 host->gArtsHostSleep) ;
1415 fprintf (fp,"%s process articles unspooled : %u\n",indent,
1416 host->gArtsFromTape) ;
1417 fprintf (fp,"%s process articles requeued from dropped connections : %u\n",
1418 indent, host->gArtsCxnDrop) ;
1419
1420 fprintf (fp,"%s average (mean) defer length : %.1f\n", indent,
1421 (double) host->dlAccum / cnt) ;
1422 fprintf (fp,"%s average (mean) queue length : %.1f\n", indent,
1423 (double) host->blAccum / cnt) ;
1424 fprintf (fp,"%s percentage of the time empty : %.1f\n", indent,
1425 100.0 * host->blNone / cnt) ;
1426 fprintf (fp,"%s percentage of the time >0%%-25%% : %.1f\n", indent,
1427 100.0 * host->blQuartile[0] / cnt) ;
1428 fprintf (fp,"%s percentage of the time 25%%-50%% : %.1f\n", indent,
1429 100.0 * host->blQuartile[1] / cnt) ;
1430 fprintf (fp,"%s percentage of the time 50%%-75%% : %.1f\n", indent,
1431 100.0 * host->blQuartile[2] / cnt) ;
1432 fprintf (fp,"%s percentage of the time 75%%-<100%% : %.1f\n", indent,
1433 100.0 * host->blQuartile[3] / cnt) ;
1434 fprintf (fp,"%s percentage of the time full : %.1f\n", indent,
1435 100.0 * host->blFull / cnt) ;
1436 fprintf (fp,"%s number of samples : %u\n", indent, host->blCount) ;
1437
1438 timeToString (host->firstConnectTime, dateString, sizeof (dateString));
1439 fprintf (fp, "%s firstConnectTime : %s\n", indent, dateString);
1440
1441 timeToString (host->connectTime, dateString, sizeof (dateString));
1442 fprintf (fp, "%s connectTime : %s\n", indent, dateString);
1443
1444 timeToString (host->spoolTime, dateString, sizeof (dateString));
1445 fprintf (fp, "%s spoolTime : %s\n", indent, dateString);
1446
1447 timeToString (host->lastSpoolTime, dateString, sizeof (dateString));
1448 fprintf (fp, "%s last-spool-time : %s\n", indent, dateString);
1449
1450 #if 0
1451 fprintf (fp,"%s tape {\n",indent) ;
1452 printTapeInfo (host->myTape,fp,indentAmt + INDENT_INCR) ;
1453 fprintf (fp,"%s }\n",indent) ;
1454 #else
1455 fprintf (fp,"%s tape : %p\n",indent,(void *) host->myTape) ;
1456 #endif
1457
1458 fprintf (fp,"%s QUEUED articles {\n",indent) ;
1459 for (qe = host->queued ; qe != NULL ; qe = qe->next)
1460 {
1461 #if 0
1462 printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
1463 #else
1464 fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
1465 #endif
1466 }
1467
1468 fprintf (fp,"%s }\n",indent) ;
1469
1470 fprintf (fp,"%s IN PROCESS articles {\n",indent) ;
1471 for (qe = host->processed ; qe != NULL ; qe = qe->next)
1472 {
1473 #if 0
1474 printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
1475 #else
1476 fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
1477 #endif
1478 }
1479
1480 fprintf (fp,"%s }\n",indent) ;
1481 fprintf (fp,"%s DEFERRED articles {\n",indent) ;
1482 for (qe = host->deferred ; qe != NULL ; qe = qe->next)
1483 {
1484 #if 0
1485 printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
1486 #else
1487 fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
1488 #endif
1489 }
1490
1491 fprintf (fp,"%s }\n",indent) ;
1492 fprintf (fp,"%s DEFERRED articles {\n",indent) ;
1493 for (qe = host->deferred ; qe != NULL ; qe = qe->next)
1494 {
1495 #if 0
1496 printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
1497 #else
1498 fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
1499 #endif
1500 }
1501
1502 fprintf (fp,"%s }\n",indent) ;
1503
1504
1505
1506 fprintf (fp,"%s Connections {\n",indent) ;
1507 for (i = 0 ; i < host->maxConnections ; i++)
1508 {
1509 #if 0
1510 if (host->connections[i] != NULL)
1511 printCxnInfo (*cxn,fp,indentAmt + INDENT_INCR) ;
1512 #else
1513 fprintf (fp,"%s %p\n",indent,(void *) host->connections[i]) ;
1514 #endif
1515 }
1516 fprintf (fp,"%s }\n",indent) ;
1517
1518 fprintf (fp,"%s Active Connections {\n%s ",indent,indent) ;
1519 for (i = 0 ; i < host->maxConnections ; i++)
1520 if (host->cxnActive[i])
1521 fprintf (fp," [%u:%p]",i,(void *) host->connections[i]) ;
1522 fprintf (fp,"\n%s }\n",indent) ;
1523
1524 fprintf (fp,"%s Sleeping Connections {\n%s ",indent,indent) ;
1525 for (i = 0 ; i < host->maxConnections ; i++)
1526 if (host->cxnSleeping[i])
1527 fprintf (fp," [%u:%p]",i,(void *) host->connections[i]) ;
1528 fprintf (fp,"\n%s }\n",indent) ;
1529
1530 fprintf (fp,"%s}\n",indent) ;
1531 }
1532
1533
1534
1535
1536
1537
1538
1539 /* close down all the connections of the Host. All articles that are in
1540 * processes are still pushed out and then a QUIT is issued. The Host will
1541 * also spool all inprocess articles to tape incase the process is about to
1542 * be killed (they'll be refused next time around). When all Connections
1543 * report that they're gone, then the Host will delete itself.
1544 */
hostClose(Host host)1545 void hostClose (Host host)
1546 {
1547 unsigned int i ;
1548 unsigned int cxnCount ;
1549
1550 d_printf (1,"Closing host %s\n",host->params->peerName) ;
1551
1552 queuesToTape (host) ;
1553 delTape (host->myTape) ;
1554 host->myTape = NULL ;
1555
1556 hostLogStats (host,true) ;
1557
1558 clearTimer (host->statsId) ;
1559 clearTimer (host->ChkCxnsId) ;
1560 clearTimer (host->deferredId) ;
1561
1562 host->connectTime = 0 ;
1563
1564 /* when we call cxnTerminate() on the last Connection, the Host objects
1565 will end up getting deleted out from under us (via hostCxnGone()). If
1566 we are running with a malloc that scribbles over memory after freeing
1567 it, then we'd fail in the second for loop test. Trying to access
1568 host->maxConnections. */
1569 for (i = 0, cxnCount = 0 ; i < host->maxConnections ; i++)
1570 cxnCount += (host->connections [i] != NULL ? 1 : 0) ;
1571 for (i = 0 ; i < cxnCount ; i++)
1572 if (host->connections[i] != NULL)
1573 cxnTerminate (host->connections [i]) ;
1574 }
1575
1576
1577 /*
1578 * check if host should get more connections opened, or some closed...
1579 */
hostChkCxns(TimeoutId tid UNUSED,void * data)1580 void hostChkCxns(TimeoutId tid UNUSED, void *data) {
1581 Host host = (Host) data;
1582 unsigned int currArticles, currSentArticles, currTotalArticles, newMaxCxns ;
1583 double lastAPS, currAPS, percentTaken, ratio ;
1584 double backlogRatio, backlogMult;
1585
1586 if(!host->maxCxnChk)
1587 return;
1588
1589 ASSERT(host->params != NULL);
1590
1591 if(host->secsInLastPeriod > 0)
1592 lastAPS = host->artsProcLastPeriod / (host->secsInLastPeriod * 1.0);
1593 else
1594 lastAPS = host->artsProcLastPeriod * 1.0;
1595
1596 newMaxCxns = host->maxConnections;
1597
1598 currArticles = (host->gArtsAccepted + host->gArtsRejected +
1599 (host->gArtsNotWanted / 4)) - host->lastCheckPoint ;
1600
1601 host->lastCheckPoint = (host->gArtsAccepted + host->gArtsRejected +
1602 (host->gArtsNotWanted / 4));
1603
1604 currSentArticles = host->gArtsAccepted + host->gArtsRejected
1605 - host->lastSentCheckPoint ;
1606
1607 host->lastSentCheckPoint = host->gArtsAccepted + host->gArtsRejected;
1608
1609 currTotalArticles = host->gArtsAccepted + host->gArtsRejected
1610 + host->gArtsRejected + host->gArtsQueueOverflow
1611 - host->lastTotalCheckPoint ;
1612
1613 host->lastTotalCheckPoint = host->gArtsAccepted + host->gArtsRejected
1614 + host->gArtsRejected + host->gArtsQueueOverflow ;
1615
1616 currAPS = currArticles / (host->nextCxnTimeChk * 1.0) ;
1617
1618 percentTaken = currSentArticles * 1.0 /
1619 ((currTotalArticles==0)?1:currTotalArticles);
1620
1621 /* Get how full the queue is currently */
1622 backlogRatio = (host->backlog * 1.0 / hostHighwater);
1623 backlogMult = 1.0/(1.0-host->params->dynBacklogFilter);
1624
1625 d_printf(1,"%s hostChkCxns - entry filter=%3.3f blmult=%3.3f blratio=%3.3f\n",host->params->peerName,host->backlogFilter, backlogMult, backlogRatio);
1626
1627 ratio = 0.0; /* ignore APS by default */
1628
1629 switch (host->params->dynamicMethod)
1630 {
1631 case METHOD_COMBINED:
1632 /* When a high % of articles is being taken, take notice of the
1633 * APS values. However for smaller %s, quickly start to ignore this
1634 * and concentrate on queue sizes
1635 */
1636 ratio = percentTaken * percentTaken;
1637 /* fallthrough */
1638 case METHOD_QUEUE:
1639 /* backlogFilter is an IIR filtered version of the backlogRatio.
1640 */
1641 host->backlogFilter *= host->params->dynBacklogFilter;
1642 /* Penalise anything over the backlog HWM twice as severely
1643 * (otherwise we end up feeding some sites constantly
1644 * just below the HWM. This way random noise makes
1645 * such sites jump to one more connection
1646 *
1647 * Use factor (1-ratio) so if ratio is near 1 we ignore this
1648 */
1649 if (backlogRatio>host->params->dynBacklogLowWaterMark/100.0)
1650 host->backlogFilter += (backlogRatio+1.0)/2.0 * (1.0-ratio);
1651 else
1652 host->backlogFilter += backlogRatio * (1.0-ratio);
1653
1654 /*
1655 * Now bump it around for APS too
1656 */
1657 if ((currAPS - lastAPS) >= 0.1)
1658 host->backlogFilter += ratio*((currAPS - lastAPS) + 1.0);
1659 else if ((currAPS - lastAPS) < -.2)
1660 host->backlogFilter -= ratio;
1661
1662 d_printf(1,"%s hostChkCxns - entry hwm=%3.3f lwm=%3.3f new=%3.3f [%3.3f,%3.3f]\n",
1663 host->params->peerName,host->params->dynBacklogHighWaterMark,
1664 host->params->dynBacklogLowWaterMark,host->backlogFilter,
1665 (host->params->dynBacklogLowWaterMark * backlogMult / 100.0),
1666 (host->params->dynBacklogHighWaterMark * backlogMult / 100.0));
1667
1668 if (host->backlogFilter <
1669 (host->params->dynBacklogLowWaterMark * backlogMult / 100.0))
1670 newMaxCxns--;
1671 else if (host->backlogFilter >
1672 (host->params->dynBacklogHighWaterMark * backlogMult / 100.0))
1673 newMaxCxns++;
1674 break;
1675 case METHOD_STATIC:
1676 /* well not much to do, just check maxConnection = absMaxConnections */
1677 ASSERT (host->maxConnections == MAXCONLIMIT(host->params->absMaxConnections));
1678 break;
1679 case METHOD_APS:
1680 if ((currAPS - lastAPS) >= 0.1)
1681 newMaxCxns += (int)(currAPS - lastAPS) + 1 ;
1682 else if ((currAPS - lastAPS) < -.2)
1683 newMaxCxns--;
1684 break;
1685 }
1686
1687 d_printf(1, "hostChkCxns: Chngs %f\n", currAPS - lastAPS);
1688
1689 if (newMaxCxns < 1) newMaxCxns=1;
1690 if (newMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
1691 newMaxCxns = MAXCONLIMIT(host->params->absMaxConnections);
1692
1693 if (newMaxCxns != host->maxConnections)
1694 {
1695 notice ("%s hostChkCxns - maxConnections was %d now %d",
1696 host->params->peerName, host->maxConnections,newMaxCxns);
1697
1698 host->backlogFilter= ((host->params->dynBacklogLowWaterMark
1699 + host->params->dynBacklogHighWaterMark)
1700 /200.0 * backlogMult);
1701 host->artsProcLastPeriod = currArticles ;
1702 host->secsInLastPeriod = host->nextCxnTimeChk ;
1703
1704 /* Alter MaxConnections and in doing so ensure we connect new
1705 cxns immediately if we are adding stuff
1706 */
1707 hostAlterMaxConnections(host, host->params->absMaxConnections,
1708 newMaxCxns, true);
1709 }
1710
1711 if(host->nextCxnTimeChk <= 240) host->nextCxnTimeChk *= 2;
1712 else host->nextCxnTimeChk = 300;
1713 d_printf(1, "prepareSleep hostChkCxns, %d\n", host->nextCxnTimeChk);
1714 host->ChkCxnsId = prepareSleep(hostChkCxns, host->nextCxnTimeChk, host);
1715 }
1716
1717
1718 /*
1719 * have the Host transmit the Article if possible.
1720 */
hostSendArticle(Host host,Article article)1721 void hostSendArticle (Host host, Article article)
1722 {
1723 ASSERT(host->params != NULL);
1724 if (host->spoolTime > 0)
1725 { /* all connections are asleep */
1726 host->artsHostSleep++ ;
1727 host->gArtsHostSleep++ ;
1728 host->artsToTape++ ;
1729 host->gArtsToTape++ ;
1730 procArtsToTape++ ;
1731 tapeTakeArticle (host->myTape, article) ;
1732 return ;
1733 }
1734
1735 /* at least one connection is feeding or waiting and there's no backlog */
1736 if (host->queued == NULL)
1737 {
1738 unsigned int idx ;
1739 Article extraRef ;
1740 Connection cxn = NULL ;
1741
1742 extraRef = artTakeRef (article) ; /* the referrence we give away */
1743
1744 /* stick on the queue of articles we've handed off--we're hopeful. */
1745 queueArticle (article,&host->processed,&host->processedTail, 0) ;
1746
1747 if (host->params->minQueueCxn) {
1748 Connection x_cxn = NULL ;
1749 unsigned int x_queue = host->params->maxChecks + 1 ;
1750
1751 for (idx = 0 ; x_queue > 0 && idx < host->maxConnections ; idx++)
1752 if ((cxn = host->connections[idx]) != host->notThisCxn && cxn != NULL) {
1753 if (!host->cxnActive [idx]) {
1754 if (!host->cxnSleeping [idx]) {
1755 if (cxnTakeArticle (cxn, extraRef)) {
1756 host->gNoQueue++ ;
1757 return ;
1758 } else
1759 d_printf (1,"%s Inactive connection %d refused an article\n",
1760 host->params->peerName,idx) ;
1761 }
1762 } else {
1763 unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) ;
1764 if (queue < x_queue) {
1765 x_queue = queue ;
1766 x_cxn = cxn ;
1767 }
1768 }
1769 }
1770
1771 if (x_cxn != NULL && cxnTakeArticle (x_cxn, extraRef)) {
1772 if (x_queue == 0) host->gNoQueue++ ;
1773 else host->gCxnQueue += x_queue ;
1774 return ;
1775 }
1776
1777 } else {
1778
1779 /* first we try to give it to one of our active connections. We
1780 simply start at the bottom and work our way up. This way
1781 connections near the end of the list will get closed sooner from
1782 idleness. */
1783 for (idx = 0 ; idx < host->maxConnections ; idx++)
1784 {
1785 if (host->cxnActive [idx] &&
1786 (cxn = host->connections[idx]) != host->notThisCxn &&
1787 cxn != NULL && cxnTakeArticle (cxn, extraRef)) {
1788 unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
1789 if (queue == 0) host->gNoQueue++ ;
1790 else host->gCxnQueue += queue ;
1791 return ;
1792 }
1793 }
1794
1795 /* Wasn't taken so try to give it to one of the waiting connections. */
1796 for (idx = 0 ; idx < host->maxConnections ; idx++)
1797 if (!host->cxnActive [idx] && !host->cxnSleeping [idx] &&
1798 (cxn = host->connections[idx]) != host->notThisCxn && cxn != NULL)
1799 {
1800 if (cxnTakeArticle (cxn, extraRef)) {
1801 unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
1802 if (queue == 0) host->gNoQueue++ ;
1803 else host->gCxnQueue += queue ;
1804 return ;
1805 } else
1806 d_printf (1,"%s Inactive connection %d refused an article\n",
1807 host->params->peerName,idx) ;
1808 }
1809 }
1810
1811 /* this'll happen if all connections are feeding and all
1812 their queues are full, or if those not feeding are asleep. */
1813 d_printf (1, "Couldn't give the article to a connection\n") ;
1814
1815 delArticle (extraRef) ;
1816
1817 remArticle (article,&host->processed,&host->processedTail) ;
1818
1819 /* cxn can be NULL if it has never been affected in the loop above. */
1820 if (cxn == NULL || !cxnCheckstate (cxn))
1821 {
1822 host->artsToTape++ ;
1823 host->gArtsToTape++ ;
1824 procArtsToTape++ ;
1825 tapeTakeArticle (host->myTape,article) ;
1826 return ;
1827 }
1828 }
1829
1830 /* Either all the peer connection queues were full or we already had
1831 a backlog, so there was no sense in checking. */
1832 queueArticle (article,&host->queued,&host->queuedTail, 0) ;
1833
1834 host->backlog++ ;
1835 backlogToTape (host) ;
1836 }
1837
1838
1839
1840
1841
1842
1843
1844 /*
1845 * called by the Host's connection when the remote is refusing postings
1846 * from us becasue we're not allowed (banner code 400).
1847 */
hostCxnBlocked(Host host,Connection cxn,char * reason)1848 void hostCxnBlocked (Host host, Connection cxn, char *reason)
1849 {
1850 ASSERT(host->params != NULL);
1851 #ifndef NDEBUG
1852 {
1853 unsigned int i ;
1854
1855 for (i = 0 ; i < host->maxConnections ; i++)
1856 if (host->connections [i] == cxn)
1857 ASSERT (host->cxnActive [i] == false) ;
1858 }
1859 #endif
1860
1861 if (host->blockedReason == NULL)
1862 host->blockedReason = xstrdup (reason) ;
1863
1864 if (host->activeCxns == 0 && host->spoolTime == 0)
1865 {
1866 host->blockedCxn = cxn ; /* to limit log notices */
1867 notice ("%s remote cannot accept articles initial: %s",
1868 host->params->peerName, reason) ;
1869 }
1870 else if (host->activeCxns > 0 && !host->notifiedChangedRemBlckd)
1871 {
1872 notice ("%s remote cannot accept articles change: %s",
1873 host->params->peerName, reason) ;
1874 host->notifiedChangedRemBlckd = true ;
1875 }
1876 else if (host->spoolTime != 0 && host->blockedCxn == cxn)
1877 {
1878 notice ("%s remote cannot accept articles still: %s",
1879 host->params->peerName, reason) ;
1880 }
1881
1882 }
1883
1884
1885
1886
1887
1888
1889
1890 /*
1891 * Called by the Connection when it gets a response back to the MODE
1892 * STREAM command. It's now that we consider the connection usable.
1893 */
hostRemoteStreams(Host host,Connection cxn,bool doesStreaming)1894 void hostRemoteStreams (Host host, Connection cxn, bool doesStreaming)
1895 {
1896 unsigned int i ;
1897
1898 host->blockedCxn = NULL ;
1899 if (host->blockedReason != NULL)
1900 free (host->blockedReason) ;
1901 host->blockedReason = NULL ;
1902
1903 /* we may have told the connection to quit while it was in the middle
1904 of connecting */
1905 if (amClosing (host))
1906 return ;
1907
1908 if (host->connectTime == 0) /* first connection for this cycle. */
1909 {
1910 if (doesStreaming && host->params->wantStreaming)
1911 notice ("%s remote MODE STREAM", host->params->peerName) ;
1912 else if (doesStreaming)
1913 notice ("%s remote MODE STREAM disabled", host->params->peerName) ;
1914 else
1915 notice ("%s remote MODE STREAM failed", host->params->peerName) ;
1916
1917 if (host->spoolTime > 0)
1918 hostStopSpooling (host) ;
1919
1920 /* set up the callback for statistics logging. */
1921 if (host->statsId != 0)
1922 clearTimer (host->statsId) ;
1923 host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
1924
1925 if (host->ChkCxnsId != 0)
1926 clearTimer (host->ChkCxnsId);
1927 host->ChkCxnsId = prepareSleep (hostChkCxns, 30, host) ;
1928
1929 host->remoteStreams = (host->params->wantStreaming ? doesStreaming : false) ;
1930
1931 host->connectTime = theTime() ;
1932 host->connectTime_checkpoint = host->connectTime ;
1933
1934 if (host->firstConnectTime == 0)
1935 host->firstConnectTime = host->connectTime ;
1936 }
1937 else if (host->remoteStreams != doesStreaming && host->params->wantStreaming)
1938 notice ("%s remote MODE STREAM change", host->params->peerName) ;
1939
1940 for (i = 0 ; i < host->maxConnections ; i++)
1941 if (host->connections [i] == cxn)
1942 {
1943 host->cxnActive [i] = true ;
1944 if (host->cxnSleeping [i])
1945 host->sleepingCxns-- ;
1946 host->cxnSleeping [i] = false ;
1947 break ;
1948 }
1949
1950 ASSERT (i != host->maxConnections) ;
1951
1952 host->activeCxns++ ;
1953
1954 hostLogStatus () ;
1955 }
1956
1957
1958
1959
1960
1961
1962
1963 /*
1964 * Called by the connection when it is no longer connected to the
1965 * remote. Perhaps due to getting a code 400 to an IHAVE, or due to a
1966 * periodic close.
1967 */
hostCxnDead(Host host,Connection cxn)1968 void hostCxnDead (Host host, Connection cxn)
1969 {
1970 unsigned int i ;
1971
1972 for (i = 0 ; i < host->maxConnections ; i++)
1973 if (host->connections [i] == cxn)
1974 {
1975 if (host->cxnActive [i]) /* won't be active if got 400 on banner */
1976 {
1977 host->cxnActive [i] = false ;
1978 host->activeCxns-- ;
1979
1980 if (!amClosing (host) && host->activeCxns == 0)
1981 {
1982 clearTimer (host->statsId) ;
1983 clearTimer (host->ChkCxnsId) ;
1984 hostLogStats (host,true) ;
1985 host->connectTime = 0 ;
1986 }
1987 }
1988 else if (host->cxnSleeping [i]) /* cxnNuke can be called on sleepers */
1989 {
1990 host->cxnSleeping [i] = false ;
1991 host->sleepingCxns-- ;
1992 }
1993
1994 break ;
1995 }
1996
1997 ASSERT (i < host->maxConnections) ;
1998 hostLogStatus () ;
1999 }
2000
2001
2002
2003
2004
2005
2006
2007 /*
2008 * Called by the Connection when it is going to sleep so the Host won't
2009 * bother trying to give it Articles
2010 */
hostCxnSleeping(Host host,Connection cxn)2011 void hostCxnSleeping (Host host, Connection cxn)
2012 {
2013 unsigned int i ;
2014
2015 for (i = 0 ; i < host->maxConnections ; i++)
2016 if (host->connections [i] == cxn)
2017 {
2018 if (!host->cxnSleeping [i])
2019 {
2020 host->cxnSleeping [i] = true ;
2021 host->sleepingCxns++ ;
2022 }
2023
2024 if (host->spoolTime == 0 && host->sleepingCxns >= host->maxConnections)
2025 hostStartSpooling (host) ;
2026
2027 break ;
2028 }
2029
2030 ASSERT (i < host->maxConnections) ;
2031
2032 hostLogStatus () ;
2033 }
2034
2035
2036
2037
2038
2039
2040
2041 /*
2042 * Called by the Connection when it goes into the waiting state.
2043 */
hostCxnWaiting(Host host,Connection cxn)2044 void hostCxnWaiting (Host host, Connection cxn)
2045 {
2046 unsigned int i ;
2047
2048 for (i = 0 ; i < host->maxConnections ; i++)
2049 if (host->connections [i] == cxn)
2050 {
2051 if (host->cxnSleeping [i])
2052 host->sleepingCxns-- ;
2053 host->cxnSleeping [i] = false ;
2054 break ;
2055 }
2056
2057 ASSERT (i < host->maxConnections) ;
2058
2059 if (host->spoolTime > 0)
2060 hostStopSpooling (host) ;
2061
2062 hostLogStatus () ;
2063 }
2064
2065
2066
2067
2068
2069
2070
2071 /*
2072 * Called by the Connection when it is about to delete itself.
2073 */
hostCxnGone(Host host,Connection cxn)2074 bool hostCxnGone (Host host, Connection cxn)
2075 {
2076 unsigned int i;
2077 bool oneThere = false ;
2078 char msgstr[SMBUF] ;
2079
2080 /* forget about the Connection and see if we are still holding any live
2081 connections still. */
2082 for (i = 0 ; i < host->maxConnections ; i++)
2083 if (host->connections [i] == cxn)
2084 {
2085 if (!amClosing (host))
2086 {
2087 warn ("%s:%d connection vanishing", host->params->peerName, i) ;
2088 }
2089 host->connections [i] = NULL ;
2090 if (host->cxnActive [i])
2091 {
2092 host->cxnActive [i] = false ;
2093 host->activeCxns-- ;
2094 }
2095 else if (host->cxnSleeping [i])
2096 {
2097 host->cxnSleeping [i] = false ;
2098 host->sleepingCxns-- ;
2099 }
2100 }
2101 else if (host->connections [i] != NULL)
2102 oneThere = true ;
2103
2104 /* remove the host if it has no connexions */
2105 if ( !oneThere )
2106 {
2107 time_t now = theTime() ;
2108 unsigned int hostsLeft ;
2109
2110 if (host->firstConnectTime > 0) {
2111 snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
2112 host->gArtsSizeAccepted, host->gArtsSizeRejected);
2113 notice ("%s global seconds %ld offered %d accepted %d refused %d"
2114 " rejected %d missing %d %s spooled %d unspooled %d",
2115 host->params->peerName, (long) (now - host->firstConnectTime),
2116 host->gArtsOffered, host->gArtsAccepted,
2117 host->gArtsNotWanted, host->gArtsRejected,
2118 host->gArtsMissing, msgstr,
2119 host->gArtsToTape, host->gArtsFromTape) ;
2120 }
2121
2122 hostsLeft = listenerHostGone (host->listener, host) ;
2123 delHost (host) ;
2124
2125 if (hostsLeft == 0) {
2126 snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
2127 (double) procArtsSizeAccepted, (double) procArtsSizeRejected);
2128 notice ("ME global seconds %ld offered %ld accepted %ld refused %ld"
2129 " rejected %ld missing %ld %s spooled %ld unspooled %ld",
2130 (long) (now - start),
2131 procArtsOffered, procArtsAccepted,
2132 procArtsNotWanted,procArtsRejected,
2133 procArtsMissing, msgstr,
2134 procArtsToTape, procArtsFromTape) ;
2135 }
2136
2137 /* return true if that was the last host */
2138 return (hostsLeft == 0 ? true : false) ;
2139 }
2140
2141 /* return false because there is still at least one host (this one) */
2142 return false ;
2143 }
2144
2145
2146
2147
2148
2149
2150
2151 /*
2152 * The connections has offered an article to the remote.
2153 */
hostArticleOffered(Host host,Connection cxn UNUSED)2154 void hostArticleOffered (Host host, Connection cxn UNUSED)
2155 {
2156 host->artsOffered++ ;
2157 host->gArtsOffered++ ;
2158 procArtsOffered++ ;
2159 }
2160
2161
2162
2163
2164
2165
2166
2167 /*
2168 * Article was succesfully transferred.
2169 */
hostArticleAccepted(Host host,Connection cxn,Article article)2170 void hostArticleAccepted (Host host, Connection cxn, Article article)
2171 {
2172 const char *filename = artFileName (article) ;
2173 const char *msgid = artMsgId (article) ;
2174 double len = artSize (article);
2175
2176 d_printf (5,"Article %s (%s) was transferred\n", msgid, filename) ;
2177
2178 host->artsAccepted++ ;
2179 host->gArtsAccepted++ ;
2180 procArtsAccepted++ ;
2181 host->artsSizeAccepted += len ;
2182 host->gArtsSizeAccepted += len ;
2183 procArtsSizeAccepted += len ;
2184
2185 /* host has two references to the article here... the parameter `article'
2186 and the queue */
2187
2188 delArticle (article) ; /* drop the parameter reference */
2189
2190 if (!amClosing (host))
2191 articleGone (host,cxn,article) ; /* and the one in the queue */
2192 }
2193
2194
2195
2196
2197
2198
2199
2200 /*
2201 * remote said no thanks to an article.
2202 */
hostArticleNotWanted(Host host,Connection cxn,Article article)2203 void hostArticleNotWanted (Host host, Connection cxn, Article article)
2204 {
2205 const char *filename = artFileName (article) ;
2206 const char *msgid = artMsgId (article) ;
2207
2208 d_printf (5,"Article %s (%s) was not wanted\n", msgid, filename) ;
2209
2210 host->artsNotWanted++ ;
2211 host->gArtsNotWanted++ ;
2212 procArtsNotWanted++ ;
2213
2214
2215 /* host has two references to the article here... `article' and the
2216 queue */
2217
2218 delArticle (article) ; /* drop the `article' reference */
2219
2220 if (!amClosing (host))
2221 articleGone (host,cxn,article) ; /* and the one in the queue */
2222 }
2223
2224
2225
2226
2227
2228
2229
2230 /*
2231 * remote rejected the article after it was was transferred
2232 */
hostArticleRejected(Host host,Connection cxn,Article article)2233 void hostArticleRejected (Host host, Connection cxn, Article article)
2234 {
2235 const char *filename = artFileName (article) ;
2236 const char *msgid = artMsgId (article) ;
2237 double len = artSize (article);
2238
2239 d_printf (5,"Article %s (%s) was rejected\n", msgid, filename) ;
2240
2241 host->artsRejected++ ;
2242 host->gArtsRejected++ ;
2243 procArtsRejected++ ;
2244 host->artsSizeRejected += len ;
2245 host->gArtsSizeRejected += len ;
2246 procArtsSizeRejected += len ;
2247
2248 /* host has two references to the article here... `article' and the queue */
2249
2250 delArticle (article) ; /* drop the `article' reference */
2251
2252 if (!amClosing (host))
2253 articleGone (host,cxn,article) ;
2254 }
2255
2256
2257
2258
2259
2260
2261
2262 /*
2263 * The remote wants us to retry the article later.
2264 */
hostArticleDeferred(Host host,Connection cxn,Article article)2265 void hostArticleDeferred (Host host, Connection cxn, Article article)
2266 {
2267 host->artsDeferred++ ;
2268 host->gArtsDeferred++ ;
2269 procArtsDeferred++ ;
2270
2271
2272 if (!amClosing (host))
2273 {
2274 Article extraRef ;
2275 int deferTimeout = 5 ; /* XXX - should be tunable */
2276 time_t now = theTime() ;
2277
2278 extraRef = artTakeRef (article) ; /* hold a reference until requeued */
2279 articleGone (host,cxn,article) ; /* drop from the queue */
2280
2281 if (host->deferred == NULL)
2282 {
2283 if (host->deferredId != 0)
2284 clearTimer (host->deferredId) ;
2285 host->deferredId = prepareSleep (hostDeferredArtCbk, deferTimeout,
2286 host) ;
2287 }
2288
2289 queueArticle (article,&host->deferred,&host->deferredTail,
2290 now + deferTimeout) ;
2291 host->deferLen++ ;
2292 backlogToTape (host) ;
2293 delArticle (extraRef) ;
2294 }
2295 else
2296 delArticle(article); /*drop parameter reference if not sent to tape*/
2297 }
2298
2299
2300
2301
2302
2303
2304
2305 /*
2306 * The Connection is giving the article back to the Host, but it doesn't
2307 * want a new one in return.
2308 */
hostTakeBackArticle(Host host,Connection cxn UNUSED,Article article)2309 void hostTakeBackArticle (Host host, Connection cxn UNUSED, Article article)
2310 {
2311 if (!amClosing (host))
2312 {
2313 Article extraRef ;
2314
2315 host->artsCxnDrop++ ;
2316 host->gArtsCxnDrop++ ;
2317 extraRef = artTakeRef (article) ; /* hold a reference until requeued */
2318 articleGone (host,NULL,article) ; /* drop from the queue */
2319 host->notThisCxn = cxn;
2320 hostSendArticle (host, article) ; /* requeue it */
2321 host->notThisCxn = NULL;
2322 delArticle (extraRef) ;
2323 }
2324 else
2325 delArticle(article); /*drop parameter reference if not sent to tape*/
2326
2327 }
2328
2329
2330
2331
2332
2333
2334
2335 /*
2336 * The disk file for the article is no longer valid
2337 */
hostArticleIsMissing(Host host,Connection cxn,Article article)2338 void hostArticleIsMissing (Host host, Connection cxn, Article article)
2339 {
2340 const char *filename = artFileName (article) ;
2341 const char *msgid = artMsgId (article) ;
2342
2343 d_printf (5, "%s article is missing %s %s\n", host->params->peerName, msgid, filename) ;
2344
2345 host->artsMissing++ ;
2346 host->gArtsMissing++ ;
2347 procArtsMissing++ ;
2348
2349 /* host has two references to the article here... `article' and the
2350 queue */
2351
2352 delArticle (article) ; /* drop the `article' reference */
2353
2354 if (!amClosing (host))
2355 articleGone (host,cxn,article) ; /* and the one in the queue */
2356 }
2357
2358
2359
2360
2361
2362
2363
2364 /* The Connection wants something to do. This is called by the Connection
2365 * after it has transferred an article. This is what keeps the pipes full
2366 * of data off the tapes if the input from inn is idle.
2367 */
hostGimmeArticle(Host host,Connection cxn)2368 bool hostGimmeArticle (Host host, Connection cxn)
2369 {
2370 Article article = NULL ;
2371 bool gaveSomething = false ;
2372 size_t amtToGive = cxnQueueSpace (cxn) ; /* may be more than one */
2373 int feed = 0 ;
2374
2375 if (amClosing (host))
2376 {
2377 d_printf (5,"%s no article to give due to closing\n",host->params->peerName) ;
2378
2379 return false ;
2380 }
2381
2382 if (amtToGive == 0)
2383 d_printf (5,"%s Queue space is zero....\n",host->params->peerName) ;
2384
2385 while (amtToGive > 0)
2386 {
2387 bool tookIt ;
2388 unsigned int queue = host->params->maxChecks - amtToGive ;
2389
2390 if (host->params->backlogFeedFirst) {
2391 if ((article = getArticle (host->myTape)) != NULL)
2392 feed = 2;
2393 else if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
2394 feed = 1;
2395 else
2396 feed = 3;
2397 }
2398 else {
2399 if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
2400 feed = 1;
2401 else if ((article = getArticle (host->myTape)) != NULL)
2402 feed = 2;
2403 else
2404 feed = 3;
2405 }
2406
2407 switch (feed) {
2408 case 1:
2409 host->backlog-- ;
2410 tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
2411
2412 ASSERT (tookIt == true) ;
2413
2414 if (queue == 0) host->gNoQueue++ ;
2415 else host->gCxnQueue += queue ;
2416
2417 queueArticle (article,&host->processed,&host->processedTail, 0) ;
2418 amtToGive-- ;
2419
2420 gaveSomething = true ;
2421 break ;
2422
2423 case 2:
2424 /* go to the tapes */
2425 tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
2426
2427 ASSERT (tookIt == true) ;
2428
2429 if (queue == 0) host->gNoQueue++ ;
2430 else host->gCxnQueue += queue ;
2431
2432 host->artsFromTape++ ;
2433 host->gArtsFromTape++ ;
2434 procArtsFromTape++ ;
2435 queueArticle (article,&host->processed,&host->processedTail, 0) ;
2436 amtToGive-- ;
2437
2438 gaveSomething = true ;
2439
2440 break ;
2441
2442 case 3:
2443 /* we had nothing left to give... */
2444
2445 if (host->processed == NULL) /* and if nothing outstanding... */
2446 listenerHostIsIdle (host->listener,host) ; /* tell our owner */
2447
2448 amtToGive = 0 ;
2449
2450 break ;
2451 }
2452 }
2453
2454 return gaveSomething ;
2455 }
2456
2457
2458
2459
2460
2461
2462
2463 /*
2464 * get the name that INN uses for this host
2465 */
hostPeerName(Host host)2466 const char *hostPeerName (Host host)
2467 {
2468 ASSERT (host != NULL) ;
2469
2470 return host->params->peerName ;
2471 }
2472
2473 /*
2474 * Get the IPv4 bindAddr.
2475 */
hostBindAddr(Host host)2476 const char *hostBindAddr (Host host)
2477 {
2478 ASSERT (host != NULL) ;
2479
2480 return host->params->bindAddr ;
2481 }
2482
2483 /*
2484 * Get the IPv6 bindAddr6.
2485 */
hostBindAddr6(Host host)2486 const char *hostBindAddr6 (Host host)
2487 {
2488 ASSERT (host != NULL) ;
2489
2490 return host->params->bindAddr6 ;
2491 }
2492
2493 /*
2494 * get the username and password for authentication
2495 */
hostUsername(Host host)2496 const char *hostUsername (Host host)
2497 {
2498 ASSERT (host != NULL) ;
2499
2500 return host->params->username ;
2501 }
hostPassword(Host host)2502 const char *hostPassword (Host host)
2503 {
2504 ASSERT (host != NULL) ;
2505
2506 return host->params->password ;
2507 }
2508
2509
2510 /* return true if the Connections for this host should attempt to do
2511 streaming. */
hostWantsStreaming(Host host)2512 bool hostWantsStreaming (Host host)
2513 {
2514 return host->params->wantStreaming ;
2515 }
2516
hostMaxChecks(Host host)2517 unsigned int hostMaxChecks (Host host)
2518 {
2519 return host->params->maxChecks ;
2520 }
2521
hostDropDeferred(Host host)2522 bool hostDropDeferred (Host host)
2523 {
2524 return host->params->dropDeferred ;
2525 }
2526
2527
2528
2529
2530
2531
2532
2533 /**********************************************************************/
2534 /** CLASS FUNCTIONS **/
2535 /**********************************************************************/
2536
2537 /*
2538 * Set the state of whether each Connection is told to log its stats when
2539 * its controlling Host logs its stats.
2540 */
hostLogConnectionStats(bool val)2541 void hostLogConnectionStats (bool val)
2542 {
2543 logConnectionStats = val ;
2544 }
2545
2546
hostLogConnectionStatsP(void)2547 bool hostLogConnectionStatsP (void)
2548 {
2549 return logConnectionStats ;
2550 }
2551
2552
2553
2554 /*
2555 * Called by one of the Host's Connection's when it (the Connection)
2556 * switches into or out of no-CHECK mode.
2557 */
hostLogNoCheckMode(Host host,bool on,double low,double cur,double high)2558 void hostLogNoCheckMode (Host host, bool on, double low, double cur, double high)
2559 {
2560 if (on && host->loggedModeOn == false)
2561 {
2562 notice ("%s mode no-CHECK entered [%.2f,%.2f,%.2f]",
2563 host->params->peerName, low, cur, high) ;
2564 host->loggedModeOn = true ;
2565 }
2566 else if (!on && host->loggedModeOff == false)
2567 {
2568 notice ("%s mode no-CHECK exited [%.2f,%.2f,%.2f]",
2569 host->params->peerName, low, cur, high) ;
2570 host->loggedModeOff = true ;
2571 }
2572 }
2573
2574
2575
hostSetStatusFile(const char * filename)2576 void hostSetStatusFile (const char *filename)
2577 {
2578 FILE *fp ;
2579
2580 if (filename == NULL)
2581 die ("Can't set status file name with a NULL filename\n") ;
2582 else if (*filename == '\0')
2583 die ("Can't set status file name with an empty string\n") ;
2584
2585 /* statusFile may already be initialized (several status-file: lines,
2586 * reload of the config file, shutdown process). */
2587 free(statusFile);
2588
2589 if (*filename == '/')
2590 statusFile = xstrdup (filename) ;
2591 else {
2592 if (genHtml)
2593 statusFile = concatpath (innconf->pathhttp,filename) ;
2594 else
2595 statusFile = concatpath (innconf->pathlog,filename) ;
2596 }
2597
2598 if ((fp = fopen (statusFile,"w")) == NULL)
2599 {
2600 syslog (LOG_ERR,"Status file is not a valid pathname: %s",
2601 statusFile) ;
2602 free (statusFile) ;
2603 statusFile = NULL ;
2604 }
2605 else
2606 fclose (fp) ;
2607 }
2608
gHostStats(void)2609 void gHostStats (void)
2610 {
2611 Host h ;
2612 time_t now = theTime() ;
2613 char msgstr[SMBUF] ;
2614
2615 for (h = gHostList ; h != NULL ; h = h->next)
2616 if (h->firstConnectTime > 0) {
2617 snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
2618 h->gArtsSizeAccepted, h->gArtsSizeRejected);
2619 notice ("%s global seconds %ld offered %d accepted %d refused %d"
2620 " rejected %d missing %d %s spooled %d unspooled %d",
2621 h->params->peerName,
2622 (long) (now - h->firstConnectTime),
2623 h->gArtsOffered, h->gArtsAccepted,
2624 h->gArtsNotWanted, h->gArtsRejected,
2625 h->gArtsMissing, msgstr,
2626 h->gArtsToTape, h->gArtsFromTape) ;
2627 }
2628 }
2629
2630
2631
2632 /**********************************************************************/
2633 /** PRIVATE FUNCTIONS **/
2634 /**********************************************************************/
2635
2636
2637
2638
2639 #define INHERIT 1
2640 #define NO_INHERIT 0
2641
2642
hostDetails(scope * s,char * name,bool isDefault,FILE * fp)2643 static HostParams hostDetails (scope *s,
2644 char *name,
2645 bool isDefault,
2646 FILE *fp)
2647 {
2648 long iv ;
2649 int bv, vival, inherit ;
2650 HostParams p;
2651 char * q;
2652 double rv, l, h ;
2653 value * v;
2654
2655 p=newHostParams(isDefault?NULL:defaultParams);
2656
2657 if (isDefault)
2658 {
2659 ASSERT (name==NULL);
2660 }
2661 else
2662 {
2663 if (name)
2664 {
2665 p->peerName=xstrdup(name);
2666 }
2667
2668 if (s != NULL)
2669 {
2670 if (getString (s,IP_NAME,&q,NO_INHERIT))
2671 p->ipName = q ;
2672 else
2673 p->ipName = xstrdup (name) ;
2674 }
2675
2676 if (getString (s,"username",&q,NO_INHERIT))
2677 p->username = q;
2678 if (getString (s,"password",&q,NO_INHERIT))
2679 p->password = q;
2680
2681 if (p->username != NULL && p->password == NULL)
2682 logOrPrint (LOG_ERR,fp,"cannot find password for %s",p->peerName);
2683 if (p->username == NULL && p->password != NULL)
2684 logOrPrint (LOG_ERR,fp,"cannot find username for %s",p->peerName);
2685
2686 }
2687
2688 if (getString(s,"bindaddress",&q,isDefault?NO_INHERIT:INHERIT))
2689 {
2690 if (p->bindAddr)
2691 free(p->bindAddr);
2692 p->bindAddr = q;
2693 }
2694 if (getString(s,"bindaddress6",&q,isDefault?NO_INHERIT:INHERIT))
2695 {
2696 if (p->bindAddr6)
2697 free(p->bindAddr6);
2698 p->bindAddr6 = q;
2699 }
2700 if (p->bindAddr && strcmp(p->bindAddr, "none") == 0 &&
2701 p->bindAddr6 && strcmp(p->bindAddr6, "none") == 0)
2702 {
2703 logOrPrint (LOG_ERR,fp,"cannot set both bindaddress and bindaddress6"
2704 " to \"none\" -- ignoring them for %s",p->peerName);
2705 free(p->bindAddr);
2706 free(p->bindAddr6);
2707 p->bindAddr = NULL;
2708 p->bindAddr6 = NULL;
2709 }
2710
2711 /* check required global defaults are there and have good values */
2712
2713
2714 #define GETINT(sc,f,n,min,max,req,val,inh) \
2715 vival = validateInteger(f,n,min,max,req,val,sc,inh); \
2716 if (isDefault) do{ \
2717 if(vival==VALUE_WRONG_TYPE) \
2718 { \
2719 logOrPrint(LOG_CRIT,fp,"cannot continue"); \
2720 exit(1); \
2721 } \
2722 else if(vival != VALUE_OK) \
2723 val = 0; \
2724 } while(0); \
2725 iv = 0 ; \
2726 getInteger (sc,n,&iv,inh) ; \
2727 val = (unsigned int) iv ;
2728
2729 #define GETREAL(sc,f,n,min,max,req,val,inh) \
2730 vival = validateReal(f,n,min,max,req,val,sc,inh); \
2731 if (isDefault) do{ \
2732 if(vival==VALUE_WRONG_TYPE) \
2733 { \
2734 logOrPrint(LOG_CRIT,fp,"cannot continue"); \
2735 exit(1); \
2736 } \
2737 else if(vival != VALUE_OK) \
2738 rv = 0; \
2739 } while(0); \
2740 rv = 0 ; \
2741 getReal (sc,n,&rv,inh) ; \
2742 val = rv ;
2743
2744 #define GETBOOL(sc,f,n,req,val,inh) \
2745 vival = validateBool(f,n,req,val,sc,inh); \
2746 if (isDefault) do{ \
2747 if(vival==VALUE_WRONG_TYPE) \
2748 { \
2749 logOrPrint(LOG_CRIT,fp,"cannot continue"); \
2750 exit(1); \
2751 } \
2752 else if(vival != VALUE_OK) \
2753 bv = 0; \
2754 } while(0); \
2755 bv = 0 ; \
2756 getBool (sc,n,&bv,inh) ; \
2757 val = (bv ? true : false);
2758
2759 inherit = isDefault?NO_INHERIT:INHERIT;
2760 GETINT(s,fp,"article-timeout",0,LONG_MAX,NOTREQ,p->articleTimeout, inherit);
2761 GETINT(s,fp,"response-timeout",0,LONG_MAX,NOTREQ,p->responseTimeout, inherit);
2762 GETINT(s,fp,"close-period",0,LONG_MAX,NOTREQ,p->closePeriod, inherit);
2763 GETINT(s,fp,"initial-connections",0,LONG_MAX,NOTREQ,p->initialConnections, inherit);
2764 GETINT(s,fp,"max-connections",0,LONG_MAX,NOTREQ,p->absMaxConnections, inherit);
2765 GETINT(s,fp,"max-queue-size",1,LONG_MAX,NOTREQ,p->maxChecks, inherit);
2766 GETBOOL(s,fp,"streaming",NOTREQ,p->wantStreaming, inherit);
2767 GETBOOL(s,fp,"drop-deferred",NOTREQ,p->dropDeferred, inherit);
2768 GETBOOL(s,fp,"min-queue-connection",NOTREQ,p->minQueueCxn, inherit);
2769 GETREAL(s,fp,"no-check-high",0.0,100.0,NOTREQ,p->lowPassHigh, inherit);
2770 GETREAL(s,fp,"no-check-low",0.0,100.0,NOTREQ,p->lowPassLow, inherit);
2771 GETREAL(s,fp,"no-check-filter",0.1,DBL_MAX,NOTREQ,p->lowPassFilter, inherit);
2772 GETINT(s,fp,"port-number",0,LONG_MAX,NOTREQ,p->portNum, inherit);
2773 GETINT(s,fp,"backlog-limit",0,LONG_MAX,NOTREQ,p->backlogLimit, inherit);
2774
2775 GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
2776 if (p->forceIPv4)
2777 {
2778 if (p->bindAddr && strcmp(p->bindAddr, "none") == 0)
2779 {
2780 free(p->bindAddr);
2781 p->bindAddr = NULL;
2782 }
2783 if (p->bindAddr6)
2784 {
2785 free(p->bindAddr6);
2786 }
2787 /* Force bindaddress6: to "none". */
2788 p->bindAddr6 = xstrdup("none");
2789 }
2790
2791 if (findValue (s,"backlog-factor",inherit) == NULL &&
2792 findValue (s,"backlog-limit-highwater",inherit) == NULL)
2793 {
2794 /* This is not an error. A default value will be used.
2795 *
2796 * logOrPrint (LOG_ERR,fp,
2797 "ME config: must define at least one of backlog-factor"
2798 " and backlog-limit-highwater. Adding %s: %f", "backlog-factor",
2799 LIMIT_FUDGE) ;
2800 */
2801 addReal (s,"backlog-factor",LIMIT_FUDGE) ;
2802 rv = 0 ;
2803 }
2804
2805 GETBOOL(s,fp,"backlog-feed-first",NOTREQ,p->backlogFeedFirst, inherit);
2806
2807 /* Innfeed should emit a warning if backlog-feed-first is set
2808 to "true" for any peer that doesn't have max-connections and
2809 initial-connections both set to "1" */
2810 if ((p->backlogFeedFirst)
2811 && ((p->initialConnections <= 1) || (p->absMaxConnections != 1)))
2812 {
2813 if (p->peerName != NULL)
2814 logOrPrint (LOG_WARNING,fp,
2815 "ME config: innfeed will make more than one connection"
2816 " to peer %s, but backlog-feed-first is set", p->peerName);
2817 else
2818 logOrPrint (LOG_WARNING,fp,
2819 "ME config: innfeed will make more than one connection"
2820 " to peer, but backlog-feed-first is set");
2821 }
2822
2823 GETINT(s,fp,"backlog-limit-highwater",0,LONG_MAX,NOTREQNOADD,p->backlogLimitHigh, inherit);
2824 GETREAL(s,fp,"backlog-factor",1.0,DBL_MAX,NOTREQNOADD,p->backlogFactor, inherit);
2825
2826 GETINT(s,fp,"dynamic-method",0,3,NOTREQ,p->dynamicMethod, inherit);
2827 GETREAL(s,fp,"dynamic-backlog-filter",0.0,DBL_MAX,NOTREQ,p->dynBacklogFilter, inherit);
2828 GETREAL(s,fp,"dynamic-backlog-low",0.0,100.0,NOTREQ,p->dynBacklogLowWaterMark, inherit);
2829 GETREAL(s,fp,"dynamic-backlog-high",0.0,100.0,NOTREQ,p->dynBacklogHighWaterMark, inherit);
2830
2831 l=p->lowPassLow;
2832 h=p->lowPassHigh;
2833 if (l > h)
2834 {
2835 logOrPrint (LOG_ERR,fp,
2836 "ME config: no-check-low value greater than no-check-high"
2837 " (%f vs %f). Setting to %f and %f", l, h, NOCHECKLOW,
2838 NOCHECKHIGH) ;
2839 rv = 0 ;
2840 v = findValue (s,"no-check-low",NO_INHERIT) ;
2841 v->v.real_val = p->lowPassLow = NOCHECKLOW ;
2842 v = findValue (s,"no-check-high",NO_INHERIT) ;
2843 v->v.real_val = p->lowPassHigh = NOCHECKHIGH ;
2844 }
2845 else if (h - l < 5.0)
2846 logOrPrint (LOG_WARNING,fp,
2847 "ME config: no-check-low and no-check-high are close"
2848 " together (%f vs %f)",l,h) ;
2849
2850 return p;
2851 }
2852
2853
2854
2855
getHostInfo(void)2856 static HostParams getHostInfo (void)
2857 {
2858 static int idx = 0 ;
2859 value *v ;
2860 scope *s ;
2861 HostParams p=NULL;
2862
2863 if (topScope == NULL)
2864 return p;
2865
2866 while ((v = getNextPeer (&idx)) != NULL)
2867 {
2868 if (!ISPEER (v))
2869 continue ;
2870
2871 s = v->v.scope_val ;
2872
2873 p=hostDetails(s,v->name,false,NULL);
2874
2875 break ;
2876 }
2877
2878 if (v == NULL)
2879 idx = 0 ; /* start over next time around */
2880
2881 return p;
2882 }
2883
2884
2885 /*
2886 * fully delete and clean up the Host object.
2887 */
delHost(Host host)2888 void delHost (Host host)
2889 {
2890 Host h,q ;
2891
2892 for (h = gHostList, q = NULL ; h != NULL ; q = h, h = h->next)
2893 if (h == host)
2894 {
2895 if (gHostList == h)
2896 gHostList = gHostList->next ;
2897 else
2898 q->next = h->next ;
2899 break ;
2900 }
2901
2902 ASSERT (h != NULL) ;
2903
2904 delTape (host->myTape) ;
2905
2906 free (host->connections) ;
2907 free (host->cxnActive) ;
2908 free (host->cxnSleeping) ;
2909 free (host->params->peerName) ;
2910 free (host->params->ipName) ;
2911
2912 if (host->ipAddrs)
2913 {
2914 if(host->ipAddrs[0])
2915 free (host->ipAddrs[0]);
2916 free (host->ipAddrs) ;
2917 }
2918
2919 free (host) ;
2920 gHostCount-- ;
2921 }
2922
2923
2924
findHostByName(char * name)2925 static Host findHostByName (char *name)
2926 {
2927 Host h;
2928
2929 for (h = gHostList; h != NULL; h = h->next)
2930 if ( strcmp(h->params->peerName, name) == 0 )
2931 return h;
2932
2933 return NULL;
2934 }
2935
2936
2937
2938 /*
2939 * the article can be dropped from the process queue and the connection can
2940 * take a new article if there are any to be had.
2941 */
articleGone(Host host,Connection cxn,Article article)2942 static void articleGone (Host host, Connection cxn, Article article)
2943 {
2944 if ( !remArticle (article,&host->processed,&host->processedTail) )
2945 die ("remArticle in articleGone failed") ;
2946
2947 delArticle (article) ;
2948
2949 if (cxn != NULL)
2950 hostGimmeArticle (host,cxn) ; /* may not give anything over */
2951 }
2952
2953
2954
2955
2956
2957
2958
2959 /*
2960 * One of the Connections for this Host has reestablished itself, so stop
2961 * spooling article info to disk.
2962 */
hostStopSpooling(Host host)2963 static void hostStopSpooling (Host host)
2964 {
2965 ASSERT (host->spoolTime != 0) ;
2966
2967 clearTimer (host->statsId) ;
2968 hostLogStats (host,true) ;
2969
2970 host->spoolTime = 0 ;
2971 }
2972
2973
2974
2975
2976
2977
2978
2979 /*
2980 * No connections are active and we're getting response 201 or 400 (or some
2981 * such) so that we need to start spooling article info to disk.
2982 */
hostStartSpooling(Host host)2983 static void hostStartSpooling (Host host)
2984 {
2985 ASSERT (host->spoolTime == 0) ;
2986
2987 queuesToTape (host) ;
2988
2989 hostLogStats (host,true) ;
2990
2991 host->spoolTime = theTime() ;
2992 host->spoolTime_checkpoint = host->spoolTime ;
2993
2994 if (host->firstConnectTime == 0)
2995 host->firstConnectTime = host->spoolTime ;
2996
2997 /* don't want to log too frequently */
2998 if (SPOOL_LOG_PERIOD > 0 &&
2999 (host->spoolTime - host->lastSpoolTime) > SPOOL_LOG_PERIOD)
3000 {
3001 notice ("%s spooling no active connections", host->params->peerName) ;
3002 host->lastSpoolTime = host->spoolTime ;
3003 }
3004
3005 host->connectTime = 0 ;
3006
3007 host->notifiedChangedRemBlckd = false ;
3008
3009 clearTimer (host->statsId) ;
3010 host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
3011 }
3012
3013
3014
3015
3016
3017
3018
3019 /*
3020 * Time to log the statistics for the Host. If FINAL is true then the
3021 * counters will be reset.
3022 */
hostLogStats(Host host,bool final)3023 static void hostLogStats (Host host, bool final)
3024 {
3025 time_t now = theTime() ;
3026 time_t *startPeriod ;
3027 double cnt = (host->blCount) ? (host->blCount) : 1.0;
3028
3029 if (host->spoolTime == 0 && host->connectTime == 0)
3030 return ; /* host has never connected and never started spooling. */
3031
3032 startPeriod = (host->spoolTime != 0 ? &host->spoolTime : &host->connectTime);
3033
3034 if (now - *startPeriod >= statsResetPeriod)
3035 final = true ;
3036
3037 if (host->spoolTime != 0) {
3038 /* Log a checkpoint in any case. */
3039 notice("%s checkpoint seconds %ld spooled %d on_close %d sleeping %d",
3040 host->params->peerName,
3041 (long) (now - host->spoolTime_checkpoint),
3042 host->artsToTape - host->artsToTape_checkpoint,
3043 host->artsHostClose - host->artsHostClose_checkpoint,
3044 host->artsHostSleep - host->artsHostSleep_checkpoint);
3045
3046 host->spoolTime_checkpoint = now;
3047 host->artsToTape_checkpoint = host->artsToTape;
3048 host->artsHostClose_checkpoint = host->artsHostClose;
3049 host->artsHostSleep_checkpoint = host->artsHostSleep;
3050
3051 if (final) {
3052 notice("%s final seconds %ld spooled %d on_close %d sleeping %d",
3053 host->params->peerName,
3054 (long) (now - host->spoolTime), host->artsToTape,
3055 host->artsHostClose, host->artsHostSleep);
3056 }
3057 } else {
3058 /* Log a checkpoint in any case.
3059 *
3060 * Note that deferred and queue values are cumulative
3061 * (and not treated by innreport). */
3062 notice("%s checkpoint seconds %ld offered %d accepted %d refused %d rejected %d"
3063 " missing %d accsize %.0f rejsize %.0f spooled %d on_close %d unspooled %d"
3064 " deferred %d/%.1f requeued %d"
3065 " queue %.1f/%d:%.0f,%.0f,%.0f,%.0f,%.0f,%.0f",
3066 host->params->peerName,
3067 (long) (now - host->connectTime_checkpoint),
3068 host->artsOffered - host->artsOffered_checkpoint,
3069 host->artsAccepted - host->artsAccepted_checkpoint,
3070 host->artsNotWanted - host->artsNotWanted_checkpoint,
3071 host->artsRejected - host->artsRejected_checkpoint,
3072 host->artsMissing - host->artsMissing_checkpoint,
3073 host->artsSizeAccepted - host->artsSizeAccepted_checkpoint,
3074 host->artsSizeRejected - host->artsSizeRejected_checkpoint,
3075 host->artsToTape - host->artsToTape_checkpoint,
3076 host->artsHostClose - host->artsHostClose_checkpoint,
3077 host->artsFromTape - host->artsFromTape_checkpoint,
3078 host->artsDeferred - host->artsDeferred_checkpoint,
3079 (double)host->dlAccum/cnt,
3080 host->artsCxnDrop - host->artsCxnDrop_checkpoint,
3081 (double)host->blAccum/cnt,
3082 hostHighwater,
3083 (100.0*host->blNone)/cnt,
3084 (100.0*host->blQuartile[0])/cnt,
3085 (100.0*host->blQuartile[1])/cnt,
3086 (100.0*host->blQuartile[2])/cnt,
3087 (100.0*host->blQuartile[3])/cnt,
3088 (100.0*host->blFull)/cnt);
3089
3090 host->connectTime_checkpoint = now;
3091 host->artsOffered_checkpoint = host->artsOffered;
3092 host->artsAccepted_checkpoint = host->artsAccepted;
3093 host->artsNotWanted_checkpoint = host->artsNotWanted;
3094 host->artsRejected_checkpoint = host->artsRejected;
3095 host->artsMissing_checkpoint = host->artsMissing;
3096 host->artsSizeAccepted_checkpoint = host->artsSizeAccepted;
3097 host->artsSizeRejected_checkpoint = host->artsSizeRejected;
3098 host->artsToTape_checkpoint = host->artsToTape;
3099 host->artsHostClose_checkpoint = host->artsHostClose;
3100 host->artsFromTape_checkpoint = host->artsFromTape;
3101 host->artsDeferred_checkpoint = host->artsDeferred;
3102 host->artsCxnDrop_checkpoint = host->artsCxnDrop;
3103
3104 if (final) {
3105 notice("%s final seconds %ld offered %d accepted %d refused %d rejected %d"
3106 " missing %d accsize %.0f rejsize %.0f spooled %d on_close %d unspooled %d"
3107 " deferred %d/%.1f requeued %d"
3108 " queue %.1f/%d:%.0f,%.0f,%.0f,%.0f,%.0f,%.0f",
3109 host->params->peerName,
3110 (long) (now - host->connectTime),
3111 host->artsOffered, host->artsAccepted,
3112 host->artsNotWanted, host->artsRejected,
3113 host->artsMissing, host->artsSizeAccepted, host->artsSizeRejected,
3114 host->artsToTape,
3115 host->artsHostClose, host->artsFromTape,
3116 host->artsDeferred, (double)host->dlAccum/cnt,
3117 host->artsCxnDrop,
3118 (double)host->blAccum/cnt, hostHighwater,
3119 (100.0*host->blNone)/cnt,
3120 (100.0*host->blQuartile[0])/cnt, (100.0*host->blQuartile[1])/cnt,
3121 (100.0*host->blQuartile[2])/cnt, (100.0*host->blQuartile[3])/cnt,
3122 (100.0*host->blFull)/cnt);
3123 }
3124 }
3125
3126 if (logConnectionStats)
3127 {
3128 unsigned int i ;
3129
3130 for (i = 0 ; i < host->maxConnections ; i++)
3131 if (host->connections [i] != NULL && host->cxnActive [i])
3132 cxnLogStats (host->connections [i],final) ;
3133 }
3134
3135 /* one 'spooling backlog' message per stats logging period */
3136 host->loggedBacklog = false ;
3137 host->loggedModeOn = host->loggedModeOff = false ;
3138
3139 if (final)
3140 {
3141 /* We also reset checkpoints because the same host structure
3142 * may be used again. */
3143 host->artsOffered = 0 ;
3144 host->artsOffered_checkpoint = 0 ;
3145 host->artsAccepted = 0 ;
3146 host->artsAccepted_checkpoint = 0 ;
3147 host->artsNotWanted = 0 ;
3148 host->artsNotWanted_checkpoint = 0 ;
3149 host->artsRejected = 0 ;
3150 host->artsRejected_checkpoint = 0 ;
3151 host->artsDeferred = 0 ;
3152 host->artsDeferred_checkpoint = 0 ;
3153 host->artsMissing = 0 ;
3154 host->artsMissing_checkpoint = 0 ;
3155 host->artsToTape = 0 ;
3156 host->artsToTape_checkpoint = 0 ;
3157 host->artsQueueOverflow = 0 ;
3158 host->artsCxnDrop = 0 ;
3159 host->artsCxnDrop_checkpoint = 0 ;
3160 host->artsHostSleep = 0 ;
3161 host->artsHostSleep_checkpoint = 0 ;
3162 host->artsHostClose = 0 ;
3163 host->artsHostClose_checkpoint = 0 ;
3164 host->artsFromTape = 0 ;
3165 host->artsFromTape_checkpoint = 0 ;
3166 host->artsSizeAccepted = 0 ;
3167 host->artsSizeAccepted_checkpoint = 0 ;
3168 host->artsSizeRejected = 0 ;
3169 host->artsSizeRejected_checkpoint = 0 ;
3170
3171 *startPeriod = theTime () ; /* in of case STATS_RESET_PERIOD */
3172 }
3173
3174 /* Reset these each log period. */
3175 host->blNone = 0 ;
3176 host->blFull = 0 ;
3177 host->blQuartile[0] = host->blQuartile[1] = host->blQuartile[2] =
3178 host->blQuartile[3] = 0;
3179 host->dlAccum = 0;
3180 host->blAccum = 0;
3181 host->blCount = 0;
3182
3183 #if 0
3184 /* XXX turn this section on to get a snapshot at each log period. */
3185 if (gPrintInfo != NULL)
3186 gPrintInfo () ;
3187 #endif
3188 }
3189
3190
3191
3192
3193
3194
3195
3196
3197 static double
convsize(double size,char ** tsize)3198 convsize(double size, char **tsize)
3199 {
3200 double dsize;
3201 static char tTB[]="TB";
3202 static char tGB[]="GB";
3203 static char tMB[]="MB";
3204 static char tKB[]="KB";
3205 static char tB []="B";
3206
3207 if (size/((double)1024*1024*1024*1000)>=1.) {
3208 dsize=size/((double)1024*1024*1024*1024);
3209 *tsize=tTB;
3210 } else if (size/(1024*1024*1000)>=1.) {
3211 dsize=size/(1024*1024*1024);
3212 *tsize=tGB;
3213 } else if (size/(1024*1000)>=1.) {
3214 dsize=size/(1024*1024);
3215 *tsize=tMB;
3216 } else if (size/1000>=1.) {
3217 dsize=size/1024;
3218 *tsize=tKB;
3219 } else {
3220 dsize=size;
3221 *tsize=tB;
3222 }
3223 return dsize;
3224 }
3225
3226
3227 /*
3228 * Log the status of the Hosts.
3229 */
hostLogStatus(void)3230 static void hostLogStatus (void)
3231 {
3232 FILE *fp = NULL ;
3233 Host h ;
3234 bool anyToLog = false ;
3235 unsigned int peerNum = 0, actConn = 0, slpConn = 0, maxcon = 0 ;
3236 static bool logged = false ;
3237 static bool flogged = false ;
3238
3239 if (statusFile == NULL && !logged)
3240 {
3241 syslog (LOG_ERR,"No status file to write to") ;
3242 logged = true ;
3243 return ;
3244 }
3245
3246 logged = false ;
3247
3248 for (h = gHostList ; h != NULL ; h = h->next)
3249 if (h->myTape != NULL) /* the host deletes its tape when it's closing */
3250 {
3251 anyToLog = true ;
3252 peerNum++ ;
3253 actConn += h->activeCxns ;
3254 slpConn += h->sleepingCxns ;
3255 maxcon += h->maxConnections ;
3256 }
3257
3258 if (!anyToLog)
3259 return ;
3260
3261 lastStatusLog = theTime() ;
3262
3263 TMRstart(TMR_STATUSFILE);
3264 if ((fp = fopen (statusFile,"w")) == NULL)
3265 {
3266 if ( !flogged )
3267 syswarn ("ME oserr status file open: %s", statusFile) ;
3268 flogged = true ;
3269 }
3270 else
3271 {
3272 char timeString [30] ;
3273 time_t now ;
3274 long sec ;
3275 long offered ;
3276 double size, totalsize;
3277 char *tsize;
3278
3279 flogged = false ;
3280
3281 now = time (NULL) ;
3282 sec = (long) (now - start) ;
3283 timeToString (now, timeString, sizeof (timeString)) ;
3284
3285 if (genHtml)
3286 {
3287 fprintf (fp, "<HTML>\n"
3288 "<HEAD>\n"
3289 "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"300;\">\n"
3290 "</HEAD>\n"
3291 "<BODY>\n") ;
3292 fprintf (fp, "\n");
3293 fprintf (fp, "<PRE>\n");
3294 }
3295
3296 fprintf (fp,"innfeed from %s\npid %d started %s\n\nUpdated: %s\n",
3297 INN_VERSION_STRING,(int) myPid,startTime,timeString) ;
3298 fprintf (fp,"Stats period: %-5ld Stats reset: %ld\n",
3299 (long) statsPeriod, (long) statsResetPeriod);
3300 fprintf (fp,"(peers: %u active-cxns: %u sleeping-cxns: %u idle-cxns: %u)\n\n",
3301 peerNum, actConn, slpConn,(maxcon - (actConn + slpConn))) ;
3302
3303 fprintf (fp,"Configuration file: %s\n\n",configFile) ;
3304
3305 if (genHtml)
3306 {
3307 fprintf (fp, "</PRE>\n");
3308 fprintf (fp,"<UL>\n");
3309 for (h = gHostList ; h != NULL ; h = h->next)
3310 fprintf (fp,"<LI><A href=\"#%s\">%s</A></LI>\n",
3311 h->params->peerName, h->params->peerName);
3312 fprintf (fp,"</UL>\n\n");
3313 fprintf (fp,"<PRE>\n");
3314 }
3315
3316 mainLogStatus (fp) ;
3317 listenerLogStatus (fp) ;
3318
3319 /*
3320 Default peer configuration parameters:
3321 article timeout: 600 initial connections: 1
3322 response timeout: 300 max connections: 5
3323 close period: 6000 max checks: 25
3324 want streaming: true dynamic method: 1
3325 no-check on: 95.0% dynamic backlog low: 25%
3326 no-check off: 90.0% dynamic backlog high: 50%
3327 no-check filter: 50.0 dynamic backlog filter: 0.7
3328 backlog low limit: 1024 port num: 119
3329 backlog high limit: 1280 backlog feed first: false
3330 backlog factor: 1.1
3331 */
3332 fprintf(fp,"%sDefault peer configuration parameters:%s\n",
3333 genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
3334 fprintf(fp," article timeout: %-5u initial connections: %u\n",
3335 defaultParams->articleTimeout,
3336 defaultParams->initialConnections) ;
3337 fprintf(fp," response timeout: %-5u max connections: %u\n",
3338 defaultParams->responseTimeout,
3339 defaultParams->absMaxConnections) ;
3340 fprintf(fp," reconnection time: %-5u max reconnection time: %u\n",
3341 init_reconnect_period, max_reconnect_period);
3342 fprintf(fp," close period: %-5u max checks: %u\n",
3343 defaultParams->closePeriod,
3344 defaultParams->maxChecks) ;
3345 fprintf(fp," DNS retry period: %-5u DNS expire period: %u\n",
3346 dnsRetPeriod, dnsExpPeriod);
3347 fprintf(fp," port num: %-5u force IPv4: %s\n",
3348 defaultParams->portNum,
3349 defaultParams->forceIPv4 ? "true " : "false");
3350 fprintf(fp," want streaming: %-5s dynamic method: %u\n",
3351 defaultParams->wantStreaming ? "true " : "false",
3352 defaultParams->dynamicMethod) ;
3353 fprintf(fp," no-check on: %-2.1f%% dynamic backlog low: %-2.1f%%\n",
3354 defaultParams->lowPassHigh,
3355 defaultParams->dynBacklogLowWaterMark) ;
3356 fprintf(fp," no-check off: %-2.1f%% dynamic backlog high: %-2.1f%%\n",
3357 defaultParams->lowPassLow,
3358 defaultParams->dynBacklogHighWaterMark) ;
3359 fprintf(fp," no-check filter: %-2.1f dynamic backlog filter: %-2.1f\n",
3360 defaultParams->lowPassFilter,
3361 defaultParams->dynBacklogFilter) ;
3362 fprintf(fp," backlog limit low: %-7u drop-deferred: %s\n",
3363 defaultParams->backlogLimit,
3364 defaultParams->dropDeferred ? "true " : "false");
3365 fprintf(fp," backlog limit high: %-7u min-queue-cxn: %s\n",
3366 defaultParams->backlogLimitHigh,
3367 defaultParams->minQueueCxn ? "true " : "false");
3368 fprintf(fp," backlog feed first: %s\n",
3369 defaultParams->backlogFeedFirst ? "true " : "false");
3370 fprintf(fp," backlog factor: %1.1f\n\n",
3371 defaultParams->backlogFactor);
3372
3373 tapeLogGlobalStatus (fp) ;
3374
3375 fprintf (fp,"\n") ;
3376 fprintf(fp,"%sglobal (process)%s\n",
3377 genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
3378
3379 fprintf (fp, " seconds: %ld\n", sec) ;
3380 if (sec == 0) sec = 1 ;
3381 offered = procArtsOffered ? procArtsOffered : 1 ;
3382 totalsize = procArtsSizeAccepted+procArtsSizeRejected ;
3383 if (totalsize == 0) totalsize = 1. ;
3384
3385 fprintf (fp, " offered: %-5ld\t%6.2f art/s\n",
3386 procArtsOffered,
3387 (double)procArtsOffered/sec) ;
3388 fprintf (fp, " accepted: %-5ld\t%6.2f art/s\t%5.1f%%\n",
3389 procArtsAccepted,
3390 (double)procArtsAccepted/sec,
3391 (double)procArtsAccepted*100./offered) ;
3392 fprintf (fp, " refused: %-5ld\t%6.2f art/s\t%5.1f%%\n",
3393 procArtsNotWanted,
3394 (double)procArtsNotWanted/sec,
3395 (double)procArtsNotWanted*100./offered) ;
3396 fprintf (fp, " rejected: %-5ld\t%6.2f art/s\t%5.1f%%\n",
3397 procArtsRejected,
3398 (double)procArtsRejected/sec,
3399 (double)procArtsRejected*100./offered) ;
3400 fprintf (fp, " missing: %-5ld\t%6.2f art/s\t%5.1f%%\n",
3401 procArtsMissing,
3402 (double)procArtsMissing/sec,
3403 (double)procArtsMissing*100./offered) ;
3404 fprintf (fp, " deferred: %-5ld\t%6.2f art/s\t%5.1f%%\n",
3405 procArtsDeferred,
3406 (double)procArtsDeferred/sec,
3407 (double)procArtsDeferred*100./offered) ;
3408
3409 size=convsize(procArtsSizeAccepted, &tsize);
3410 fprintf (fp, "accpt size: %.3g %s", size, tsize) ;
3411 size=convsize(procArtsSizeAccepted/sec, &tsize);
3412 fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
3413 size, tsize,
3414 procArtsSizeAccepted*100./totalsize) ;
3415
3416 size=convsize(procArtsSizeRejected, &tsize);
3417 fprintf (fp, "rejct size: %.3g %s", size, tsize) ;
3418 size=convsize(procArtsSizeRejected/sec, &tsize);
3419 fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
3420 size, tsize,
3421 procArtsSizeRejected*100./totalsize) ;
3422
3423 fprintf (fp, "\n");
3424
3425 for (h = gHostList ; h != NULL ; h = h->next)
3426 hostPrintStatus (h,fp) ;
3427
3428 if (genHtml)
3429 {
3430 fprintf (fp,"</PRE>\n") ;
3431 fprintf (fp,"</BODY>\n") ;
3432 fprintf (fp,"</HTML>\n") ;
3433 }
3434
3435 fclose (fp) ;
3436 }
3437 TMRstop(TMR_STATUSFILE);
3438 }
3439
3440 /*
3441 * This prints status information for each host. An example of the
3442 * format of the output is:
3443 *
3444 * sitename
3445 * Addr 1: IPv4 12.0.0.42
3446 * seconds: 351 art. timeout: 400 ip name: foo.bar
3447 * offered: 1194 resp. timeout: 240 port: 119
3448 * accepted: 178 want streaming: yes active cxns: 6
3449 * refused: 948 is streaming: yes sleeping cxns: 0
3450 * rejected: 31 max checks: 25 initial cxns: 5
3451 * missing: 0 no-check on: 95.0% idle cxns: 4
3452 * deferred: 0 no-check off: 95.0% max cxns: 8/10
3453 * requeued: 0 no-check fltr: 50.0 queue length: 0.0/200
3454 * spooled: 0 dynamic method: 0 empty: 100.0%
3455 *[overflow]: 0 dyn b'log low: 25% >0%-25%: 0.0%
3456 *[on_close]: 0 dyn b'log high: 50% 25%-50%: 0.0%
3457 *[sleeping]: 0 dyn b'log stat: 37% 50%-75%: 0.0%
3458 * unspooled: 0 dyn b'log fltr: 0.7 75%-<100%: 0.0%
3459 * no queue: 1234 avr.cxns queue: 0.0 full: 0.0%
3460 *accpt size: 121.1 MB drop-deferred: false defer length: 0
3461 *rejct size: 27.1 MB min-queue-cxn: false
3462 * backlog low limit: 1000000
3463 * backlog high limit: 2000000 (factor 2.0)
3464 * backlog shrinkage: 0 bytes (from current file)
3465 * offered: 1.13 art/s accepted: 0.69 art/s (101.71 KB/s)
3466 * refused: 0.01 art/s rejected: 0.42 art/s (145.11 KB/s)
3467 * missing 0 spooled 0
3468 *
3469 */
hostPrintStatus(Host host,FILE * fp)3470 static void hostPrintStatus (Host host, FILE *fp)
3471 {
3472 time_t now = theTime() ;
3473 double cnt = (host->blCount) ? (host->blCount) : 1.0;
3474 double size;
3475 char *tsize;
3476 char buf[]="1.234e+05 TB"; /* usual length is shorter, like "12.34 MB" */
3477
3478 ASSERT (host != NULL) ;
3479 ASSERT (fp != NULL) ;
3480
3481 if (genHtml)
3482 fprintf (fp,"<A name=\"%s\"><B>%s</B></A>",host->params->peerName,
3483 host->params->peerName);
3484 else
3485 fprintf (fp,"%s",host->params->peerName);
3486
3487 if (host->blockedReason != NULL)
3488 fprintf (fp," (remote status: ``%s'')",host->blockedReason) ;
3489
3490 fputc ('\n',fp) ;
3491
3492 if (host->ipAddrs) {
3493 size_t i;
3494 char ip_addr[INET6_ADDRSTRLEN];
3495 const char *family;
3496
3497 for(i = 0; host->ipAddrs[i] != NULL; i++) {
3498 switch(host->ipAddrs[i]->sa_family) {
3499 case AF_INET:
3500 family = "IPv4";
3501 break;
3502 #ifdef HAVE_INET6
3503 case AF_INET6:
3504 family = "IPv6";
3505 break;
3506 #endif
3507 default:
3508 family = "????";
3509 break;
3510 }
3511
3512 network_sockaddr_sprint(ip_addr, sizeof(ip_addr),
3513 host->ipAddrs[i]);
3514 fprintf(fp, " Addr %-2lu: %-4.4s %s\n", (unsigned long) (i+1),
3515 family, ip_addr);
3516 }
3517 }
3518
3519 fprintf (fp, " seconds: %-7ld art. timeout: %-5u ip name: %s\n",
3520 host->firstConnectTime > 0 ? (long)(now - host->firstConnectTime) : 0,
3521 host->params->articleTimeout, host->params->ipName) ;
3522
3523 fprintf (fp, " offered: %-7ld resp. timeout: %-5u port: %u\n",
3524 (long) host->gArtsOffered, host->params->responseTimeout,
3525 host->params->portNum);
3526
3527 fprintf (fp, " accepted: %-7ld want streaming: %s active cxns: %u\n",
3528 (long) host->gArtsAccepted,
3529 (host->params->wantStreaming ? "yes" : "no "),
3530 host->activeCxns) ;
3531
3532 fprintf (fp, " refused: %-7ld is streaming: %s sleeping cxns: %u\n",
3533 (long) host->gArtsNotWanted,
3534 (host->remoteStreams ? "yes" : "no "),
3535 host->sleepingCxns) ;
3536
3537 fprintf (fp, " rejected: %-7ld max checks: %-5u initial cxns: %u\n",
3538 (long) host->gArtsRejected, host->params->maxChecks,
3539 host->params->initialConnections) ;
3540
3541 fprintf (fp, " missing: %-7ld no-check on: %-3.1f%% idle cxns: %u\n",
3542 (long) host->gArtsMissing, host->params->lowPassHigh,
3543 host->maxConnections - (host->activeCxns + host->sleepingCxns)) ;
3544
3545 fprintf (fp, " deferred: %-7ld no-check off: %-3.1f%% max cxns: %u/%u\n",
3546 (long) host->gArtsDeferred, host->params->lowPassLow,
3547 host->maxConnections, host->params->absMaxConnections) ;
3548
3549 fprintf (fp, " requeued: %-7ld no-check fltr: %-3.1f queue length: %-3.1f/%u\n",
3550 (long) host->gArtsCxnDrop, host->params->lowPassFilter,
3551 (double)host->blAccum / cnt, hostHighwater) ;
3552
3553 fprintf (fp, " spooled: %-7ld dynamic method: %-5u empty: %-3.1f%%\n",
3554 (long) host->gArtsToTape,
3555 host->params->dynamicMethod,
3556 100.0 * host->blNone / cnt) ;
3557
3558 fprintf (fp, "[overflow]: %-7ld dyn b'log low: %-3.1f%% >0%%-25%%: %-3.1f%%\n",
3559 (long) host->gArtsQueueOverflow,
3560 host->params->dynBacklogLowWaterMark,
3561 100.0 * host->blQuartile[0] / cnt) ;
3562
3563 fprintf (fp, "[on_close]: %-7ld dyn b'log high: %-3.1f%% 25%%-50%%: %-3.1f%%\n",
3564 (long) host->gArtsHostClose,
3565 host->params->dynBacklogHighWaterMark,
3566 100.0 * host->blQuartile[1] / cnt) ;
3567
3568 fprintf (fp, "[sleeping]: %-7ld dyn b'log stat: %-3.1f%% 50%%-75%%: %-3.1f%%\n",
3569 (long) host->gArtsHostSleep,
3570 host->backlogFilter*100.0*(1.0-host->params->dynBacklogFilter),
3571 100.0 * host->blQuartile[2] / cnt) ;
3572
3573 fprintf (fp, " unspooled: %-7ld dyn b'log fltr: %-3.1f 75%%-<100%%: %-3.1f%%\n",
3574 (long) host->gArtsFromTape,
3575 host->params->dynBacklogLowWaterMark,
3576 100.0 * host->blQuartile[3] / cnt) ;
3577
3578 fprintf (fp, " no queue: %-7ld avr.cxns queue: %-3.1f full: %-3.1f%%\n",
3579 (long) host->gNoQueue,
3580 (double) host->gCxnQueue / (host->gArtsOffered ? host->gArtsOffered :1) ,
3581 100.0 * host->blFull / cnt) ;
3582 size=convsize(host->gArtsSizeAccepted, &tsize);
3583 snprintf(buf, sizeof(buf), "%.3g %s", size, tsize);
3584 fprintf (fp, "accpt size: %-8s drop-deferred: %-5s defer length: %-3.1f\n",
3585 buf, host->params->dropDeferred ? "true " : "false",
3586 (double)host->dlAccum / cnt) ;
3587 size=convsize(host->gArtsSizeRejected, &tsize);
3588 snprintf(buf, sizeof(buf), "%.3g %s", size, tsize);
3589 fprintf (fp, "rejct size: %-8s min-queue-cxn: %s\n",
3590 buf, host->params->minQueueCxn ? "true " : "false");
3591
3592 tapeLogStatus (host->myTape,fp) ;
3593
3594 {
3595 time_t sec = (time_t) (now - host->connectTime);
3596 double or, ar, rr, jr;
3597 double ars, jrs;
3598 char *tars, *tjrs;
3599 if (sec != 0) {
3600 or = (double) host->artsOffered / (double) sec;
3601 ar = (double) host->artsAccepted / (double) sec;
3602 rr = (double) host->artsNotWanted / (double) sec;
3603 jr = (double) host->artsRejected / (double) sec;
3604 ars = convsize (host->artsSizeAccepted/sec, &tars);
3605 jrs = convsize (host->artsSizeRejected/sec, &tjrs);
3606 fprintf(fp, " offered: %5.2f art/s accepted: %5.2f art/s, %.3g %s/s\n",
3607 or, ar, ars, tars);
3608 fprintf(fp, " refused: %5.2f art/s rejected: %5.2f art/s, %.3g %s/s\n",
3609 rr, jr, jrs, tjrs);
3610 }
3611 fprintf(fp, " missing %u spooled %u\n",
3612 host->artsMissing, host->artsToTape);
3613 }
3614
3615 #ifdef XXX_STATSHACK
3616 {
3617 time_t now2 = time(NULL);
3618 time_t sec2 = (long) (now2 - host->connectTime);
3619 double or, ar, rr, jr;
3620
3621 if (sec2 != 0) {
3622 or = (double) host->artsOffered / (double) sec2;
3623 ar = (double) host->artsAccepted / (double) sec2;
3624 rr = (double) host->artsNotWanted / (double) sec2;
3625 jr = (double) host->artsRejected / (double) sec2;
3626 fprintf(fp, " or %02.2f ar %02.2f rr %02.2f jr %02.2f\n",
3627 or, ar, rr, jr);
3628 }
3629 fprintf(fp, " missing %u spooled %u\n",
3630 host->artsMissing, host->artsToTape);
3631 }
3632 #endif /* XXX_STATSHACK */
3633
3634 fprintf (fp, "\n\n");
3635 }
3636
3637
3638
3639
3640
3641
3642
3643 /*
3644 * The callback function for the statistics timer to call.
3645 */
hostStatsTimeoutCbk(TimeoutId tid UNUSED,void * data)3646 static void hostStatsTimeoutCbk (TimeoutId tid UNUSED, void *data)
3647 {
3648 Host host = (Host) data ;
3649 time_t now = theTime () ;
3650
3651 ASSERT (tid == host->statsId) ;
3652
3653 if (!amClosing (host))
3654 hostLogStats (host, false) ;
3655
3656 if (now - lastStatusLog >= statsPeriod)
3657 hostLogStatus () ;
3658
3659 host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
3660 }
3661
3662
3663 /*
3664 * The callback function for the deferred article timer to call.
3665 */
hostDeferredArtCbk(TimeoutId tid UNUSED,void * data)3666 static void hostDeferredArtCbk (TimeoutId tid UNUSED, void *data)
3667 {
3668 Host host = (Host) data ;
3669 time_t now = theTime () ;
3670 Article article ;
3671
3672 ASSERT (tid == host->deferredId) ;
3673
3674 while (host->deferred && host->deferred->whenToRequeue <= now)
3675 {
3676 article = remHead (&host->deferred,&host->deferredTail) ;
3677 host->deferLen-- ;
3678 hostSendArticle (host, article) ; /* requeue it */
3679 }
3680
3681 if (host->deferred)
3682 host->deferredId = prepareSleep (hostDeferredArtCbk,
3683 host->deferred->whenToRequeue - now,
3684 host) ;
3685 else
3686 host->deferredId = 0;
3687 }
3688
3689
3690 /* if the host has too many unprocessed articles so we send some to the tape. */
backlogToTape(Host host)3691 static void backlogToTape (Host host)
3692 {
3693 Article article ;
3694
3695 while ((host->backlog + host->deferLen) > hostHighwater)
3696 {
3697 if (!host->loggedBacklog)
3698 {
3699 host->loggedBacklog = true ;
3700 }
3701
3702 if (host->deferred != NULL)
3703 {
3704 article = remHead (&host->deferred,&host->deferredTail) ;
3705 host->deferLen--;
3706 }
3707 else
3708 {
3709 article = remHead (&host->queued,&host->queuedTail) ;
3710 host->backlog--;
3711 }
3712
3713 ASSERT(article != NULL);
3714
3715 host->artsQueueOverflow++ ;
3716 host->gArtsQueueOverflow++ ;
3717 host->artsToTape++ ;
3718 host->gArtsToTape++ ;
3719 procArtsToTape++ ;
3720 tapeTakeArticle (host->myTape,article) ;
3721 }
3722 }
3723
3724
3725
3726
3727
3728
3729
3730 /*
3731 * Returns true of the Host is in the middle of closing down.
3732 */
amClosing(Host host)3733 static bool amClosing (Host host)
3734 {
3735 return (host->myTape == NULL ? true : false) ;
3736 }
3737
3738
3739
3740
3741
3742
3743
3744 /*
3745 * flush all queued articles all the way out to disk.
3746 */
queuesToTape(Host host)3747 static void queuesToTape (Host host)
3748 {
3749 Article art ;
3750
3751 while ((art = remHead (&host->processed,&host->processedTail)) != NULL)
3752 {
3753 host->artsHostClose++ ;
3754 host->gArtsHostClose++ ;
3755 host->artsToTape++ ;
3756 host->gArtsToTape++ ;
3757 procArtsToTape++ ;
3758 tapeTakeArticle (host->myTape,art) ;
3759 }
3760
3761 while ((art = remHead (&host->queued,&host->queuedTail)) != NULL)
3762 {
3763 host->backlog-- ;
3764 host->artsHostClose++ ;
3765 host->gArtsHostClose++ ;
3766 host->artsToTape++ ;
3767 host->gArtsToTape++ ;
3768 procArtsToTape++ ;
3769 tapeTakeArticle (host->myTape,art) ;
3770 }
3771
3772 while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
3773 {
3774 host->deferLen-- ;
3775 host->artsHostClose++ ;
3776 host->gArtsHostClose++ ;
3777 host->artsToTape++ ;
3778 host->gArtsToTape++ ;
3779 procArtsToTape++ ;
3780 tapeTakeArticle (host->myTape,art) ;
3781 }
3782
3783 while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
3784 {
3785 host->deferLen-- ;
3786 host->artsHostClose++ ;
3787 host->gArtsHostClose++ ;
3788 host->artsToTape++ ;
3789 host->gArtsToTape++ ;
3790 procArtsToTape++ ;
3791 tapeTakeArticle (host->myTape,art) ;
3792 }
3793 }
3794
3795
3796
3797
3798
3799
3800
3801 #define QUEUE_ELEM_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (struct proc_q_elem)))
3802
3803 static ProcQElem queueElemPool ;
3804
3805 /*
3806 * Add an article to the given queue.
3807 */
queueArticle(Article article,ProcQElem * head,ProcQElem * tail,time_t when)3808 static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
3809 time_t when)
3810 {
3811 ProcQElem elem ;
3812
3813 if (queueElemPool == NULL)
3814 {
3815 unsigned int i ;
3816
3817 queueElemPool =
3818 xmalloc (sizeof(struct proc_q_elem) * QUEUE_ELEM_POOL_SIZE) ;
3819
3820 for (i = 0; i < QUEUE_ELEM_POOL_SIZE - 1; i++)
3821 queueElemPool[i] . next = &(queueElemPool [i + 1]) ;
3822 queueElemPool [QUEUE_ELEM_POOL_SIZE-1] . next = NULL ;
3823 }
3824
3825 elem = queueElemPool ;
3826 ASSERT (elem != NULL) ;
3827 queueElemPool = queueElemPool->next ;
3828
3829 elem->article = article ;
3830 elem->next = NULL ;
3831 elem->prev = *tail ;
3832 elem->whenToRequeue = when ;
3833 if (*tail != NULL)
3834 (*tail)->next = elem ;
3835 else
3836 *head = elem ;
3837 *tail = elem ;
3838 }
3839
3840
3841
3842
3843
3844
3845
3846 /*
3847 * remove the article from the queue
3848 */
remArticle(Article article,ProcQElem * head,ProcQElem * tail)3849 static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail)
3850 {
3851 ProcQElem elem ;
3852
3853 ASSERT (head != NULL) ;
3854 ASSERT (tail != NULL) ;
3855
3856 /* we go backwards down the list--probably faster */
3857 elem = *tail ;
3858 while (elem != NULL && elem->article != article)
3859 elem = elem->prev ;
3860
3861 if (elem != NULL)
3862 {
3863 if (elem->prev != NULL)
3864 elem->prev->next = elem->next ;
3865 if (elem->next != NULL)
3866 elem->next->prev = elem->prev ;
3867 if (*head == elem)
3868 *head = elem->next ;
3869 if (*tail == elem)
3870 *tail = elem->prev ;
3871
3872 elem->next = queueElemPool ;
3873 queueElemPool = elem ;
3874
3875 return true ;
3876 }
3877 else
3878 return false ;
3879 }
3880
3881
3882
3883
3884
3885
3886
3887 /*
3888 * remove the article that's at the head of the queue and return
3889 * it. Returns NULL if the queue is empty.
3890 */
remHead(ProcQElem * head,ProcQElem * tail)3891 static Article remHead (ProcQElem *head, ProcQElem *tail)
3892 {
3893 ProcQElem elem ;
3894 Article art ;
3895
3896 ASSERT (head != NULL) ;
3897 ASSERT (tail != NULL) ;
3898 ASSERT ((*head == NULL && *tail == NULL) ||
3899 (*head != NULL && *tail != NULL)) ;
3900
3901 if (*head == NULL)
3902 return NULL ;
3903
3904 elem = *head ;
3905 art = elem->article ;
3906 *head = elem->next ;
3907 if (elem->next != NULL)
3908 elem->next->prev = NULL ;
3909
3910 if (*tail == elem)
3911 *tail = NULL ;
3912
3913 elem->next = queueElemPool ;
3914 queueElemPool = elem ;
3915
3916 return art ;
3917 }
3918
3919
3920
validateInteger(FILE * fp,const char * name,long low,long high,int required,long setval,scope * sc,unsigned int inh)3921 static int validateInteger (FILE *fp, const char *name,
3922 long low, long high, int required, long setval,
3923 scope * sc, unsigned int inh)
3924 {
3925 int rval = VALUE_OK ;
3926 value *v ;
3927 scope *s ;
3928 char *p = strrchr (name,':') ;
3929
3930 v = findValue (sc,name,inh) ;
3931 if (v == NULL && required != NOTREQNOADD)
3932 {
3933 s = findScope (sc,name,0) ;
3934 addInteger (s,p ? p + 1 : name,setval) ;
3935 if (required == REQ)
3936 {
3937 rval = VALUE_MISSING ;
3938 logOrPrint (LOG_ERR,fp,
3939 "ME config: no definition for required key %s",name) ;
3940 }
3941 else
3942 logOrPrint (LOG_INFO,fp,
3943 "ME config: adding default value for key %s: %ld",name
3944 ,setval) ;
3945 }
3946 else if (v != NULL && v->type != intval)
3947 {
3948 rval = VALUE_WRONG_TYPE ;
3949 logOrPrint (LOG_ERR,fp,"ME config: value of %s is not an integer",name) ;
3950 }
3951 else if (v != NULL && low != LONG_MIN && v->v.int_val < low)
3952 {
3953 rval = VALUE_TOO_LOW ;
3954 logOrPrint (LOG_ERR,fp,
3955 "ME config: value of %s (%ld) in %s is lower than minimum"
3956 " of %ld. Using %ld",name,v->v.int_val,
3957 "global scope",low,low) ;
3958 v->v.int_val = low ;
3959 }
3960 else if (v != NULL && high != LONG_MAX && v->v.int_val > high)
3961 {
3962 rval = VALUE_TOO_HIGH ;
3963 logOrPrint(LOG_ERR,fp,
3964 "ME config: value of %s (%ld) in %s is higher than maximum"
3965 " of %ld. Using %ld",name,v->v.int_val,
3966 "global scope",high,high);
3967 v->v.int_val = high ;
3968 }
3969
3970 return rval ;
3971 }
3972
3973
3974
validateReal(FILE * fp,const char * name,double low,double high,int required,double setval,scope * sc,unsigned int inh)3975 static int validateReal (FILE *fp, const char *name, double low,
3976 double high, int required, double setval,
3977 scope * sc, unsigned int inh)
3978 {
3979 int rval = VALUE_OK ;
3980 value *v ;
3981 scope *s ;
3982 char *p = strrchr (name,':') ;
3983
3984 v = findValue (sc,name,inh) ;
3985 if (v == NULL && required != NOTREQNOADD)
3986 {
3987 s = findScope (sc,name,0) ;
3988 addReal (s,p ? p + 1 : name,setval) ;
3989 if (required == REQ)
3990 {
3991 rval = VALUE_MISSING ;
3992 logOrPrint (LOG_ERR,fp,
3993 "ME config: no definition for required key %s",name) ;
3994 }
3995 else
3996 logOrPrint (LOG_INFO,fp,
3997 "ME config: adding default value for key %s: %f",name,
3998 setval) ;
3999 }
4000 else if (v != NULL && v->type != realval)
4001 {
4002 rval = VALUE_WRONG_TYPE ;
4003 logOrPrint (LOG_ERR,fp,
4004 "ME config: value of %s is not a floating point number",
4005 name) ;
4006 }
4007 else if (v != NULL && low != -DBL_MAX && v->v.real_val < low)
4008 {
4009 logOrPrint (LOG_ERR,fp,
4010 "ME config: value of %s (%f) is lower than minimum of %f",
4011 name,v->v.real_val,low) ;
4012 v->v.real_val = setval ;
4013 }
4014 else if (v != NULL && high != DBL_MAX && v->v.real_val > high)
4015 {
4016 logOrPrint (LOG_ERR,fp,
4017 "ME config: value of %s (%f) is higher than maximum of %f",
4018 name,v->v.real_val,high) ;
4019 v->v.real_val = setval ;
4020 }
4021
4022 return rval ;
4023 }
4024
4025
4026
validateBool(FILE * fp,const char * name,int required,bool setval,scope * sc,unsigned int inh)4027 static int validateBool (FILE *fp, const char *name, int required, bool setval,
4028 scope * sc, unsigned int inh)
4029 {
4030 int rval = VALUE_OK ;
4031 value *v ;
4032 scope *s ;
4033 char *p = strrchr (name,':') ;
4034
4035 v = findValue (sc,name,inh) ;
4036 if (v == NULL && required != NOTREQNOADD)
4037 {
4038 s = findScope (sc,name,0) ;
4039 addBoolean (s,p ? p + 1 : name, setval ? 1 : 0) ;
4040 if (required == REQ)
4041 {
4042 rval = VALUE_MISSING ;
4043 logOrPrint (LOG_ERR,fp,
4044 "ME config: no definition for required key %s",name) ;
4045 }
4046 else
4047 logOrPrint (LOG_INFO,fp,
4048 "ME config: adding default value for key %s: %s",name,
4049 (setval ? "true" : "false")) ;
4050 }
4051 else if (v != NULL && v->type != boolval)
4052 {
4053 rval = VALUE_WRONG_TYPE ;
4054 logOrPrint (LOG_ERR,fp,"ME config: value of %s is not a boolean",name) ;
4055 }
4056
4057 return rval ;
4058 }
4059
4060
gCalcHostBlStat(void)4061 void gCalcHostBlStat (void)
4062 {
4063 Host h ;
4064
4065 for (h = gHostList ; h != NULL ; h = h->next)
4066 {
4067 h->dlAccum += h->deferLen ;
4068 h->blAccum += h->backlog ;
4069 if (h->backlog == 0)
4070 h->blNone++ ;
4071 else if (h->backlog >= (hostHighwater - h->deferLen))
4072 h->blFull++ ;
4073 else
4074 h->blQuartile[(4*h->backlog) / (hostHighwater - h->deferLen)]++ ;
4075 h->blCount++ ;
4076 }
4077 }
hostCleanup(void)4078 static void hostCleanup (void)
4079 {
4080 if (statusFile != NULL)
4081 free (statusFile) ;
4082 statusFile = NULL ;
4083 }
4084