2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 15 Neighbor Routines */
12 #include "acl/FilledChecklist.h"
13 #include "anyp/PortCfg.h"
14 #include "base/EnumIterator.h"
15 #include "CacheDigest.h"
16 #include "CachePeer.h"
17 #include "comm/Connection.h"
18 #include "comm/ConnOpener.h"
19 #include "DebugMessages.h"
24 #include "HttpRequest.h"
25 #include "icmp/net_db.h"
28 #include "ip/Address.h"
31 #include "MemObject.h"
32 #include "mgr/Registration.h"
33 #include "multicast.h"
34 #include "neighbors.h"
35 #include "NeighborTypeDomainList.h"
37 #include "PeerDigest.h"
38 #include "PeerPoolMgr.h"
39 #include "PeerSelectState.h"
40 #include "RequestFlags.h"
41 #include "SquidConfig.h"
42 #include "SquidMath.h"
43 #include "SquidTime.h"
46 #include "store_key_md5.h"
49 /* count mcast group peers every 15 minutes */
50 #define MCAST_COUNT_RATE 900
52 bool peerAllowedToUse(const CachePeer
*, PeerSelector
*);
53 static int peerWouldBePinged(const CachePeer
*, PeerSelector
*);
54 static void neighborRemove(CachePeer
*);
55 static void neighborAlive(CachePeer
*, const MemObject
*, const icp_common_t
*);
57 static void neighborAliveHtcp(CachePeer
*, const MemObject
*, const HtcpReplyData
*);
59 static void neighborCountIgnored(CachePeer
*);
60 static void peerRefreshDNS(void *);
61 static IPH peerDNSConfigure
;
62 static void peerProbeConnect(CachePeer
*, const bool reprobeIfBusy
= false);
63 static CNCB peerProbeConnectDone
;
64 static void peerCountMcastPeersDone(void *data
);
65 static void peerCountMcastPeersStart(void *data
);
66 static void peerCountMcastPeersSchedule(CachePeer
* p
, time_t when
);
67 static void peerCountMcastPeersAbort(PeerSelector
*);
68 static void peerCountMcastPeersCreateAndSend(CachePeer
*p
);
69 static IRCB peerCountHandleIcpReply
;
71 static void neighborIgnoreNonPeer(const Ip::Address
&, icp_opcode
);
72 static OBJH neighborDumpPeers
;
73 static OBJH neighborDumpNonPeers
;
74 static void dump_peers(StoreEntry
* sentry
, CachePeer
* peers
);
76 static unsigned short echo_port
;
78 static int NLateReplies
= 0;
79 static CachePeer
*first_ping
= NULL
;
82 neighborTypeStr(const CachePeer
* p
)
84 if (p
->type
== PEER_NONE
)
87 if (p
->type
== PEER_SIBLING
)
90 if (p
->type
== PEER_MULTICAST
)
91 return "Multicast Group";
97 whichPeer(const Ip::Address
&from
)
102 debugs(15, 3, "whichPeer: from " << from
);
104 for (p
= Config
.peers
; p
; p
= p
->next
) {
105 for (j
= 0; j
< p
->n_addresses
; ++j
) {
106 if (from
== p
->addresses
[j
] && from
.port() == p
->icp
.port
) {
116 neighborType(const CachePeer
* p
, const AnyP::Uri
&url
)
119 const NeighborTypeDomainList
*d
= NULL
;
121 for (d
= p
->typelist
; d
; d
= d
->next
) {
122 if (0 == matchDomainName(url
.host(), d
->domain
))
123 if (d
->type
!= PEER_NONE
)
126 #if PEER_MULTICAST_SIBLINGS
127 if (p
->type
== PEER_MULTICAST
)
128 if (p
->options
.mcast_siblings
)
136 * \return Whether it is appropriate to fetch REQUEST from PEER.
139 peerAllowedToUse(const CachePeer
* p
, PeerSelector
* ps
)
142 HttpRequest
*request
= ps
->request
;
143 assert(request
!= NULL
);
145 if (neighborType(p
, request
->url
) == PEER_SIBLING
) {
146 #if PEER_MULTICAST_SIBLINGS
147 if (p
->type
== PEER_MULTICAST
&& p
->options
.mcast_siblings
&&
148 (request
->flags
.noCache
|| request
->flags
.refresh
|| request
->flags
.loopDetected
|| request
->flags
.needValidation
))
149 debugs(15, 2, "peerAllowedToUse(" << p
->name
<< ", " << request
->url
.authority() << ") : multicast-siblings optimization match");
151 if (request
->flags
.noCache
)
154 if (request
->flags
.refresh
)
157 if (request
->flags
.loopDetected
)
160 if (request
->flags
.needValidation
)
164 // CONNECT requests are proxy requests. Not to be forwarded to origin servers.
165 // Unless the destination port matches, in which case we MAY perform a 'DIRECT' to this CachePeer.
166 if (p
->options
.originserver
&& request
->method
== Http::METHOD_CONNECT
&& request
->url
.port() != p
->http_port
)
169 if (p
->access
== NULL
)
172 ACLFilledChecklist
checklist(p
->access
, request
, NULL
);
173 checklist
.al
= ps
->al
;
174 if (ps
->al
&& ps
->al
->reply
) {
175 checklist
.reply
= ps
->al
->reply
.getRaw();
176 HTTPMSGLOCK(checklist
.reply
);
178 checklist
.syncAle(request
, nullptr);
179 return checklist
.fastCheck().allowed();
182 /* Return TRUE if it is okay to send an ICP request to this CachePeer. */
184 peerWouldBePinged(const CachePeer
* p
, PeerSelector
* ps
)
187 HttpRequest
*request
= ps
->request
;
189 if (p
->icp
.port
== 0)
192 if (p
->options
.no_query
)
195 if (p
->options
.mcast_responder
)
198 if (p
->n_addresses
== 0)
201 if (p
->options
.background_ping
&& (squid_curtime
- p
->stats
.last_query
< Config
.backgroundPingRate
))
204 /* the case below seems strange, but can happen if the
205 * URL host is on the other side of a firewall */
206 if (p
->type
== PEER_SIBLING
)
207 if (!request
->flags
.hierarchical
)
210 if (!peerAllowedToUse(p
, ps
))
213 /* Ping dead peers every timeout interval */
214 if (squid_curtime
- p
->stats
.last_query
> Config
.Timeout
.deadPeer
)
224 peerCanOpenMore(const CachePeer
*p
)
226 const int effectiveLimit
= p
->max_conn
<= 0 ? Squid_MaxFD
: p
->max_conn
;
227 const int remaining
= effectiveLimit
- p
->stats
.conn_open
;
228 debugs(15, 7, remaining
<< '=' << effectiveLimit
<< '-' << p
->stats
.conn_open
);
229 return remaining
> 0;
233 peerHasConnAvailable(const CachePeer
*p
)
235 // Standby connections can be used without opening new connections.
236 const int standbys
= p
->standby
.pool
? p
->standby
.pool
->count() : 0;
238 // XXX: Some idle pconns can be used without opening new connections.
239 // Complication: Idle pconns cannot be reused for some requests.
240 const int usableIdles
= 0;
242 const int available
= standbys
+ usableIdles
;
243 debugs(15, 7, available
<< '=' << standbys
<< '+' << usableIdles
);
244 return available
> 0;
248 peerConnClosed(CachePeer
*p
)
250 --p
->stats
.conn_open
;
251 if (p
->standby
.waitingForClose
&& peerCanOpenMore(p
)) {
252 p
->standby
.waitingForClose
= false;
253 PeerPoolMgr::Checkpoint(p
->standby
.mgr
, "conn closed");
257 /* Return TRUE if it is okay to send an HTTP request to this CachePeer. */
259 peerHTTPOkay(const CachePeer
* p
, PeerSelector
* ps
)
261 if (!peerCanOpenMore(p
) && !peerHasConnAvailable(p
))
264 if (!peerAllowedToUse(p
, ps
))
274 neighborsCount(PeerSelector
*ps
)
279 for (p
= Config
.peers
; p
; p
= p
->next
)
280 if (peerWouldBePinged(p
, ps
))
283 debugs(15, 3, "neighborsCount: " << count
);
289 getFirstUpParent(PeerSelector
*ps
)
292 HttpRequest
*request
= ps
->request
;
296 for (p
= Config
.peers
; p
; p
= p
->next
) {
300 if (neighborType(p
, request
->url
) != PEER_PARENT
)
303 if (!peerHTTPOkay(p
, ps
))
309 debugs(15, 3, "getFirstUpParent: returning " << (p
? p
->host
: "NULL"));
314 getRoundRobinParent(PeerSelector
*ps
)
317 HttpRequest
*request
= ps
->request
;
322 for (p
= Config
.peers
; p
; p
= p
->next
) {
323 if (!p
->options
.roundrobin
)
326 if (neighborType(p
, request
->url
) != PEER_PARENT
)
329 if (!peerHTTPOkay(p
, ps
))
336 if (p
->weight
== q
->weight
) {
337 if (q
->rr_count
< p
->rr_count
)
339 } else if ( ((double) q
->rr_count
/ q
->weight
) < ((double) p
->rr_count
/ p
->weight
)) {
350 debugs(15, 3, HERE
<< "returning " << (q
? q
->host
: "NULL"));
356 getWeightedRoundRobinParent(PeerSelector
*ps
)
359 HttpRequest
*request
= ps
->request
;
365 for (p
= Config
.peers
; p
; p
= p
->next
) {
366 if (!p
->options
.weighted_roundrobin
)
369 if (neighborType(p
, request
->url
) != PEER_PARENT
)
372 if (!peerHTTPOkay(p
, ps
))
375 if (q
&& q
->rr_count
< p
->rr_count
)
381 if (q
&& q
->rr_count
> 1000000)
382 for (p
= Config
.peers
; p
; p
= p
->next
) {
383 if (!p
->options
.weighted_roundrobin
)
386 if (neighborType(p
, request
->url
) != PEER_PARENT
)
393 weighted_rtt
= (q
->stats
.rtt
- q
->basetime
) / q
->weight
;
395 if (weighted_rtt
< 1)
398 q
->rr_count
+= weighted_rtt
;
400 debugs(15, 3, "getWeightedRoundRobinParent: weighted_rtt " << weighted_rtt
);
403 debugs(15, 3, "getWeightedRoundRobinParent: returning " << (q
? q
->host
: "NULL"));
408 * This gets called every 5 minutes to clear the round-robin counter.
409 * The exact timing is an arbitrary default, set on estimate timing of a
410 * large number of requests in a high-performance environment during the
411 * period. The larger the number of requests between cycled resets the
412 * more balanced the operations.
416 * TODO: Make the reset timing a selectable parameter in squid.conf
419 peerClearRRLoop(void *data
)
422 eventAdd("peerClearRR", peerClearRRLoop
, data
, 5 * 60.0, 0);
426 * This gets called on startup and restart to kick off the CachePeer round-robin
427 * maintenance event. It ensures that no matter how many times its called
428 * no more than one event is scheduled.
431 peerClearRRStart(void)
433 static bool event_added
= false;
435 peerClearRRLoop(NULL
);
441 * Called whenever the round-robin counters need to be reset to a sane state.
442 * So far those times are:
443 * - On startup and reconfigure - to set the counters to sane initial settings.
444 * - When a CachePeer has revived from dead, to prevent the revived CachePeer being
445 * flooded with requests which it has 'missed' during the down period.
451 for (p
= Config
.peers
; p
; p
= p
->next
) {
457 * Perform all actions when a CachePeer is detected revived.
460 peerAlive(CachePeer
*p
)
462 if (p
->stats
.logged_state
== PEER_DEAD
&& p
->tcp_up
) {
463 debugs(15, DBG_IMPORTANT
, "Detected REVIVED " << neighborTypeStr(p
) << ": " << p
->name
);
464 p
->stats
.logged_state
= PEER_ALIVE
;
466 if (p
->standby
.mgr
.valid())
467 PeerPoolMgr::Checkpoint(p
->standby
.mgr
, "revived peer");
470 p
->stats
.last_reply
= squid_curtime
;
471 p
->stats
.probe_start
= 0;
475 getDefaultParent(PeerSelector
*ps
)
478 HttpRequest
*request
= ps
->request
;
482 for (p
= Config
.peers
; p
; p
= p
->next
) {
483 if (neighborType(p
, request
->url
) != PEER_PARENT
)
486 if (!p
->options
.default_parent
)
489 if (!peerHTTPOkay(p
, ps
))
492 debugs(15, 3, "getDefaultParent: returning " << p
->host
);
497 debugs(15, 3, "getDefaultParent: returning NULL");
502 getNextPeer(CachePeer
* p
)
514 neighborRemove(CachePeer
* target
)
517 CachePeer
**P
= NULL
;
537 first_ping
= Config
.peers
;
541 neighborsRegisterWithCacheManager()
543 Mgr::RegisterAction("server_list",
544 "Peer Cache Statistics",
545 neighborDumpPeers
, 0, 1);
547 if (Comm::IsConnOpen(icpIncomingConn
)) {
548 Mgr::RegisterAction("non_peers",
549 "List of Unknown sites sending ICP messages",
550 neighborDumpNonPeers
, 0, 1);
557 struct servent
*sep
= NULL
;
558 const char *me
= getMyHostname();
559 CachePeer
*thisPeer
= NULL
;
560 CachePeer
*next
= NULL
;
562 neighborsRegisterWithCacheManager();
564 if (Comm::IsConnOpen(icpIncomingConn
)) {
566 for (thisPeer
= Config
.peers
; thisPeer
; thisPeer
= next
) {
567 next
= thisPeer
->next
;
569 if (0 != strcmp(thisPeer
->host
, me
))
572 for (AnyP::PortCfgPointer s
= HttpPortList
; s
!= NULL
; s
= s
->next
) {
573 if (thisPeer
->http_port
!= s
->s
.port())
576 debugs(15, DBG_IMPORTANT
, "WARNING: Peer looks like this host." <<
577 Debug::Extra
<< "Ignoring " <<
578 neighborTypeStr(thisPeer
) << " " << thisPeer
->host
<<
579 "/" << thisPeer
->http_port
<< "/" <<
582 neighborRemove(thisPeer
);
587 peerRefreshDNS((void *) 1);
589 sep
= getservbyname("echo", "udp");
590 echo_port
= sep
? ntohs((unsigned short) sep
->s_port
) : 7;
592 first_ping
= Config
.peers
;
596 neighborsUdpPing(HttpRequest
* request
,
603 const char *url
= entry
->url();
604 MemObject
*mem
= entry
->mem_obj
;
609 int queries_sent
= 0;
610 int peers_pinged
= 0;
611 int parent_timeout
= 0, parent_exprep
= 0;
612 int sibling_timeout
= 0, sibling_exprep
= 0;
613 int mcast_timeout
= 0, mcast_exprep
= 0;
615 if (Config
.peers
== NULL
)
618 assert(!entry
->hasDisk());
620 mem
->start_ping
= current_time
;
622 mem
->ping_reply_callback
= callback
;
626 reqnum
= icpSetCacheKey((const cache_key
*)entry
->key
);
628 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
632 debugs(15, 5, "neighborsUdpPing: Peer " << p
->host
);
634 if (!peerWouldBePinged(p
, ps
))
635 continue; /* next CachePeer */
639 debugs(15, 4, "neighborsUdpPing: pinging peer " << p
->host
<< " for '" << url
<< "'");
641 debugs(15, 3, "neighborsUdpPing: key = '" << entry
->getMD5Text() << "'");
643 debugs(15, 3, "neighborsUdpPing: reqnum = " << reqnum
);
646 if (p
->options
.htcp
&& !p
->options
.htcp_only_clr
) {
647 if (Config
.Port
.htcp
<= 0) {
648 debugs(15, DBG_CRITICAL
, "HTCP is disabled! Cannot send HTCP request to peer.");
652 debugs(15, 3, "neighborsUdpPing: sending HTCP query");
653 if (htcpQuery(entry
, request
, p
) <= 0)
654 continue; // unable to send.
658 if (Config
.Port
.icp
<= 0 || !Comm::IsConnOpen(icpOutgoingConn
)) {
659 debugs(15, DBG_CRITICAL
, "ICP is disabled! Cannot send ICP request to peer.");
663 if (p
->type
== PEER_MULTICAST
)
664 mcastSetTtl(icpOutgoingConn
->fd
, p
->mcast
.ttl
);
666 if (p
->icp
.port
== echo_port
) {
667 debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping");
668 // TODO: Get ALE from callback_data if possible.
669 icpCreateAndSend(ICP_DECHO
, 0, url
, reqnum
, 0,
670 icpOutgoingConn
->fd
, p
->in_addr
, nullptr);
674 if (Config
.onoff
.query_icmp
)
675 if (p
->icp
.version
== ICP_VERSION_2
)
676 flags
|= ICP_FLAG_SRC_RTT
;
678 // TODO: Get ALE from callback_data if possible.
679 icpCreateAndSend(ICP_QUERY
, flags
, url
, reqnum
, 0,
680 icpOutgoingConn
->fd
, p
->in_addr
, nullptr);
687 ++ p
->stats
.pings_sent
;
689 if (p
->type
== PEER_MULTICAST
) {
690 mcast_exprep
+= p
->mcast
.n_replies_expected
;
691 mcast_timeout
+= (p
->stats
.rtt
* p
->mcast
.n_replies_expected
);
692 } else if (neighborUp(p
)) {
693 /* its alive, expect a reply from it */
695 if (neighborType(p
, request
->url
) == PEER_PARENT
) {
697 parent_timeout
+= p
->stats
.rtt
;
700 sibling_timeout
+= p
->stats
.rtt
;
703 /* Neighbor is dead; ping it anyway, but don't expect a reply */
704 /* log it once at the threshold */
706 if (p
->stats
.logged_state
== PEER_ALIVE
) {
707 debugs(15, DBG_IMPORTANT
, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
708 p
->stats
.logged_state
= PEER_DEAD
;
712 p
->stats
.last_query
= squid_curtime
;
715 * keep probe_start == 0 for a multicast CachePeer,
716 * so neighborUp() never says this CachePeer is dead.
719 if ((p
->type
!= PEER_MULTICAST
) && (p
->stats
.probe_start
== 0))
720 p
->stats
.probe_start
= squid_curtime
;
723 if ((first_ping
= first_ping
->next
) == NULL
)
724 first_ping
= Config
.peers
;
727 * How many replies to expect?
729 *exprep
= parent_exprep
+ sibling_exprep
+ mcast_exprep
;
732 * If there is a configured timeout, use it
734 if (Config
.Timeout
.icp_query
)
735 *timeout
= Config
.Timeout
.icp_query
;
739 *timeout
= 2 * parent_timeout
/ parent_exprep
;
740 else if (mcast_exprep
)
741 *timeout
= 2 * mcast_timeout
/ mcast_exprep
;
743 *timeout
= 2 * sibling_timeout
/ sibling_exprep
;
745 *timeout
= 2000; /* 2 seconds */
747 if (Config
.Timeout
.icp_query_max
)
748 if (*timeout
> Config
.Timeout
.icp_query_max
)
749 *timeout
= Config
.Timeout
.icp_query_max
;
751 if (*timeout
< Config
.Timeout
.icp_query_min
)
752 *timeout
= Config
.Timeout
.icp_query_min
;
758 /* lookup the digest of a given CachePeer */
760 peerDigestLookup(CachePeer
* p
, PeerSelector
* ps
)
762 #if USE_CACHE_DIGESTS
764 HttpRequest
*request
= ps
->request
;
765 const cache_key
*key
= request
? storeKeyPublicByRequest(request
) : NULL
;
768 debugs(15, 5, "peerDigestLookup: peer " << p
->host
);
769 /* does the peeer have a valid digest? */
772 debugs(15, 5, "peerDigestLookup: gone!");
774 } else if (!peerHTTPOkay(p
, ps
)) {
775 debugs(15, 5, "peerDigestLookup: !peerHTTPOkay");
777 } else if (!p
->digest
->flags
.needed
) {
778 debugs(15, 5, "peerDigestLookup: note need");
779 peerDigestNeeded(p
->digest
);
781 } else if (!p
->digest
->flags
.usable
) {
782 debugs(15, 5, "peerDigestLookup: !ready && " << (p
->digest
->flags
.requested
? "" : "!") << "requested");
786 debugs(15, 5, "peerDigestLookup: OK to lookup peer " << p
->host
);
787 assert(p
->digest
->cd
);
788 /* does digest predict a hit? */
790 if (!p
->digest
->cd
->contains(key
))
793 debugs(15, 5, "peerDigestLookup: peer " << p
->host
<< " says HIT!");
802 /* select best CachePeer based on cache digests */
804 neighborsDigestSelect(PeerSelector
*ps
)
806 CachePeer
*best_p
= NULL
;
807 #if USE_CACHE_DIGESTS
809 HttpRequest
*request
= ps
->request
;
812 int choice_count
= 0;
813 int ichoice_count
= 0;
818 if (!request
->flags
.hierarchical
)
821 storeKeyPublicByRequest(request
);
823 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
832 lookup
= peerDigestLookup(p
, ps
);
834 if (lookup
== LOOKUP_NONE
)
839 if (lookup
== LOOKUP_MISS
)
842 p_rtt
= netdbHostRtt(p
->host
);
844 debugs(15, 5, "neighborsDigestSelect: peer " << p
->host
<< " rtt: " << p_rtt
);
846 /* is this CachePeer better than others in terms of rtt ? */
847 if (!best_p
|| (p_rtt
&& p_rtt
< best_rtt
)) {
851 if (p_rtt
) /* informative choice (aka educated guess) */
854 debugs(15, 4, "neighborsDigestSelect: peer " << p
->host
<< " leads with rtt " << best_rtt
);
858 debugs(15, 4, "neighborsDigestSelect: choices: " << choice_count
<< " (" << ichoice_count
<< ")");
859 peerNoteDigestLookup(request
, best_p
,
860 best_p
? LOOKUP_HIT
: (choice_count
? LOOKUP_MISS
: LOOKUP_NONE
));
861 request
->hier
.n_choices
= choice_count
;
862 request
->hier
.n_ichoices
= ichoice_count
;
869 peerNoteDigestLookup(HttpRequest
* request
, CachePeer
* p
, lookup_t lookup
)
871 #if USE_CACHE_DIGESTS
873 strncpy(request
->hier
.cd_host
, p
->host
, sizeof(request
->hier
.cd_host
)-1);
875 *request
->hier
.cd_host
= '\0';
877 request
->hier
.cd_lookup
= lookup
;
878 debugs(15, 4, "peerNoteDigestLookup: peer " << (p
? p
->host
: "<none>") << ", lookup: " << lookup_t_str
[lookup
] );
883 neighborAlive(CachePeer
* p
, const MemObject
*, const icp_common_t
* header
)
886 ++ p
->stats
.pings_acked
;
888 if ((icp_opcode
) header
->opcode
<= ICP_END
)
889 ++ p
->icp
.counts
[header
->opcode
];
891 p
->icp
.version
= (int) header
->version
;
895 neighborUpdateRtt(CachePeer
* p
, MemObject
* mem
)
897 int rtt
, rtt_av_factor
;
902 if (!mem
->start_ping
.tv_sec
)
905 rtt
= tvSubMsec(mem
->start_ping
, current_time
);
907 if (rtt
< 1 || rtt
> 10000)
910 rtt_av_factor
= RTT_AV_FACTOR
;
912 if (p
->options
.weighted_roundrobin
)
913 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
915 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, p
->stats
.pings_acked
, rtt_av_factor
);
920 neighborAliveHtcp(CachePeer
* p
, const MemObject
*, const HtcpReplyData
* htcp
)
923 ++ p
->stats
.pings_acked
;
924 ++ p
->htcp
.counts
[htcp
->hit
? 1 : 0];
925 p
->htcp
.version
= htcp
->version
;
931 neighborCountIgnored(CachePeer
* p
)
936 ++ p
->stats
.ignored_replies
;
941 static CachePeer
*non_peers
= NULL
;
944 neighborIgnoreNonPeer(const Ip::Address
&from
, icp_opcode opcode
)
948 for (np
= non_peers
; np
; np
= np
->next
) {
949 if (np
->in_addr
!= from
)
952 if (np
->in_addr
.port() != from
.port())
961 np
->icp
.port
= from
.port();
962 np
->type
= PEER_NONE
;
963 np
->host
= new char[MAX_IPSTRLEN
];
964 from
.toStr(np
->host
,MAX_IPSTRLEN
);
965 np
->next
= non_peers
;
969 ++ np
->icp
.counts
[opcode
];
971 if (isPowTen(++np
->stats
.ignored_replies
))
972 debugs(15, DBG_IMPORTANT
, "WARNING: Ignored " << np
->stats
.ignored_replies
<< " replies from non-peer " << np
->host
);
975 /* ignoreMulticastReply
977 * * We want to ignore replies from multicast peers if the
978 * * cache_host_domain rules would normally prevent the CachePeer
982 ignoreMulticastReply(CachePeer
* p
, PeerSelector
* ps
)
987 if (!p
->options
.mcast_responder
)
990 if (peerHTTPOkay(p
, ps
))
997 * I should attach these records to the entry. We take the first
998 * hit we get our wait until everyone misses. The timeout handler
999 * call needs to nip this shopping list or call one of the misses.
1001 * If a hit process is already started, then sobeit
1004 neighborsUdpAck(const cache_key
* key
, icp_common_t
* header
, const Ip::Address
&from
)
1006 CachePeer
*p
= NULL
;
1008 MemObject
*mem
= NULL
;
1009 peer_t ntype
= PEER_NONE
;
1010 icp_opcode opcode
= (icp_opcode
) header
->opcode
;
1012 debugs(15, 6, "neighborsUdpAck: opcode " << opcode
<< " '" << storeKeyText(key
) << "'");
1014 if ((entry
= Store::Root().findCallbackXXX(key
)))
1015 mem
= entry
->mem_obj
;
1017 if ((p
= whichPeer(from
)))
1018 neighborAlive(p
, mem
, header
);
1020 if (opcode
> ICP_END
)
1023 const char *opcode_d
= icp_opcode_str
[opcode
];
1026 neighborUpdateRtt(p
, mem
);
1028 /* Does the entry exist? */
1029 if (NULL
== entry
) {
1030 debugs(12, 3, "neighborsUdpAck: Cache key '" << storeKeyText(key
) << "' not found");
1031 neighborCountIgnored(p
);
1035 /* check if someone is already fetching it */
1036 if (EBIT_TEST(entry
->flags
, ENTRY_DISPATCHED
)) {
1037 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1038 neighborCountIgnored(p
);
1043 debugs(15, 2, "Ignoring " << opcode_d
<< " for missing mem_obj: " << storeKeyText(key
));
1044 neighborCountIgnored(p
);
1048 if (entry
->ping_status
!= PING_WAITING
) {
1049 debugs(15, 2, "neighborsUdpAck: Late " << opcode_d
<< " for " << storeKeyText(key
));
1050 neighborCountIgnored(p
);
1054 if (!entry
->locked()) {
1055 // TODO: many entries are unlocked; why is this reported at level 1?
1056 debugs(12, DBG_IMPORTANT
, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1057 neighborCountIgnored(p
);
1061 if (!mem
->ircb_data
) {
1062 debugs(12, DBG_IMPORTANT
, "BUG: missing ICP callback data for " << *entry
);
1063 neighborCountIgnored(p
);
1067 debugs(15, 3, "neighborsUdpAck: " << opcode_d
<< " for '" << storeKeyText(key
) << "' from " << (p
? p
->host
: "source") << " ");
1070 ntype
= neighborType(p
, mem
->request
->url
);
1073 if (ignoreMulticastReply(p
, mem
->ircb_data
)) {
1074 neighborCountIgnored(p
);
1075 } else if (opcode
== ICP_MISS
) {
1077 neighborIgnoreNonPeer(from
, opcode
);
1079 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1081 } else if (opcode
== ICP_HIT
) {
1083 neighborIgnoreNonPeer(from
, opcode
);
1085 header
->opcode
= ICP_HIT
;
1086 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1088 } else if (opcode
== ICP_DECHO
) {
1090 neighborIgnoreNonPeer(from
, opcode
);
1091 } else if (ntype
== PEER_SIBLING
) {
1092 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
1093 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
1095 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1097 } else if (opcode
== ICP_SECHO
) {
1099 debugs(15, DBG_IMPORTANT
, "Ignoring SECHO from neighbor " << p
->host
);
1100 neighborCountIgnored(p
);
1102 debugs(15, DBG_IMPORTANT
, "Unsolicited SECHO from " << from
);
1104 } else if (opcode
== ICP_DENIED
) {
1106 neighborIgnoreNonPeer(from
, opcode
);
1107 } else if (p
->stats
.pings_acked
> 100) {
1108 if (100 * p
->icp
.counts
[ICP_DENIED
] / p
->stats
.pings_acked
> 95) {
1109 debugs(15, DBG_CRITICAL
, "95%% of replies from '" << p
->host
<< "' are UDP_DENIED");
1110 debugs(15, DBG_CRITICAL
, "Disabling '" << p
->host
<< "', please check your configuration.");
1114 neighborCountIgnored(p
);
1117 } else if (opcode
== ICP_MISS_NOFETCH
) {
1118 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1120 debugs(15, DBG_CRITICAL
, "neighborsUdpAck: Unexpected ICP reply: " << opcode_d
);
1125 peerFindByName(const char *name
)
1127 CachePeer
*p
= NULL
;
1129 for (p
= Config
.peers
; p
; p
= p
->next
) {
1130 if (!strcasecmp(name
, p
->name
))
1138 peerFindByNameAndPort(const char *name
, unsigned short port
)
1140 CachePeer
*p
= NULL
;
1142 for (p
= Config
.peers
; p
; p
= p
->next
) {
1143 if (strcasecmp(name
, p
->name
))
1146 if (port
!= p
->http_port
)
1156 neighborUp(const CachePeer
* p
)
1159 peerProbeConnect(const_cast<CachePeer
*>(p
));
1164 * The CachePeer can not be UP if we don't have any IP addresses
1167 if (0 == p
->n_addresses
) {
1168 debugs(15, 8, "neighborUp: DOWN (no-ip): " << p
->host
<< " (" << p
->in_addr
<< ")");
1172 if (p
->options
.no_query
) {
1173 debugs(15, 8, "neighborUp: UP (no-query): " << p
->host
<< " (" << p
->in_addr
<< ")");
1177 if (p
->stats
.probe_start
!= 0 &&
1178 squid_curtime
- p
->stats
.probe_start
> Config
.Timeout
.deadPeer
) {
1179 debugs(15, 8, "neighborUp: DOWN (dead): " << p
->host
<< " (" << p
->in_addr
<< ")");
1183 debugs(15, 8, "neighborUp: UP: " << p
->host
<< " (" << p
->in_addr
<< ")");
1188 positiveTimeout(const time_t timeout
)
1190 return max(static_cast<time_t>(1), timeout
);
1194 peerDNSConfigure(const ipcache_addrs
*ia
, const Dns::LookupDetails
&, void *data
)
1196 // TODO: connections to no-longer valid IP addresses should be
1197 // closed when we can detect such IP addresses.
1199 CachePeer
*p
= (CachePeer
*)data
;
1201 if (p
->n_addresses
== 0) {
1202 debugs(15, Important(29), "Configuring " << neighborTypeStr(p
) << " " << p
->host
<< "/" << p
->http_port
<< "/" << p
->icp
.port
);
1204 if (p
->type
== PEER_MULTICAST
)
1205 debugs(15, DBG_IMPORTANT
, " Multicast TTL = " << p
->mcast
.ttl
);
1211 debugs(0, DBG_CRITICAL
, "WARNING: DNS lookup for '" << p
->host
<< "' failed!");
1216 debugs(0, DBG_CRITICAL
, "WARNING: No IP address found for '" << p
->host
<< "'!");
1220 for (const auto &ip
: ia
->goodAndBad()) { // TODO: Consider using just good().
1221 if (p
->n_addresses
< PEER_MAX_ADDRESSES
) {
1222 const auto idx
= p
->n_addresses
++;
1223 p
->addresses
[idx
] = ip
;
1224 debugs(15, 2, "--> IP address #" << idx
<< ": " << p
->addresses
[idx
]);
1226 debugs(15, 3, "ignoring remaining " << (ia
->size() - p
->n_addresses
) << " ips");
1231 p
->in_addr
.setEmpty();
1232 p
->in_addr
= p
->addresses
[0];
1233 p
->in_addr
.port(p
->icp
.port
);
1235 peerProbeConnect(p
, true); // detect any died or revived peers ASAP
1237 if (p
->type
== PEER_MULTICAST
)
1238 peerCountMcastPeersSchedule(p
, 10);
1241 if (p
->type
!= PEER_MULTICAST
&& IamWorkerProcess())
1242 if (!p
->options
.no_netdb_exchange
)
1243 eventAddIsh("netdbExchangeStart", netdbExchangeStart
, p
, 30.0, 1);
1246 if (p
->standby
.mgr
.valid())
1247 PeerPoolMgr::Checkpoint(p
->standby
.mgr
, "resolved peer");
1251 peerRefreshDNS(void *data
)
1253 CachePeer
*p
= NULL
;
1255 if (eventFind(peerRefreshDNS
, NULL
))
1256 eventDelete(peerRefreshDNS
, NULL
);
1258 if (!data
&& 0 == stat5minClientRequests()) {
1259 /* no recent client traffic, wait a bit */
1260 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 180.0, 1);
1264 for (p
= Config
.peers
; p
; p
= p
->next
)
1265 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1267 /* Reconfigure the peers every hour */
1268 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 3600.0, 1);
1272 peerConnectFailedSilent(CachePeer
* p
)
1274 p
->stats
.last_connect_failure
= squid_curtime
;
1277 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<<
1285 debugs(15, DBG_IMPORTANT
, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
1286 p
->stats
.logged_state
= PEER_DEAD
;
1291 peerConnectFailed(CachePeer
*p
)
1293 debugs(15, DBG_IMPORTANT
, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " failed");
1294 peerConnectFailedSilent(p
);
1298 peerConnectSucceded(CachePeer
* p
)
1301 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " succeeded");
1302 p
->tcp_up
= p
->connect_fail_limit
; // NP: so peerAlive(p) works properly.
1304 if (!p
->n_addresses
)
1305 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1307 p
->tcp_up
= p
->connect_fail_limit
;
1310 /// whether new TCP probes are currently banned
1312 peerProbeIsBusy(const CachePeer
*p
)
1314 if (p
->testing_now
> 0) {
1315 debugs(15, 8, "yes, probing " << p
);
1318 if (squid_curtime
- p
->stats
.last_connect_probe
== 0) {
1319 debugs(15, 8, "yes, just probed " << p
);
1325 * peerProbeConnect will be called on dead peers by neighborUp
1328 peerProbeConnect(CachePeer
*p
, const bool reprobeIfBusy
)
1330 if (peerProbeIsBusy(p
)) {
1331 p
->reprobe
= reprobeIfBusy
;
1336 const auto ctimeout
= p
->connectTimeout();
1337 /* for each IP address of this CachePeer. find one that we can connect to and probe it. */
1338 for (int i
= 0; i
< p
->n_addresses
; ++i
) {
1339 Comm::ConnectionPointer conn
= new Comm::Connection
;
1340 conn
->remote
= p
->addresses
[i
];
1341 conn
->remote
.port(p
->http_port
);
1343 getOutgoingAddress(NULL
, conn
);
1347 AsyncCall::Pointer call
= commCbCall(15,3, "peerProbeConnectDone", CommConnectCbPtrFun(peerProbeConnectDone
, p
));
1348 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, ctimeout
);
1349 cs
->setHost(p
->host
);
1350 AsyncJob::Start(cs
);
1353 p
->stats
.last_connect_probe
= squid_curtime
;
1357 peerProbeConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int, void *data
)
1359 CachePeer
*p
= (CachePeer
*)data
;
1361 if (status
== Comm::OK
) {
1362 peerConnectSucceded(p
);
1364 peerConnectFailedSilent(p
);
1369 // TODO: log this traffic.
1372 peerProbeConnect(p
);
1376 peerCountMcastPeersSchedule(CachePeer
* p
, time_t when
)
1378 if (p
->mcast
.flags
.count_event_pending
)
1381 eventAdd("peerCountMcastPeersStart",
1382 peerCountMcastPeersStart
,
1386 p
->mcast
.flags
.count_event_pending
= true;
1390 peerCountMcastPeersStart(void *data
)
1392 const auto peer
= static_cast<CachePeer
*>(data
);
1393 CallContextCreator([peer
] {
1394 peerCountMcastPeersCreateAndSend(peer
);
1396 peerCountMcastPeersSchedule(peer
, MCAST_COUNT_RATE
);
1399 /// initiates an ICP transaction to a multicast peer
1401 peerCountMcastPeersCreateAndSend(CachePeer
* const p
)
1403 // XXX: Do not create lots of complex fake objects (while abusing their
1404 // APIs) to pass around a few basic data points like start_ping and ping!
1407 // TODO: use class AnyP::Uri instead of constructing and re-parsing a string
1408 LOCAL_ARRAY(char, url
, MAX_URL
);
1409 assert(p
->type
== PEER_MULTICAST
);
1410 p
->mcast
.flags
.count_event_pending
= false;
1411 snprintf(url
, MAX_URL
, "http://");
1412 p
->in_addr
.toUrl(url
+7, MAX_URL
-8 );
1414 const MasterXaction::Pointer mx
= new MasterXaction(XactionInitiator::initPeerMcast
);
1415 auto *req
= HttpRequest::FromUrlXXX(url
, mx
);
1416 assert(req
!= nullptr);
1417 const AccessLogEntry::Pointer ale
= new AccessLogEntry
;
1419 CodeContext::Reset(ale
);
1420 StoreEntry
*fake
= storeCreateEntry(url
, url
, RequestFlags(), Http::METHOD_GET
);
1421 const auto psstate
= new PeerSelector(nullptr);
1422 psstate
->request
= req
;
1423 HTTPMSGLOCK(psstate
->request
);
1424 psstate
->entry
= fake
;
1425 psstate
->peerCountMcastPeerXXX
= cbdataReference(p
);
1426 psstate
->ping
.start
= current_time
;
1428 mem
= fake
->mem_obj
;
1429 mem
->request
= psstate
->request
;
1430 mem
->start_ping
= current_time
;
1431 mem
->ping_reply_callback
= peerCountHandleIcpReply
;
1432 mem
->ircb_data
= psstate
;
1433 mcastSetTtl(icpOutgoingConn
->fd
, p
->mcast
.ttl
);
1434 p
->mcast
.id
= mem
->id
;
1435 reqnum
= icpSetCacheKey((const cache_key
*)fake
->key
);
1436 icpCreateAndSend(ICP_QUERY
, 0, url
, reqnum
, 0,
1437 icpOutgoingConn
->fd
, p
->in_addr
, psstate
->al
);
1438 fake
->ping_status
= PING_WAITING
; // TODO: refactor to use PeerSelector::startPingWaiting()
1439 eventAdd("peerCountMcastPeersDone",
1440 peerCountMcastPeersDone
,
1442 Config
.Timeout
.mcast_icp_query
/ 1000.0, 1);
1443 p
->mcast
.flags
.counting
= true;
1447 peerCountMcastPeersDone(void *data
)
1449 const auto psstate
= static_cast<PeerSelector
*>(data
);
1450 CallBack(psstate
->al
, [psstate
] {
1451 peerCountMcastPeersAbort(psstate
);
1456 /// ends counting of multicast ICP replies
1457 /// to the ICP query initiated by peerCountMcastPeersCreateAndSend()
1459 peerCountMcastPeersAbort(PeerSelector
* const psstate
)
1461 StoreEntry
*fake
= psstate
->entry
;
1463 if (cbdataReferenceValid(psstate
->peerCountMcastPeerXXX
)) {
1464 CachePeer
*p
= (CachePeer
*)psstate
->peerCountMcastPeerXXX
;
1465 p
->mcast
.flags
.counting
= false;
1466 p
->mcast
.avg_n_members
= Math::doubleAverage(p
->mcast
.avg_n_members
, (double) psstate
->ping
.n_recv
, ++p
->mcast
.n_times_counted
, 10);
1467 debugs(15, DBG_IMPORTANT
, "Group " << p
->host
<< ": " << psstate
->ping
.n_recv
<<
1468 " replies, "<< std::setw(4)<< std::setprecision(2) <<
1469 p
->mcast
.avg_n_members
<<" average, RTT " << p
->stats
.rtt
);
1470 p
->mcast
.n_replies_expected
= (int) p
->mcast
.avg_n_members
;
1473 cbdataReferenceDone(psstate
->peerCountMcastPeerXXX
);
1475 fake
->abort(); // sets ENTRY_ABORTED and initiates related cleanup
1476 fake
->mem_obj
->request
= nullptr;
1477 fake
->unlock("peerCountMcastPeersDone");
1481 peerCountHandleIcpReply(CachePeer
* p
, peer_t
, AnyP::ProtocolType proto
, void *, void *data
)
1483 const auto psstate
= static_cast<PeerSelector
*>(data
);
1484 StoreEntry
*fake
= psstate
->entry
;
1486 MemObject
*mem
= fake
->mem_obj
;
1488 int rtt
= tvSubMsec(mem
->start_ping
, current_time
);
1489 assert(proto
== AnyP::PROTO_ICP
);
1490 ++ psstate
->ping
.n_recv
;
1491 int rtt_av_factor
= RTT_AV_FACTOR
;
1493 if (p
->options
.weighted_roundrobin
)
1494 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
1496 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, psstate
->ping
.n_recv
, rtt_av_factor
);
1500 neighborDumpPeers(StoreEntry
* sentry
)
1502 dump_peers(sentry
, Config
.peers
);
1506 neighborDumpNonPeers(StoreEntry
* sentry
)
1508 dump_peers(sentry
, non_peers
);
1512 dump_peer_options(StoreEntry
* sentry
, CachePeer
* p
)
1514 if (p
->options
.proxy_only
)
1515 storeAppendPrintf(sentry
, " proxy-only");
1517 if (p
->options
.no_query
)
1518 storeAppendPrintf(sentry
, " no-query");
1520 if (p
->options
.background_ping
)
1521 storeAppendPrintf(sentry
, " background-ping");
1523 if (p
->options
.no_digest
)
1524 storeAppendPrintf(sentry
, " no-digest");
1526 if (p
->options
.default_parent
)
1527 storeAppendPrintf(sentry
, " default");
1529 if (p
->options
.roundrobin
)
1530 storeAppendPrintf(sentry
, " round-robin");
1532 if (p
->options
.carp
)
1533 storeAppendPrintf(sentry
, " carp");
1536 if (p
->options
.userhash
)
1537 storeAppendPrintf(sentry
, " userhash");
1540 if (p
->options
.sourcehash
)
1541 storeAppendPrintf(sentry
, " sourcehash");
1543 if (p
->options
.weighted_roundrobin
)
1544 storeAppendPrintf(sentry
, " weighted-round-robin");
1546 if (p
->options
.mcast_responder
)
1547 storeAppendPrintf(sentry
, " multicast-responder");
1549 #if PEER_MULTICAST_SIBLINGS
1550 if (p
->options
.mcast_siblings
)
1551 storeAppendPrintf(sentry
, " multicast-siblings");
1555 storeAppendPrintf(sentry
, " weight=%d", p
->weight
);
1557 if (p
->options
.closest_only
)
1558 storeAppendPrintf(sentry
, " closest-only");
1561 if (p
->options
.htcp
) {
1562 storeAppendPrintf(sentry
, " htcp");
1563 if (p
->options
.htcp_oldsquid
|| p
->options
.htcp_no_clr
|| p
->options
.htcp_no_purge_clr
|| p
->options
.htcp_only_clr
) {
1564 bool doneopts
= false;
1565 if (p
->options
.htcp_oldsquid
) {
1566 storeAppendPrintf(sentry
, "oldsquid");
1569 if (p
->options
.htcp_no_clr
) {
1570 storeAppendPrintf(sentry
, "%sno-clr",(doneopts
?",":"="));
1573 if (p
->options
.htcp_no_purge_clr
) {
1574 storeAppendPrintf(sentry
, "%sno-purge-clr",(doneopts
?",":"="));
1577 if (p
->options
.htcp_only_clr
) {
1578 storeAppendPrintf(sentry
, "%sonly-clr",(doneopts
?",":"="));
1579 //doneopts = true; // uncomment if more opts are added
1585 if (p
->options
.no_netdb_exchange
)
1586 storeAppendPrintf(sentry
, " no-netdb-exchange");
1589 if (p
->options
.no_delay
)
1590 storeAppendPrintf(sentry
, " no-delay");
1594 storeAppendPrintf(sentry
, " login=%s", p
->login
);
1596 if (p
->mcast
.ttl
> 0)
1597 storeAppendPrintf(sentry
, " ttl=%d", p
->mcast
.ttl
);
1599 if (p
->connect_timeout_raw
> 0)
1600 storeAppendPrintf(sentry
, " connect-timeout=%d", (int)p
->connect_timeout_raw
);
1602 if (p
->connect_fail_limit
!= PEER_TCP_MAGIC_COUNT
)
1603 storeAppendPrintf(sentry
, " connect-fail-limit=%d", p
->connect_fail_limit
);
1605 #if USE_CACHE_DIGESTS
1608 storeAppendPrintf(sentry
, " digest-url=%s", p
->digest_url
);
1612 if (p
->options
.allow_miss
)
1613 storeAppendPrintf(sentry
, " allow-miss");
1615 if (p
->options
.no_tproxy
)
1616 storeAppendPrintf(sentry
, " no-tproxy");
1618 if (p
->max_conn
> 0)
1619 storeAppendPrintf(sentry
, " max-conn=%d", p
->max_conn
);
1620 if (p
->standby
.limit
> 0)
1621 storeAppendPrintf(sentry
, " standby=%d", p
->standby
.limit
);
1623 if (p
->options
.originserver
)
1624 storeAppendPrintf(sentry
, " originserver");
1627 storeAppendPrintf(sentry
, " forceddomain=%s", p
->domain
);
1629 if (p
->connection_auth
== 0)
1630 storeAppendPrintf(sentry
, " connection-auth=off");
1631 else if (p
->connection_auth
== 1)
1632 storeAppendPrintf(sentry
, " connection-auth=on");
1633 else if (p
->connection_auth
== 2)
1634 storeAppendPrintf(sentry
, " connection-auth=auto");
1636 p
->secure
.dumpCfg(sentry
,"tls-");
1637 storeAppendPrintf(sentry
, "\n");
1641 dump_peers(StoreEntry
* sentry
, CachePeer
* peers
)
1643 char ntoabuf
[MAX_IPSTRLEN
];
1647 storeAppendPrintf(sentry
, "There are no neighbors installed.\n");
1649 for (CachePeer
*e
= peers
; e
; e
= e
->next
) {
1650 assert(e
->host
!= NULL
);
1651 storeAppendPrintf(sentry
, "\n%-11.11s: %s\n",
1654 storeAppendPrintf(sentry
, "Host : %s/%d/%d\n",
1658 storeAppendPrintf(sentry
, "Flags :");
1659 dump_peer_options(sentry
, e
);
1661 for (i
= 0; i
< e
->n_addresses
; ++i
) {
1662 storeAppendPrintf(sentry
, "Address[%d] : %s\n", i
,
1663 e
->addresses
[i
].toStr(ntoabuf
,MAX_IPSTRLEN
) );
1666 storeAppendPrintf(sentry
, "Status : %s\n",
1667 neighborUp(e
) ? "Up" : "Down");
1668 storeAppendPrintf(sentry
, "FETCHES : %d\n", e
->stats
.fetches
);
1669 storeAppendPrintf(sentry
, "OPEN CONNS : %d\n", e
->stats
.conn_open
);
1670 storeAppendPrintf(sentry
, "AVG RTT : %d msec\n", e
->stats
.rtt
);
1672 if (!e
->options
.no_query
) {
1673 storeAppendPrintf(sentry
, "LAST QUERY : %8d seconds ago\n",
1674 (int) (squid_curtime
- e
->stats
.last_query
));
1676 if (e
->stats
.last_reply
> 0)
1677 storeAppendPrintf(sentry
, "LAST REPLY : %8d seconds ago\n",
1678 (int) (squid_curtime
- e
->stats
.last_reply
));
1680 storeAppendPrintf(sentry
, "LAST REPLY : none received\n");
1682 storeAppendPrintf(sentry
, "PINGS SENT : %8d\n", e
->stats
.pings_sent
);
1684 storeAppendPrintf(sentry
, "PINGS ACKED: %8d %3d%%\n",
1685 e
->stats
.pings_acked
,
1686 Math::intPercent(e
->stats
.pings_acked
, e
->stats
.pings_sent
));
1689 storeAppendPrintf(sentry
, "IGNORED : %8d %3d%%\n", e
->stats
.ignored_replies
, Math::intPercent(e
->stats
.ignored_replies
, e
->stats
.pings_acked
));
1691 if (!e
->options
.no_query
) {
1692 storeAppendPrintf(sentry
, "Histogram of PINGS ACKED:\n");
1695 if (e
->options
.htcp
) {
1696 storeAppendPrintf(sentry
, "\tMisses\t%8d %3d%%\n",
1698 Math::intPercent(e
->htcp
.counts
[0], e
->stats
.pings_acked
));
1699 storeAppendPrintf(sentry
, "\tHits\t%8d %3d%%\n",
1701 Math::intPercent(e
->htcp
.counts
[1], e
->stats
.pings_acked
));
1705 for (auto op
: WholeEnum
<icp_opcode
>()) {
1706 if (e
->icp
.counts
[op
] == 0)
1709 storeAppendPrintf(sentry
, " %12.12s : %8d %3d%%\n",
1712 Math::intPercent(e
->icp
.counts
[op
], e
->stats
.pings_acked
));
1723 if (e
->stats
.last_connect_failure
) {
1724 storeAppendPrintf(sentry
, "Last failed connect() at: %s\n",
1725 Time::FormatHttpd(e
->stats
.last_connect_failure
));
1728 storeAppendPrintf(sentry
, "keep-alive ratio: %d%%\n", Math::intPercent(e
->stats
.n_keepalives_recv
, e
->stats
.n_keepalives_sent
));
1734 neighborsHtcpReply(const cache_key
* key
, HtcpReplyData
* htcp
, const Ip::Address
&from
)
1736 StoreEntry
*e
= Store::Root().findCallbackXXX(key
);
1737 MemObject
*mem
= NULL
;
1739 peer_t ntype
= PEER_NONE
;
1740 debugs(15, 6, "neighborsHtcpReply: " <<
1741 (htcp
->hit
? "HIT" : "MISS") << " " <<
1742 storeKeyText(key
) );
1747 if ((p
= whichPeer(from
)))
1748 neighborAliveHtcp(p
, mem
, htcp
);
1750 /* Does the entry exist? */
1752 debugs(12, 3, "neighyborsHtcpReply: Cache key '" << storeKeyText(key
) << "' not found");
1753 neighborCountIgnored(p
);
1757 /* check if someone is already fetching it */
1758 if (EBIT_TEST(e
->flags
, ENTRY_DISPATCHED
)) {
1759 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1760 neighborCountIgnored(p
);
1765 debugs(15, 2, "Ignoring reply for missing mem_obj: " << storeKeyText(key
));
1766 neighborCountIgnored(p
);
1770 if (e
->ping_status
!= PING_WAITING
) {
1771 debugs(15, 2, "neighborsUdpAck: Entry " << storeKeyText(key
) << " is not PING_WAITING");
1772 neighborCountIgnored(p
);
1777 // TODO: many entries are unlocked; why is this reported at level 1?
1778 debugs(12, DBG_IMPORTANT
, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1779 neighborCountIgnored(p
);
1783 if (!mem
->ircb_data
) {
1784 debugs(12, DBG_IMPORTANT
, "BUG: missing HTCP callback data for " << *e
);
1785 neighborCountIgnored(p
);
1790 ntype
= neighborType(p
, mem
->request
->url
);
1791 neighborUpdateRtt(p
, mem
);
1794 if (ignoreMulticastReply(p
, mem
->ircb_data
)) {
1795 neighborCountIgnored(p
);
1799 debugs(15, 3, "neighborsHtcpReply: e = " << e
);
1800 // TODO: Refactor (ping_reply_callback,ircb_data) to add CodeContext.
1801 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_HTCP
, htcp
, mem
->ircb_data
);
1805 * Send HTCP CLR messages to all peers configured to receive them.
1808 neighborsHtcpClear(StoreEntry
* e
, HttpRequest
* req
, const HttpRequestMethod
&method
, htcp_clr_reason reason
)
1813 for (p
= Config
.peers
; p
; p
= p
->next
) {
1814 if (!p
->options
.htcp
) {
1817 if (p
->options
.htcp_no_clr
) {
1820 if (p
->options
.htcp_no_purge_clr
&& reason
== HTCP_CLR_PURGE
) {
1823 debugs(15, 3, "neighborsHtcpClear: sending CLR to " << p
->in_addr
.toUrl(buf
, 128));
1824 htcpClear(e
, req
, method
, p
, reason
);