2 * DEBUG: section 15 Neighbor Routines
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "ProtoPort.h"
35 #include "acl/FilledChecklist.h"
37 #include "CacheManager.h"
39 #include "HttpRequest.h"
41 #include "MemObject.h"
42 #include "PeerDigest.h"
43 #include "PeerSelectState.h"
44 #include "SquidMath.h"
45 #include "SquidTime.h"
47 #include "icmp/net_db.h"
48 #include "ip/Address.h"
50 /* count mcast group peers every 15 minutes */
51 #define MCAST_COUNT_RATE 900
53 int peerAllowedToUse(const peer
*, HttpRequest
*);
54 static int peerWouldBePinged(const peer
*, HttpRequest
*);
55 static void neighborRemove(peer
*);
56 static void neighborAlive(peer
*, const MemObject
*, const icp_common_t
*);
58 static void neighborAliveHtcp(peer
*, const MemObject
*, const htcpReplyData
*);
60 static void neighborCountIgnored(peer
*);
61 static void peerRefreshDNS(void *);
62 static IPH peerDNSConfigure
;
63 static int peerProbeConnect(peer
*);
64 static CNCB peerProbeConnectDone
;
65 static void peerCountMcastPeersDone(void *data
);
66 static void peerCountMcastPeersStart(void *data
);
67 static void peerCountMcastPeersSchedule(peer
* p
, time_t when
);
68 static IRCB peerCountHandleIcpReply
;
70 static void neighborIgnoreNonPeer(const Ip::Address
&, icp_opcode
);
71 static OBJH neighborDumpPeers
;
72 static OBJH neighborDumpNonPeers
;
73 static void dump_peers(StoreEntry
* sentry
, peer
* peers
);
75 static icp_common_t echo_hdr
;
76 static u_short echo_port
;
78 static int NLateReplies
= 0;
79 static peer
*first_ping
= NULL
;
82 neighborTypeStr(const peer
* p
)
84 if (p
->type
== PEER_NONE
)
87 if (p
->type
== PEER_SIBLING
)
90 if (p
->type
== PEER_MULTICAST
)
91 return "Multicast Group";
98 whichPeer(const Ip::Address
&from
)
103 debugs(15, 3, "whichPeer: from " << from
);
105 for (p
= Config
.peers
; p
; p
= p
->next
) {
106 for (j
= 0; j
< p
->n_addresses
; j
++) {
107 if (from
== p
->addresses
[j
] && from
.GetPort() == p
->icp
.port
) {
117 neighborType(const peer
* p
, const HttpRequest
* request
)
120 const struct _domain_type
*d
= NULL
;
122 for (d
= p
->typelist
; d
; d
= d
->next
) {
123 if (0 == matchDomainName(request
->GetHost(), d
->domain
))
124 if (d
->type
!= PEER_NONE
)
127 #if PEER_MULTICAST_SIBLINGS
128 if (p
->type
== PEER_MULTICAST
)
129 if (p
->options
.mcast_siblings
)
139 * this function figures out if it is appropriate to fetch REQUEST
143 peerAllowedToUse(const peer
* p
, HttpRequest
* request
)
146 const struct _domain_ping
*d
= NULL
;
148 assert(request
!= NULL
);
150 if (neighborType(p
, request
) == PEER_SIBLING
) {
151 #if PEER_MULTICAST_SIBLINGS
152 if (p
->type
== PEER_MULTICAST
&& p
->options
.mcast_siblings
&&
153 (request
->flags
.nocache
|| request
->flags
.refresh
|| request
->flags
.loopdetect
|| request
->flags
.need_validation
))
154 debugs(15, 2, "peerAllowedToUse(" << p
->name
<< ", " << request
->GetHost() << ") : multicast-siblings optimization match");
156 if (request
->flags
.nocache
)
159 if (request
->flags
.refresh
)
162 if (request
->flags
.loopdetect
)
165 if (request
->flags
.need_validation
)
169 if (p
->peer_domain
== NULL
&& p
->access
== NULL
)
174 for (d
= p
->peer_domain
; d
; d
= d
->next
) {
175 if (0 == matchDomainName(request
->GetHost(), d
->domain
)) {
176 do_ping
= d
->do_ping
;
180 do_ping
= !d
->do_ping
;
183 if (p
->peer_domain
&& 0 == do_ping
)
186 if (p
->access
== NULL
)
189 ACLFilledChecklist
checklist(p
->access
, request
, NULL
);
190 checklist
.src_addr
= request
->client_addr
;
191 checklist
.my_addr
= request
->my_addr
;
195 * this is currently broken because 'request->user_ident' has been
196 * moved to conn->rfc931 and we don't have access to the parent
197 * ConnStateData here.
199 if (request
->user_ident
[0])
200 xstrncpy(checklist
.rfc931
, request
->user_ident
, USER_IDENT_SZ
);
204 return checklist
.fastCheck();
207 /* Return TRUE if it is okay to send an ICP request to this peer. */
209 peerWouldBePinged(const peer
* p
, HttpRequest
* request
)
211 if (!peerAllowedToUse(p
, request
))
214 if (p
->options
.no_query
)
217 if (p
->options
.background_ping
&& (squid_curtime
- p
->stats
.last_query
< Config
.backgroundPingRate
))
220 if (p
->options
.mcast_responder
)
223 if (p
->n_addresses
== 0)
226 if (p
->icp
.port
== 0)
229 /* the case below seems strange, but can happen if the
230 * URL host is on the other side of a firewall */
231 if (p
->type
== PEER_SIBLING
)
232 if (!request
->flags
.hierarchical
)
235 /* Ping dead peers every timeout interval */
236 if (squid_curtime
- p
->stats
.last_query
> Config
.Timeout
.deadPeer
)
245 /* Return TRUE if it is okay to send an HTTP request to this peer. */
247 peerHTTPOkay(const peer
* p
, HttpRequest
* request
)
249 if (!peerAllowedToUse(p
, request
))
256 if (p
->stats
.conn_open
>= p
->max_conn
)
263 neighborsCount(HttpRequest
* request
)
268 for (p
= Config
.peers
; p
; p
= p
->next
)
269 if (peerWouldBePinged(p
, request
))
272 debugs(15, 3, "neighborsCount: " << count
);
278 getFirstUpParent(HttpRequest
* request
)
282 for (p
= Config
.peers
; p
; p
= p
->next
) {
286 if (neighborType(p
, request
) != PEER_PARENT
)
289 if (!peerHTTPOkay(p
, request
))
295 debugs(15, 3, "getFirstUpParent: returning " << (p
? p
->host
: "NULL"));
300 getRoundRobinParent(HttpRequest
* request
)
305 for (p
= Config
.peers
; p
; p
= p
->next
) {
306 if (!p
->options
.roundrobin
)
309 if (neighborType(p
, request
) != PEER_PARENT
)
312 if (!peerHTTPOkay(p
, request
))
319 if (p
->weight
== q
->weight
) {
320 if (q
->rr_count
< p
->rr_count
)
322 } else if ( (double) q
->rr_count
/ q
->weight
< (double) p
->rr_count
/ p
->weight
) {
333 debugs(15, 3, HERE
<< "returning " << (q
? q
->host
: "NULL"));
339 getWeightedRoundRobinParent(HttpRequest
* request
)
345 for (p
= Config
.peers
; p
; p
= p
->next
) {
346 if (!p
->options
.weighted_roundrobin
)
349 if (neighborType(p
, request
) != PEER_PARENT
)
352 if (!peerHTTPOkay(p
, request
))
355 if (q
&& q
->rr_count
< p
->rr_count
)
361 if (q
&& q
->rr_count
> 1000000)
362 for (p
= Config
.peers
; p
; p
= p
->next
) {
363 if (!p
->options
.weighted_roundrobin
)
366 if (neighborType(p
, request
) != PEER_PARENT
)
373 weighted_rtt
= (q
->stats
.rtt
- q
->basetime
) / q
->weight
;
375 if (weighted_rtt
< 1)
378 q
->rr_count
+= weighted_rtt
;
380 debugs(15, 3, "getWeightedRoundRobinParent: weighted_rtt " << weighted_rtt
);
383 debugs(15, 3, "getWeightedRoundRobinParent: returning " << (q
? q
->host
: "NULL"));
388 * This gets called every 5 minutes to clear the round-robin counter.
389 * The exact timing is an arbitrary default, set on estimate timing of a
390 * large number of requests in a high-performance environment during the
391 * period. The larger the number of requests between cycled resets the
392 * more balanced the operations.
395 \todo Make the reset timing a selectable parameter in squid.conf
398 peerClearRRLoop(void *data
)
401 eventAdd("peerClearRR", peerClearRRLoop
, data
, 5 * 60.0, 0);
405 * This gets called on startup and restart to kick off the peer round-robin
406 * maintenance event. It ensures that no matter how many times its called
407 * no more than one event is scheduled.
410 peerClearRRStart(void)
412 static int event_added
= 0;
414 peerClearRRLoop(NULL
);
419 * Called whenever the round-robin counters need to be reset to a sane state.
420 * So far those times are:
421 * - On startup and reconfigure - to set the counters to sane initial settings.
422 * - When a peer has revived from dead, to prevent the revived peer being
423 * flooded with requests which it has 'missed' during the down period.
429 for (p
= Config
.peers
; p
; p
= p
->next
) {
435 * Perform all actions when a peer is detected revived.
440 if (p
->stats
.logged_state
== PEER_DEAD
&& p
->tcp_up
) {
441 debugs(15, 1, "Detected REVIVED " << neighborTypeStr(p
) << ": " << p
->name
);
442 p
->stats
.logged_state
= PEER_ALIVE
;
446 p
->stats
.last_reply
= squid_curtime
;
447 p
->stats
.probe_start
= 0;
451 getDefaultParent(HttpRequest
* request
)
455 for (p
= Config
.peers
; p
; p
= p
->next
) {
456 if (neighborType(p
, request
) != PEER_PARENT
)
459 if (!p
->options
.default_parent
)
462 if (!peerHTTPOkay(p
, request
))
465 debugs(15, 3, "getDefaultParent: returning " << p
->host
);
470 debugs(15, 3, "getDefaultParent: returning NULL");
475 * XXX DW thinks this function is equivalent to/redundant with
476 * getFirstUpParent(). peerHTTPOkay() only returns true if the
477 * peer is UP anyway, so this function would not return a
481 getAnyParent(HttpRequest
* request
)
485 for (p
= Config
.peers
; p
; p
= p
->next
) {
486 if (neighborType(p
, request
) != PEER_PARENT
)
489 if (!peerHTTPOkay(p
, request
))
492 debugs(15, 3, "getAnyParent: returning " << p
->host
);
497 debugs(15, 3, "getAnyParent: returning NULL");
502 getNextPeer(peer
* p
)
514 neighborRemove(peer
* target
)
536 first_ping
= Config
.peers
;
540 neighborsRegisterWithCacheManager()
542 CacheManager
*manager
= CacheManager::GetInstance();
543 manager
->registerAction("server_list",
544 "Peer Cache Statistics",
545 neighborDumpPeers
, 0, 1);
547 if (theInIcpConnection
>= 0) {
548 manager
->registerAction("non_peers",
549 "List of Unknown sites sending ICP messages",
550 neighborDumpNonPeers
, 0, 1);
558 struct addrinfo
*AI
= NULL
;
559 struct servent
*sep
= NULL
;
560 const char *me
= getMyHostname();
561 peer
*thisPeer
= NULL
;
563 int fd
= theInIcpConnection
;
565 neighborsRegisterWithCacheManager();
567 /* setup addrinfo for use */
568 nul
.InitAddrInfo(AI
);
572 if (getsockname(fd
, AI
->ai_addr
, &AI
->ai_addrlen
) < 0)
573 debugs(15, 1, "getsockname(" << fd
<< "," << AI
->ai_addr
<< "," << &AI
->ai_addrlen
<< ") failed.");
575 for (thisPeer
= Config
.peers
; thisPeer
; thisPeer
= next
) {
576 http_port_list
*s
= NULL
;
577 next
= thisPeer
->next
;
579 if (0 != strcmp(thisPeer
->host
, me
))
582 for (s
= Config
.Sockaddr
.http
; s
; s
= s
->next
) {
583 if (thisPeer
->http_port
!= s
->s
.GetPort())
586 debugs(15, 1, "WARNING: Peer looks like this host");
588 debugs(15, 1, " Ignoring " <<
589 neighborTypeStr(thisPeer
) << " " << thisPeer
->host
<<
590 "/" << thisPeer
->http_port
<< "/" <<
593 neighborRemove(thisPeer
);
598 peerRefreshDNS((void *) 1);
600 if (ICP_INVALID
== echo_hdr
.opcode
) {
601 echo_hdr
.opcode
= ICP_SECHO
;
602 echo_hdr
.version
= ICP_VERSION_CURRENT
;
608 nul
.GetInAddr( *((struct in_addr
*)&echo_hdr
.shostid
) );
609 sep
= getservbyname("echo", "udp");
610 echo_port
= sep
? ntohs((u_short
) sep
->s_port
) : 7;
613 first_ping
= Config
.peers
;
614 nul
.FreeAddrInfo(AI
);
618 neighborsUdpPing(HttpRequest
* request
,
625 const char *url
= entry
->url();
626 MemObject
*mem
= entry
->mem_obj
;
632 int queries_sent
= 0;
633 int peers_pinged
= 0;
634 int parent_timeout
= 0, parent_exprep
= 0;
635 int sibling_timeout
= 0, sibling_exprep
= 0;
636 int mcast_timeout
= 0, mcast_exprep
= 0;
638 if (Config
.peers
== NULL
)
641 assert(entry
->swap_status
== SWAPOUT_NONE
);
643 mem
->start_ping
= current_time
;
645 mem
->ping_reply_callback
= callback
;
647 mem
->ircb_data
= callback_data
;
649 reqnum
= icpSetCacheKey((const cache_key
*)entry
->key
);
651 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
655 debugs(15, 5, "neighborsUdpPing: Peer " << p
->host
);
657 if (!peerWouldBePinged(p
, request
))
658 continue; /* next peer */
662 debugs(15, 4, "neighborsUdpPing: pinging peer " << p
->host
<< " for '" << url
<< "'");
664 debugs(15, 3, "neighborsUdpPing: key = '" << entry
->getMD5Text() << "'");
666 debugs(15, 3, "neighborsUdpPing: reqnum = " << reqnum
);
669 if (p
->options
.htcp
&& !p
->options
.htcp_only_clr
) {
670 if (Config
.Port
.htcp
<= 0) {
671 debugs(15, DBG_CRITICAL
, "HTCP is disabled! Cannot send HTCP request to peer.");
675 debugs(15, 3, "neighborsUdpPing: sending HTCP query");
676 if (htcpQuery(entry
, request
, p
) <= 0) continue; // unable to send.
680 if (Config
.Port
.icp
<= 0 || theOutIcpConnection
<= 0) {
681 debugs(15, DBG_CRITICAL
, "ICP is disabled! Cannot send ICP request to peer.");
685 if (p
->type
== PEER_MULTICAST
)
686 mcastSetTtl(theOutIcpConnection
, p
->mcast
.ttl
);
688 if (p
->icp
.port
== echo_port
) {
689 debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping");
690 echo_hdr
.reqnum
= reqnum
;
691 query
= _icp_common_t::createMessage(ICP_DECHO
, 0, url
, reqnum
, 0);
692 icpUdpSend(theOutIcpConnection
,p
->in_addr
,query
,LOG_ICP_QUERY
,0);
696 if (Config
.onoff
.query_icmp
)
697 if (p
->icp
.version
== ICP_VERSION_2
)
698 flags
|= ICP_FLAG_SRC_RTT
;
700 query
= _icp_common_t::createMessage(ICP_QUERY
, flags
, url
, reqnum
, 0);
702 icpUdpSend(theOutIcpConnection
, p
->in_addr
, query
, LOG_ICP_QUERY
, 0);
709 p
->stats
.pings_sent
++;
711 if (p
->type
== PEER_MULTICAST
) {
712 mcast_exprep
+= p
->mcast
.n_replies_expected
;
713 mcast_timeout
+= (p
->stats
.rtt
* p
->mcast
.n_replies_expected
);
714 } else if (neighborUp(p
)) {
715 /* its alive, expect a reply from it */
717 if (neighborType(p
, request
) == PEER_PARENT
) {
719 parent_timeout
+= p
->stats
.rtt
;
722 sibling_timeout
+= p
->stats
.rtt
;
725 /* Neighbor is dead; ping it anyway, but don't expect a reply */
726 /* log it once at the threshold */
728 if (p
->stats
.logged_state
== PEER_ALIVE
) {
729 debugs(15, 1, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
730 p
->stats
.logged_state
= PEER_DEAD
;
734 p
->stats
.last_query
= squid_curtime
;
737 * keep probe_start == 0 for a multicast peer,
738 * so neighborUp() never says this peer is dead.
741 if ((p
->type
!= PEER_MULTICAST
) && (p
->stats
.probe_start
== 0))
742 p
->stats
.probe_start
= squid_curtime
;
745 if ((first_ping
= first_ping
->next
) == NULL
)
746 first_ping
= Config
.peers
;
749 * How many replies to expect?
751 *exprep
= parent_exprep
+ sibling_exprep
+ mcast_exprep
;
754 * If there is a configured timeout, use it
756 if (Config
.Timeout
.icp_query
)
757 *timeout
= Config
.Timeout
.icp_query
;
761 *timeout
= 2 * parent_timeout
/ parent_exprep
;
762 else if (mcast_exprep
)
763 *timeout
= 2 * mcast_timeout
/ mcast_exprep
;
765 *timeout
= 2 * sibling_timeout
/ sibling_exprep
;
767 *timeout
= 2000; /* 2 seconds */
769 if (Config
.Timeout
.icp_query_max
)
770 if (*timeout
> Config
.Timeout
.icp_query_max
)
771 *timeout
= Config
.Timeout
.icp_query_max
;
773 if (*timeout
< Config
.Timeout
.icp_query_min
)
774 *timeout
= Config
.Timeout
.icp_query_min
;
780 /* lookup the digest of a given peer */
782 peerDigestLookup(peer
* p
, HttpRequest
* request
)
784 #if USE_CACHE_DIGESTS
785 const cache_key
*key
= request
? storeKeyPublicByRequest(request
) : NULL
;
788 debugs(15, 5, "peerDigestLookup: peer " << p
->host
);
789 /* does the peeer have a valid digest? */
792 debugs(15, 5, "peerDigestLookup: gone!");
794 } else if (!peerHTTPOkay(p
, request
)) {
795 debugs(15, 5, "peerDigestLookup: !peerHTTPOkay");
797 } else if (!p
->digest
->flags
.needed
) {
798 debugs(15, 5, "peerDigestLookup: note need");
799 peerDigestNeeded(p
->digest
);
801 } else if (!p
->digest
->flags
.usable
) {
802 debugs(15, 5, "peerDigestLookup: !ready && " << (p
->digest
->flags
.requested
? "" : "!") << "requested");
806 debugs(15, 5, "peerDigestLookup: OK to lookup peer " << p
->host
);
807 assert(p
->digest
->cd
);
808 /* does digest predict a hit? */
810 if (!cacheDigestTest(p
->digest
->cd
, key
))
813 debugs(15, 5, "peerDigestLookup: peer " << p
->host
<< " says HIT!");
822 /* select best peer based on cache digests */
824 neighborsDigestSelect(HttpRequest
* request
)
827 #if USE_CACHE_DIGESTS
829 const cache_key
*key
;
831 int choice_count
= 0;
832 int ichoice_count
= 0;
837 if (!request
->flags
.hierarchical
)
840 key
= storeKeyPublicByRequest(request
);
842 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
851 lookup
= peerDigestLookup(p
, request
);
853 if (lookup
== LOOKUP_NONE
)
858 if (lookup
== LOOKUP_MISS
)
861 p_rtt
= netdbHostRtt(p
->host
);
863 debugs(15, 5, "neighborsDigestSelect: peer " << p
->host
<< " rtt: " << p_rtt
);
865 /* is this peer better than others in terms of rtt ? */
866 if (!best_p
|| (p_rtt
&& p_rtt
< best_rtt
)) {
870 if (p_rtt
) /* informative choice (aka educated guess) */
873 debugs(15, 4, "neighborsDigestSelect: peer " << p
->host
<< " leads with rtt " << best_rtt
);
877 debugs(15, 4, "neighborsDigestSelect: choices: " << choice_count
<< " (" << ichoice_count
<< ")");
878 peerNoteDigestLookup(request
, best_p
,
879 best_p
? LOOKUP_HIT
: (choice_count
? LOOKUP_MISS
: LOOKUP_NONE
));
880 request
->hier
.n_choices
= choice_count
;
881 request
->hier
.n_ichoices
= ichoice_count
;
888 peerNoteDigestLookup(HttpRequest
* request
, peer
* p
, lookup_t lookup
)
890 #if USE_CACHE_DIGESTS
892 strncpy(request
->hier
.cd_host
, p
->host
, sizeof(request
->hier
.cd_host
));
894 *request
->hier
.cd_host
= '\0';
896 request
->hier
.cd_lookup
= lookup
;
897 debugs(15, 4, "peerNoteDigestLookup: peer " << (p
? p
->host
: "<none>") << ", lookup: " << lookup_t_str
[lookup
] );
902 neighborAlive(peer
* p
, const MemObject
* mem
, const icp_common_t
* header
)
905 p
->stats
.pings_acked
++;
907 if ((icp_opcode
) header
->opcode
<= ICP_END
)
908 p
->icp
.counts
[header
->opcode
]++;
910 p
->icp
.version
= (int) header
->version
;
914 neighborUpdateRtt(peer
* p
, MemObject
* mem
)
916 int rtt
, rtt_av_factor
;
921 if (!mem
->start_ping
.tv_sec
)
924 rtt
= tvSubMsec(mem
->start_ping
, current_time
);
926 if (rtt
< 1 || rtt
> 10000)
929 rtt_av_factor
= RTT_AV_FACTOR
;
931 if (p
->options
.weighted_roundrobin
)
932 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
934 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, p
->stats
.pings_acked
, rtt_av_factor
);
939 neighborAliveHtcp(peer
* p
, const MemObject
* mem
, const htcpReplyData
* htcp
)
942 p
->stats
.pings_acked
++;
943 p
->htcp
.counts
[htcp
->hit
? 1 : 0]++;
944 p
->htcp
.version
= htcp
->version
;
950 neighborCountIgnored(peer
* p
)
955 p
->stats
.ignored_replies
++;
960 static peer
*non_peers
= NULL
;
963 neighborIgnoreNonPeer(const Ip::Address
&from
, icp_opcode opcode
)
967 for (np
= non_peers
; np
; np
= np
->next
) {
968 if (np
->in_addr
!= from
)
971 if (np
->in_addr
.GetPort() != from
.GetPort())
978 np
= (peer
*)xcalloc(1, sizeof(peer
));
980 np
->icp
.port
= from
.GetPort();
981 np
->type
= PEER_NONE
;
982 np
->host
= new char[MAX_IPSTRLEN
];
983 from
.NtoA(np
->host
,MAX_IPSTRLEN
);
984 np
->next
= non_peers
;
988 np
->icp
.counts
[opcode
]++;
990 if (isPowTen(++np
->stats
.ignored_replies
))
991 debugs(15, 1, "WARNING: Ignored " << np
->stats
.ignored_replies
<< " replies from non-peer " << np
->host
);
994 /* ignoreMulticastReply
996 * * We want to ignore replies from multicast peers if the
997 * * cache_host_domain rules would normally prevent the peer
1001 ignoreMulticastReply(peer
* p
, MemObject
* mem
)
1006 if (!p
->options
.mcast_responder
)
1009 if (peerHTTPOkay(p
, mem
->request
))
1016 * I should attach these records to the entry. We take the first
1017 * hit we get our wait until everyone misses. The timeout handler
1018 * call needs to nip this shopping list or call one of the misses.
1020 * If a hit process is already started, then sobeit
1023 neighborsUdpAck(const cache_key
* key
, icp_common_t
* header
, const Ip::Address
&from
)
1027 MemObject
*mem
= NULL
;
1028 peer_t ntype
= PEER_NONE
;
1029 icp_opcode opcode
= (icp_opcode
) header
->opcode
;
1031 debugs(15, 6, "neighborsUdpAck: opcode " << opcode
<< " '" << storeKeyText(key
) << "'");
1033 if (NULL
!= (entry
= Store::Root().get(key
)))
1034 mem
= entry
->mem_obj
;
1036 if ((p
= whichPeer(from
)))
1037 neighborAlive(p
, mem
, header
);
1039 if (opcode
> ICP_END
)
1042 const char *opcode_d
= icp_opcode_str
[opcode
];
1045 neighborUpdateRtt(p
, mem
);
1047 /* Does the entry exist? */
1048 if (NULL
== entry
) {
1049 debugs(12, 3, "neighborsUdpAck: Cache key '" << storeKeyText(key
) << "' not found");
1050 neighborCountIgnored(p
);
1054 /* check if someone is already fetching it */
1055 if (EBIT_TEST(entry
->flags
, ENTRY_DISPATCHED
)) {
1056 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1057 neighborCountIgnored(p
);
1062 debugs(15, 2, "Ignoring " << opcode_d
<< " for missing mem_obj: " << storeKeyText(key
));
1063 neighborCountIgnored(p
);
1067 if (entry
->ping_status
!= PING_WAITING
) {
1068 debugs(15, 2, "neighborsUdpAck: Late " << opcode_d
<< " for " << storeKeyText(key
));
1069 neighborCountIgnored(p
);
1073 if (entry
->lock_count
== 0) {
1074 debugs(12, 1, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1075 neighborCountIgnored(p
);
1079 debugs(15, 3, "neighborsUdpAck: " << opcode_d
<< " for '" << storeKeyText(key
) << "' from " << (p
? p
->host
: "source") << " ");
1082 ntype
= neighborType(p
, mem
->request
);
1085 if (ignoreMulticastReply(p
, mem
)) {
1086 neighborCountIgnored(p
);
1087 } else if (opcode
== ICP_MISS
) {
1089 neighborIgnoreNonPeer(from
, opcode
);
1091 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
1093 } else if (opcode
== ICP_HIT
) {
1095 neighborIgnoreNonPeer(from
, opcode
);
1097 header
->opcode
= ICP_HIT
;
1098 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
1100 } else if (opcode
== ICP_DECHO
) {
1102 neighborIgnoreNonPeer(from
, opcode
);
1103 } else if (ntype
== PEER_SIBLING
) {
1104 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
1105 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
1107 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
1109 } else if (opcode
== ICP_SECHO
) {
1111 debugs(15, 1, "Ignoring SECHO from neighbor " << p
->host
);
1112 neighborCountIgnored(p
);
1114 debugs(15, 1, "Unsolicited SECHO from " << from
);
1116 } else if (opcode
== ICP_DENIED
) {
1118 neighborIgnoreNonPeer(from
, opcode
);
1119 } else if (p
->stats
.pings_acked
> 100) {
1120 if (100 * p
->icp
.counts
[ICP_DENIED
] / p
->stats
.pings_acked
> 95) {
1121 debugs(15, 0, "95%% of replies from '" << p
->host
<< "' are UDP_DENIED");
1122 debugs(15, 0, "Disabling '" << p
->host
<< "', please check your configuration.");
1126 neighborCountIgnored(p
);
1129 } else if (opcode
== ICP_MISS_NOFETCH
) {
1130 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
1132 debugs(15, 0, "neighborsUdpAck: Unexpected ICP reply: " << opcode_d
);
1137 peerFindByName(const char *name
)
1141 for (p
= Config
.peers
; p
; p
= p
->next
) {
1142 if (!strcasecmp(name
, p
->name
))
1150 peerFindByNameAndPort(const char *name
, unsigned short port
)
1154 for (p
= Config
.peers
; p
; p
= p
->next
) {
1155 if (strcasecmp(name
, p
->name
))
1158 if (port
!= p
->http_port
)
1168 neighborUp(const peer
* p
)
1171 if (!peerProbeConnect((peer
*) p
)) {
1172 debugs(15, 8, "neighborUp: DOWN (probed): " << p
->host
<< " (" << p
->in_addr
<< ")");
1178 * The peer can not be UP if we don't have any IP addresses
1181 if (0 == p
->n_addresses
) {
1182 debugs(15, 8, "neighborUp: DOWN (no-ip): " << p
->host
<< " (" << p
->in_addr
<< ")");
1186 if (p
->options
.no_query
) {
1187 debugs(15, 8, "neighborUp: UP (no-query): " << p
->host
<< " (" << p
->in_addr
<< ")");
1191 if (p
->stats
.probe_start
!= 0 &&
1192 squid_curtime
- p
->stats
.probe_start
> Config
.Timeout
.deadPeer
) {
1193 debugs(15, 8, "neighborUp: DOWN (dead): " << p
->host
<< " (" << p
->in_addr
<< ")");
1197 debugs(15, 8, "neighborUp: UP: " << p
->host
<< " (" << p
->in_addr
<< ")");
1202 peerDestroy(void *data
)
1204 peer
*p
= (peer
*)data
;
1206 struct _domain_ping
*l
= NULL
;
1208 struct _domain_ping
*nl
= NULL
;
1213 for (l
= p
->peer_domain
; l
; l
= nl
) {
1215 safe_free(l
->domain
);
1221 safe_free(p
->domain
);
1222 #if USE_CACHE_DIGESTS
1224 cbdataReferenceDone(p
->digest
);
1229 peerNoteDigestGone(peer
* p
)
1231 #if USE_CACHE_DIGESTS
1232 cbdataReferenceDone(p
->digest
);
1237 peerDNSConfigure(const ipcache_addrs
*ia
, const DnsLookupDetails
&, void *data
)
1239 peer
*p
= (peer
*)data
;
1243 if (p
->n_addresses
== 0) {
1244 debugs(15, 1, "Configuring " << neighborTypeStr(p
) << " " << p
->host
<< "/" << p
->http_port
<< "/" << p
->icp
.port
);
1246 if (p
->type
== PEER_MULTICAST
)
1247 debugs(15, 1, " Multicast TTL = " << p
->mcast
.ttl
);
1253 debugs(0, 0, "WARNING: DNS lookup for '" << p
->host
<< "' failed!");
1257 if ((int) ia
->count
< 1) {
1258 debugs(0, 0, "WARNING: No IP address found for '" << p
->host
<< "'!");
1262 p
->tcp_up
= p
->connect_fail_limit
;
1264 for (j
= 0; j
< (int) ia
->count
&& j
< PEER_MAX_ADDRESSES
; j
++) {
1265 p
->addresses
[j
] = ia
->in_addrs
[j
];
1266 debugs(15, 2, "--> IP address #" << j
<< ": " << p
->addresses
[j
]);
1270 p
->in_addr
.SetEmpty();
1271 p
->in_addr
= p
->addresses
[0];
1272 p
->in_addr
.SetPort(p
->icp
.port
);
1274 if (p
->type
== PEER_MULTICAST
)
1275 peerCountMcastPeersSchedule(p
, 10);
1278 if (p
->type
!= PEER_MULTICAST
)
1279 if (!p
->options
.no_netdb_exchange
)
1280 eventAddIsh("netdbExchangeStart", netdbExchangeStart
, p
, 30.0, 1);
1286 peerRefreshDNS(void *data
)
1290 if (eventFind(peerRefreshDNS
, NULL
))
1291 eventDelete(peerRefreshDNS
, NULL
);
1293 if (!data
&& 0 == stat5minClientRequests()) {
1294 /* no recent client traffic, wait a bit */
1295 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 180.0, 1);
1299 for (p
= Config
.peers
; p
; p
= p
->next
)
1300 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1302 /* Reconfigure the peers every hour */
1303 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 3600.0, 1);
1307 peerConnectFailedSilent(peer
* p
)
1309 p
->stats
.last_connect_failure
= squid_curtime
;
1312 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<<
1320 debugs(15, 1, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
1321 p
->stats
.logged_state
= PEER_DEAD
;
1326 peerConnectFailed(peer
*p
)
1328 debugs(15, 1, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " failed");
1329 peerConnectFailedSilent(p
);
1333 peerConnectSucceded(peer
* p
)
1336 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " succeded");
1337 p
->tcp_up
= p
->connect_fail_limit
; // NP: so peerAlive(p) works properly.
1339 if (!p
->n_addresses
)
1340 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1342 p
->tcp_up
= p
->connect_fail_limit
;
1345 /// called by Comm when test_fd is closed while connect is in progress
1347 peerProbeClosed(int fd
, void *data
)
1349 peer
*p
= (peer
*)data
;
1351 // it is a failure because we failed to connect
1352 peerConnectFailedSilent(p
);
1356 peerProbeConnectTimeout(int fd
, void *data
)
1358 peer
* p
= (peer
*)data
;
1359 comm_remove_close_handler(fd
, &peerProbeClosed
, p
);
1362 peerConnectFailedSilent(p
);
1366 * peerProbeConnect will be called on dead peers by neighborUp
1369 peerProbeConnect(peer
* p
)
1372 time_t ctimeout
= p
->connect_timeout
> 0 ? p
->connect_timeout
1373 : Config
.Timeout
.peer_connect
;
1374 int ret
= squid_curtime
- p
->stats
.last_connect_failure
> ctimeout
* 10;
1376 if (p
->test_fd
!= -1)
1377 return ret
;/* probe already running */
1379 if (squid_curtime
- p
->stats
.last_connect_probe
== 0)
1380 return ret
;/* don't probe to often */
1382 Ip::Address
temp(getOutgoingAddr(NULL
,p
));
1384 // if IPv6 is disabled try to force IPv4-only outgoing.
1385 if (!Ip::EnableIpv6
&& !temp
.SetIPv4()) {
1386 debugs(50, DBG_IMPORTANT
, "WARNING: IPv6 is disabled. Failed to use " << temp
<< " to probe " << p
->host
);
1390 // if IPv6 is split-stack, prefer IPv4
1391 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
) {
1392 // NP: This is not a great choice of default,
1393 // but with the current Internet being IPv4-majority has a higher success rate.
1394 // if setting to IPv4 fails we dont care, that just means to use IPv6 outgoing.
1398 fd
= comm_open(SOCK_STREAM
, IPPROTO_TCP
, temp
, COMM_NONBLOCKING
, p
->host
);
1403 comm_add_close_handler(fd
, &peerProbeClosed
, p
);
1404 commSetTimeout(fd
, ctimeout
, peerProbeConnectTimeout
, p
);
1408 p
->stats
.last_connect_probe
= squid_curtime
;
1410 commConnectStart(p
->test_fd
,
1413 peerProbeConnectDone
,
1420 peerProbeConnectDone(int fd
, const DnsLookupDetails
&, comm_err_t status
, int xerrno
, void *data
)
1422 peer
*p
= (peer
*)data
;
1424 if (status
== COMM_OK
) {
1425 peerConnectSucceded(p
);
1427 peerConnectFailedSilent(p
);
1430 comm_remove_close_handler(fd
, &peerProbeClosed
, p
);
1437 peerCountMcastPeersSchedule(peer
* p
, time_t when
)
1439 if (p
->mcast
.flags
.count_event_pending
)
1442 eventAdd("peerCountMcastPeersStart",
1443 peerCountMcastPeersStart
,
1447 p
->mcast
.flags
.count_event_pending
= 1;
1451 peerCountMcastPeersStart(void *data
)
1453 peer
*p
= (peer
*)data
;
1457 icp_common_t
*query
;
1459 LOCAL_ARRAY(char, url
, MAX_URL
);
1460 assert(p
->type
== PEER_MULTICAST
);
1461 p
->mcast
.flags
.count_event_pending
= 0;
1462 snprintf(url
, MAX_URL
, "http://");
1463 p
->in_addr
.ToURL(url
+7, MAX_URL
-8 );
1465 fake
= storeCreateEntry(url
, url
, request_flags(), METHOD_GET
);
1466 HttpRequest
*req
= HttpRequest::CreateFromUrl(url
);
1467 psstate
= new ps_state
;
1468 psstate
->request
= HTTPMSGLOCK(req
);
1469 psstate
->entry
= fake
;
1470 psstate
->callback
= NULL
;
1471 psstate
->callback_data
= cbdataReference(p
);
1472 psstate
->ping
.start
= current_time
;
1473 mem
= fake
->mem_obj
;
1474 mem
->request
= HTTPMSGLOCK(psstate
->request
);
1475 mem
->start_ping
= current_time
;
1476 mem
->ping_reply_callback
= peerCountHandleIcpReply
;
1477 mem
->ircb_data
= psstate
;
1478 mcastSetTtl(theOutIcpConnection
, p
->mcast
.ttl
);
1479 p
->mcast
.id
= mem
->id
;
1480 reqnum
= icpSetCacheKey((const cache_key
*)fake
->key
);
1481 query
= _icp_common_t::createMessage(ICP_QUERY
, 0, url
, reqnum
, 0);
1482 icpUdpSend(theOutIcpConnection
,
1487 fake
->ping_status
= PING_WAITING
;
1488 eventAdd("peerCountMcastPeersDone",
1489 peerCountMcastPeersDone
,
1491 Config
.Timeout
.mcast_icp_query
/ 1000.0, 1);
1492 p
->mcast
.flags
.counting
= 1;
1493 peerCountMcastPeersSchedule(p
, MCAST_COUNT_RATE
);
1497 peerCountMcastPeersDone(void *data
)
1499 ps_state
*psstate
= (ps_state
*)data
;
1500 StoreEntry
*fake
= psstate
->entry
;
1502 if (cbdataReferenceValid(psstate
->callback_data
)) {
1503 peer
*p
= (peer
*)psstate
->callback_data
;
1504 p
->mcast
.flags
.counting
= 0;
1505 p
->mcast
.avg_n_members
= Math::doubleAverage(p
->mcast
.avg_n_members
, (double) psstate
->ping
.n_recv
, ++p
->mcast
.n_times_counted
, 10);
1506 debugs(15, 1, "Group " << p
->host
<< ": " << psstate
->ping
.n_recv
<<
1507 " replies, "<< std::setw(4)<< std::setprecision(2) <<
1508 p
->mcast
.avg_n_members
<<" average, RTT " << p
->stats
.rtt
);
1509 p
->mcast
.n_replies_expected
= (int) p
->mcast
.avg_n_members
;
1512 cbdataReferenceDone(psstate
->callback_data
);
1514 EBIT_SET(fake
->flags
, ENTRY_ABORTED
);
1515 HTTPMSGUNLOCK(fake
->mem_obj
->request
);
1516 fake
->releaseRequest();
1518 HTTPMSGUNLOCK(psstate
->request
);
1519 cbdataFree(psstate
);
1523 peerCountHandleIcpReply(peer
* p
, peer_t type
, protocol_t proto
, void *hdrnotused
, void *data
)
1527 ps_state
*psstate
= (ps_state
*)data
;
1528 StoreEntry
*fake
= psstate
->entry
;
1529 MemObject
*mem
= fake
->mem_obj
;
1530 int rtt
= tvSubMsec(mem
->start_ping
, current_time
);
1531 assert(proto
== PROTO_ICP
);
1534 psstate
->ping
.n_recv
++;
1535 rtt_av_factor
= RTT_AV_FACTOR
;
1537 if (p
->options
.weighted_roundrobin
)
1538 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
1540 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, psstate
->ping
.n_recv
, rtt_av_factor
);
1544 neighborDumpPeers(StoreEntry
* sentry
)
1546 dump_peers(sentry
, Config
.peers
);
1550 neighborDumpNonPeers(StoreEntry
* sentry
)
1552 dump_peers(sentry
, non_peers
);
1556 dump_peer_options(StoreEntry
* sentry
, peer
* p
)
1558 if (p
->options
.proxy_only
)
1559 storeAppendPrintf(sentry
, " proxy-only");
1561 if (p
->options
.no_query
)
1562 storeAppendPrintf(sentry
, " no-query");
1564 if (p
->options
.background_ping
)
1565 storeAppendPrintf(sentry
, " background-ping");
1567 if (p
->options
.no_digest
)
1568 storeAppendPrintf(sentry
, " no-digest");
1570 if (p
->options
.default_parent
)
1571 storeAppendPrintf(sentry
, " default");
1573 if (p
->options
.roundrobin
)
1574 storeAppendPrintf(sentry
, " round-robin");
1576 if (p
->options
.carp
)
1577 storeAppendPrintf(sentry
, " carp");
1579 if (p
->options
.userhash
)
1580 storeAppendPrintf(sentry
, " userhash");
1582 if (p
->options
.userhash
)
1583 storeAppendPrintf(sentry
, " sourcehash");
1585 if (p
->options
.weighted_roundrobin
)
1586 storeAppendPrintf(sentry
, " weighted-round-robin");
1588 if (p
->options
.mcast_responder
)
1589 storeAppendPrintf(sentry
, " multicast-responder");
1591 #if PEER_MULTICAST_SIBLINGS
1592 if (p
->options
.mcast_siblings
)
1593 storeAppendPrintf(sentry
, " multicast-siblings");
1597 storeAppendPrintf(sentry
, " weight=%d", p
->weight
);
1599 if (p
->options
.closest_only
)
1600 storeAppendPrintf(sentry
, " closest-only");
1603 if (p
->options
.htcp
)
1604 storeAppendPrintf(sentry
, " htcp");
1605 if (p
->options
.htcp_oldsquid
)
1606 storeAppendPrintf(sentry
, " htcp-oldsquid");
1607 if (p
->options
.htcp_no_clr
)
1608 storeAppendPrintf(sentry
, " htcp-no-clr");
1609 if (p
->options
.htcp_no_purge_clr
)
1610 storeAppendPrintf(sentry
, " htcp-no-purge-clr");
1611 if (p
->options
.htcp_only_clr
)
1612 storeAppendPrintf(sentry
, " htcp-only-clr");
1615 if (p
->options
.no_netdb_exchange
)
1616 storeAppendPrintf(sentry
, " no-netdb-exchange");
1620 if (p
->options
.no_delay
)
1621 storeAppendPrintf(sentry
, " no-delay");
1626 storeAppendPrintf(sentry
, " login=%s", p
->login
);
1628 if (p
->mcast
.ttl
> 0)
1629 storeAppendPrintf(sentry
, " ttl=%d", p
->mcast
.ttl
);
1631 if (p
->connect_timeout
> 0)
1632 storeAppendPrintf(sentry
, " connect-timeout=%d", (int) p
->connect_timeout
);
1634 if (p
->connect_fail_limit
!= PEER_TCP_MAGIC_COUNT
)
1635 storeAppendPrintf(sentry
, " connect-fail-limit=%d", p
->connect_fail_limit
);
1637 #if USE_CACHE_DIGESTS
1640 storeAppendPrintf(sentry
, " digest-url=%s", p
->digest_url
);
1644 if (p
->options
.allow_miss
)
1645 storeAppendPrintf(sentry
, " allow-miss");
1647 if (p
->options
.no_tproxy
)
1648 storeAppendPrintf(sentry
, " no-tproxy");
1650 if (p
->max_conn
> 0)
1651 storeAppendPrintf(sentry
, " max-conn=%d", p
->max_conn
);
1653 if (p
->options
.originserver
)
1654 storeAppendPrintf(sentry
, " originserver");
1657 storeAppendPrintf(sentry
, " forceddomain=%s", p
->domain
);
1659 if (p
->connection_auth
== 0)
1660 storeAppendPrintf(sentry
, " connection-auth=off");
1661 else if (p
->connection_auth
== 1)
1662 storeAppendPrintf(sentry
, " connection-auth=on");
1663 else if (p
->connection_auth
== 2)
1664 storeAppendPrintf(sentry
, " connection-auth=auto");
1666 storeAppendPrintf(sentry
, "\n");
1670 dump_peers(StoreEntry
* sentry
, peer
* peers
)
1673 char ntoabuf
[MAX_IPSTRLEN
];
1674 struct _domain_ping
*d
= NULL
;
1679 storeAppendPrintf(sentry
, "There are no neighbors installed.\n");
1681 for (e
= peers
; e
; e
= e
->next
) {
1682 assert(e
->host
!= NULL
);
1683 storeAppendPrintf(sentry
, "\n%-11.11s: %s\n",
1686 storeAppendPrintf(sentry
, "Host : %s/%d/%d\n",
1690 storeAppendPrintf(sentry
, "Flags :");
1691 dump_peer_options(sentry
, e
);
1693 for (i
= 0; i
< e
->n_addresses
; i
++) {
1694 storeAppendPrintf(sentry
, "Address[%d] : %s\n", i
,
1695 e
->addresses
[i
].NtoA(ntoabuf
,MAX_IPSTRLEN
) );
1698 storeAppendPrintf(sentry
, "Status : %s\n",
1699 neighborUp(e
) ? "Up" : "Down");
1700 storeAppendPrintf(sentry
, "FETCHES : %d\n", e
->stats
.fetches
);
1701 storeAppendPrintf(sentry
, "OPEN CONNS : %d\n", e
->stats
.conn_open
);
1702 storeAppendPrintf(sentry
, "AVG RTT : %d msec\n", e
->stats
.rtt
);
1704 if (!e
->options
.no_query
) {
1705 storeAppendPrintf(sentry
, "LAST QUERY : %8d seconds ago\n",
1706 (int) (squid_curtime
- e
->stats
.last_query
));
1708 if (e
->stats
.last_reply
> 0)
1709 storeAppendPrintf(sentry
, "LAST REPLY : %8d seconds ago\n",
1710 (int) (squid_curtime
- e
->stats
.last_reply
));
1712 storeAppendPrintf(sentry
, "LAST REPLY : none received\n");
1714 storeAppendPrintf(sentry
, "PINGS SENT : %8d\n", e
->stats
.pings_sent
);
1716 storeAppendPrintf(sentry
, "PINGS ACKED: %8d %3d%%\n",
1717 e
->stats
.pings_acked
,
1718 Math::intPercent(e
->stats
.pings_acked
, e
->stats
.pings_sent
));
1721 storeAppendPrintf(sentry
, "IGNORED : %8d %3d%%\n", e
->stats
.ignored_replies
, Math::intPercent(e
->stats
.ignored_replies
, e
->stats
.pings_acked
));
1723 if (!e
->options
.no_query
) {
1724 storeAppendPrintf(sentry
, "Histogram of PINGS ACKED:\n");
1727 if (e
->options
.htcp
) {
1728 storeAppendPrintf(sentry
, "\tMisses\t%8d %3d%%\n",
1730 Math::intPercent(e
->htcp
.counts
[0], e
->stats
.pings_acked
));
1731 storeAppendPrintf(sentry
, "\tHits\t%8d %3d%%\n",
1733 Math::intPercent(e
->htcp
.counts
[1], e
->stats
.pings_acked
));
1737 for (op
= ICP_INVALID
; op
< ICP_END
; ++op
) {
1738 if (e
->icp
.counts
[op
] == 0)
1741 storeAppendPrintf(sentry
, " %12.12s : %8d %3d%%\n",
1744 Math::intPercent(e
->icp
.counts
[op
], e
->stats
.pings_acked
));
1755 if (e
->stats
.last_connect_failure
) {
1756 storeAppendPrintf(sentry
, "Last failed connect() at: %s\n",
1757 mkhttpdlogtime(&(e
->stats
.last_connect_failure
)));
1760 if (e
->peer_domain
!= NULL
) {
1761 storeAppendPrintf(sentry
, "DOMAIN LIST: ");
1763 for (d
= e
->peer_domain
; d
; d
= d
->next
) {
1764 storeAppendPrintf(sentry
, "%s%s ",
1765 d
->do_ping
? null_string
: "!", d
->domain
);
1768 storeAppendPrintf(sentry
, "\n");
1771 storeAppendPrintf(sentry
, "keep-alive ratio: %d%%\n", Math::intPercent(e
->stats
.n_keepalives_recv
, e
->stats
.n_keepalives_sent
));
1777 neighborsHtcpReply(const cache_key
* key
, htcpReplyData
* htcp
, const Ip::Address
&from
)
1779 StoreEntry
*e
= Store::Root().get(key
);
1780 MemObject
*mem
= NULL
;
1782 peer_t ntype
= PEER_NONE
;
1783 debugs(15, 6, "neighborsHtcpReply: " <<
1784 (htcp
->hit
? "HIT" : "MISS") << " " <<
1785 storeKeyText(key
) );
1790 if ((p
= whichPeer(from
)))
1791 neighborAliveHtcp(p
, mem
, htcp
);
1793 /* Does the entry exist? */
1795 debugs(12, 3, "neighyborsHtcpReply: Cache key '" << storeKeyText(key
) << "' not found");
1796 neighborCountIgnored(p
);
1800 /* check if someone is already fetching it */
1801 if (EBIT_TEST(e
->flags
, ENTRY_DISPATCHED
)) {
1802 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1803 neighborCountIgnored(p
);
1808 debugs(15, 2, "Ignoring reply for missing mem_obj: " << storeKeyText(key
));
1809 neighborCountIgnored(p
);
1813 if (e
->ping_status
!= PING_WAITING
) {
1814 debugs(15, 2, "neighborsUdpAck: Entry " << storeKeyText(key
) << " is not PING_WAITING");
1815 neighborCountIgnored(p
);
1819 if (e
->lock_count
== 0) {
1820 debugs(12, 1, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1821 neighborCountIgnored(p
);
1826 ntype
= neighborType(p
, mem
->request
);
1827 neighborUpdateRtt(p
, mem
);
1830 if (ignoreMulticastReply(p
, mem
)) {
1831 neighborCountIgnored(p
);
1835 debugs(15, 3, "neighborsHtcpReply: e = " << e
);
1836 mem
->ping_reply_callback(p
, ntype
, PROTO_HTCP
, htcp
, mem
->ircb_data
);
1840 * Send HTCP CLR messages to all peers configured to receive them.
1843 neighborsHtcpClear(StoreEntry
* e
, const char *uri
, HttpRequest
* req
, const HttpRequestMethod
&method
, htcp_clr_reason reason
)
1848 for (p
= Config
.peers
; p
; p
= p
->next
) {
1849 if (!p
->options
.htcp
) {
1852 if (p
->options
.htcp_no_clr
) {
1855 if (p
->options
.htcp_no_purge_clr
&& reason
== HTCP_CLR_PURGE
) {
1858 debugs(15, 3, "neighborsHtcpClear: sending CLR to " << p
->in_addr
.ToURL(buf
, 128));
1859 htcpClear(e
, uri
, req
, method
, p
, reason
);