]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors | |
3 | * | |
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. | |
7 | */ | |
8 | ||
9 | #ifndef SQUID_SRC_PEERSELECTSTATE_H | |
10 | #define SQUID_SRC_PEERSELECTSTATE_H | |
11 | ||
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" | |
18 | #include "ipcache.h" | |
19 | #include "mem/forward.h" | |
20 | #include "PingData.h" | |
21 | #include "typedefs.h" /* for IRCB */ | |
22 | ||
23 | class ErrorState; | |
24 | class HtcpReplyData; | |
25 | class HttpRequest; | |
26 | class icp_common_t; | |
27 | class StoreEntry; | |
28 | ||
29 | void peerSelectInit(void); | |
30 | ||
31 | /// Interface for those who need a list of peers to forward a request to. | |
32 | class PeerSelectionInitiator: public CbdataParent | |
33 | { | |
34 | public: | |
35 | ~PeerSelectionInitiator() override = default; | |
36 | ||
37 | /// called when a new unique destination has been found | |
38 | virtual void noteDestination(Comm::ConnectionPointer path) = 0; | |
39 | ||
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; | |
44 | ||
45 | /// whether noteDestination() and noteDestinationsEnd() calls are allowed | |
46 | bool subscribed = false; | |
47 | ||
48 | /* protected: */ | |
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); | |
53 | }; | |
54 | ||
55 | class FwdServer; | |
56 | ||
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 | |
60 | { | |
61 | CBDATA_CHILD(PeerSelector); | |
62 | ||
63 | public: | |
64 | explicit PeerSelector(PeerSelectionInitiator*); | |
65 | ~PeerSelector() override; | |
66 | ||
67 | /* Dns::IpReceiver API */ | |
68 | void noteIp(const Ip::Address &ip) override; | |
69 | void noteIps(const Dns::CachedIps *ips, const Dns::LookupDetails &details) override; | |
70 | void noteLookup(const Dns::LookupDetails &details) override; | |
71 | ||
72 | // Produce a URL for display identifying the transaction we are | |
73 | // trying to locate a peer for. | |
74 | const SBuf url() const; | |
75 | ||
76 | /// \returns valid/interested peer initiator or nil | |
77 | PeerSelectionInitiator *interestedInitiator(); | |
78 | ||
79 | /// \returns whether the initiator may use more destinations | |
80 | bool wantsMoreDestinations() const; | |
81 | ||
82 | /// processes a newly discovered/finalized path | |
83 | void handlePath(const Comm::ConnectionPointer &path, FwdServer &fs); | |
84 | ||
85 | /// a single selection loop iteration: attempts to add more destinations | |
86 | void selectMore(); | |
87 | ||
88 | /// switches into the PING_WAITING state (and associated timeout monitoring) | |
89 | void startPingWaiting(); | |
90 | ||
91 | /// terminates ICP ping timeout monitoring | |
92 | void cancelPingTimeoutMonitoring(); | |
93 | ||
94 | /// called when the given selector should stop expecting ICP ping responses | |
95 | static void HandlePingTimeout(PeerSelector *); | |
96 | ||
97 | HttpRequest *request; | |
98 | AccessLogEntry::Pointer al; ///< info for the future access.log entry | |
99 | StoreEntry *entry; | |
100 | ||
101 | void *peerCountMcastPeerXXX = nullptr; ///< a hack to help peerCountMcastPeersStart() | |
102 | ||
103 | ping_data ping; | |
104 | ||
105 | protected: | |
106 | bool selectionAborted(); | |
107 | ||
108 | void handlePingTimeout(); | |
109 | void handleIcpReply(CachePeer*, const peer_t, icp_common_t *header); | |
110 | void handleIcpParentMiss(CachePeer*, icp_common_t*); | |
111 | #if USE_HTCP | |
112 | void handleHtcpParentMiss(CachePeer*, HtcpReplyData*); | |
113 | void handleHtcpReply(CachePeer*, const peer_t, HtcpReplyData*); | |
114 | #endif | |
115 | ||
116 | int checkNetdbDirect(); | |
117 | void checkAlwaysDirectDone(const Acl::Answer answer); | |
118 | void checkNeverDirectDone(const Acl::Answer answer); | |
119 | ||
120 | void selectSomeNeighbor(); | |
121 | void selectSomeNeighborReplies(); | |
122 | void selectSomeDirect(); | |
123 | void selectSomeParent(); | |
124 | void selectAllParents(); | |
125 | void selectPinned(); | |
126 | ||
127 | void addSelection(CachePeer*, const hier_code); | |
128 | ||
129 | void resolveSelected(); | |
130 | ||
131 | static IRCB HandlePingReply; | |
132 | static ACLCB CheckAlwaysDirectDone; | |
133 | static ACLCB CheckNeverDirectDone; | |
134 | ||
135 | private: | |
136 | Acl::Answer always_direct; | |
137 | Acl::Answer never_direct; | |
138 | int direct; // TODO: fold always_direct/never_direct/prefer_direct into this now that ACL can do a multi-state result. | |
139 | size_t foundPaths = 0; ///< number of unique destinations identified so far | |
140 | ErrorState *lastError; | |
141 | ||
142 | FwdServer *servers; ///< a linked list of (unresolved) selected peers | |
143 | ||
144 | /* | |
145 | * Why are these Ip::Address instead of CachePeer *? Because a | |
146 | * CachePeer structure can become invalid during the CachePeer selection | |
147 | * phase, specifically after a reconfigure. Thus we need to lookup | |
148 | * the CachePeer * based on the address when we are finally ready to | |
149 | * reference the CachePeer structure. | |
150 | */ | |
151 | ||
152 | Ip::Address first_parent_miss; | |
153 | ||
154 | Ip::Address closest_parent_miss; | |
155 | /* | |
156 | * ->hit can be CachePeer* because it should only be | |
157 | * accessed during the thread when it is set | |
158 | */ | |
159 | CachePeer *hit; | |
160 | peer_t hit_type; | |
161 | ||
162 | typedef CbcPointer<PeerSelectionInitiator> Initiator; | |
163 | Initiator initiator_; ///< recipient of the destinations we select; use interestedInitiator() to access | |
164 | ||
165 | const InstanceId<PeerSelector> id; ///< unique identification in worker log | |
166 | }; | |
167 | ||
168 | #endif /* SQUID_SRC_PEERSELECTSTATE_H */ | |
169 |