2 * Copyright (C) 1996-2019 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 #ifndef SQUID_PEERSELECTSTATE_H
10 #define SQUID_PEERSELECTSTATE_H
12 #include "AccessLogEntry.h"
13 #include "acl/Checklist.h"
14 #include "base/CbcPointer.h"
15 #include "comm/forward.h"
16 #include "hier_code.h"
17 #include "ip/Address.h"
19 #include "mem/forward.h"
21 #include "typedefs.h" /* for IRCB */
29 void peerSelectInit(void);
31 /// Interface for those who need a list of peers to forward a request to.
32 class PeerSelectionInitiator
: public CbdataParent
35 virtual ~PeerSelectionInitiator() = default;
37 /// called when a new unique destination has been found
38 virtual void noteDestination(Comm::ConnectionPointer path
) = 0;
40 /// called when there will be no more noteDestination() calls
41 /// \param error is a possible reason why no destinations were found; it is
42 /// guaranteed to be nil if there was at least one noteDestination() call
43 virtual void noteDestinationsEnd(ErrorState
*error
) = 0;
45 /// whether noteDestination() and noteDestinationsEnd() calls are allowed
46 bool subscribed
= false;
49 /// Initiates asynchronous peer selection that eventually
50 /// results in zero or more noteDestination() calls and
51 /// exactly one noteDestinationsEnd() call.
52 void startSelectingDestinations(HttpRequest
*request
, const AccessLogEntry::Pointer
&ale
, StoreEntry
*entry
);
57 /// Finds peer (including origin server) IPs for forwarding a single request.
58 /// Gives PeerSelectionInitiator each found destination, in the right order.
59 class PeerSelector
: public Dns::IpReceiver
61 CBDATA_CHILD(PeerSelector
);
64 explicit PeerSelector(PeerSelectionInitiator
*);
65 virtual ~PeerSelector() override
;
67 /* Dns::IpReceiver API */
68 virtual void noteIp(const Ip::Address
&ip
) override
;
69 virtual void noteIps(const Dns::CachedIps
*ips
, const Dns::LookupDetails
&details
) override
;
70 virtual void noteLookup(const Dns::LookupDetails
&details
) override
;
72 // Produce a URL for display identifying the transaction we are
73 // trying to locate a peer for.
74 const SBuf
url() const;
76 /// \returns valid/interested peer initiator or nil
77 PeerSelectionInitiator
*interestedInitiator();
79 /// \returns whether the initiator may use more destinations
80 bool wantsMoreDestinations() const;
82 /// processes a newly discovered/finalized path
83 void handlePath(const Comm::ConnectionPointer
&path
, FwdServer
&fs
);
85 /// a single selection loop iteration: attempts to add more destinations
89 AccessLogEntry::Pointer al
; ///< info for the future access.log entry
92 void *peerCountMcastPeerXXX
= nullptr; ///< a hack to help peerCountMcastPeersStart()
97 bool selectionAborted();
99 void handlePingTimeout();
100 void handleIcpReply(CachePeer
*, const peer_t
, icp_common_t
*header
);
101 void handleIcpParentMiss(CachePeer
*, icp_common_t
*);
103 void handleHtcpParentMiss(CachePeer
*, HtcpReplyData
*);
104 void handleHtcpReply(CachePeer
*, const peer_t
, HtcpReplyData
*);
107 int checkNetdbDirect();
108 void checkAlwaysDirectDone(const Acl::Answer answer
);
109 void checkNeverDirectDone(const Acl::Answer answer
);
111 void selectSomeNeighbor();
112 void selectSomeNeighborReplies();
113 void selectSomeDirect();
114 void selectSomeParent();
115 void selectAllParents();
118 void addSelection(CachePeer
*, const hier_code
);
120 void resolveSelected();
122 static IRCB HandlePingReply
;
123 static ACLCB CheckAlwaysDirectDone
;
124 static ACLCB CheckNeverDirectDone
;
125 static EVH HandlePingTimeout
;
128 Acl::Answer always_direct
;
129 Acl::Answer never_direct
;
130 int direct
; // TODO: fold always_direct/never_direct/prefer_direct into this now that ACL can do a multi-state result.
131 size_t foundPaths
= 0; ///< number of unique destinations identified so far
132 ErrorState
*lastError
;
134 FwdServer
*servers
; ///< a linked list of (unresolved) selected peers
137 * Why are these Ip::Address instead of CachePeer *? Because a
138 * CachePeer structure can become invalid during the CachePeer selection
139 * phase, specifically after a reconfigure. Thus we need to lookup
140 * the CachePeer * based on the address when we are finally ready to
141 * reference the CachePeer structure.
144 Ip::Address first_parent_miss
;
146 Ip::Address closest_parent_miss
;
148 * ->hit can be CachePeer* because it should only be
149 * accessed during the thread when it is set
153 ACLChecklist
*acl_checklist
;
155 typedef CbcPointer
<PeerSelectionInitiator
> Initiator
;
156 Initiator initiator_
; ///< recipient of the destinations we select; use interestedInitiator() to access
158 const InstanceId
<PeerSelector
> id
; ///< unique identification in worker log
161 #endif /* SQUID_PEERSELECTSTATE_H */