]>
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_FWDSTATE_H | |
10 | #define SQUID_SRC_FWDSTATE_H | |
11 | ||
12 | #include "base/forward.h" | |
13 | #include "base/JobWait.h" | |
14 | #include "base/RefCount.h" | |
15 | #include "clients/forward.h" | |
16 | #include "comm.h" | |
17 | #include "comm/Connection.h" | |
18 | #include "error/forward.h" | |
19 | #include "fde.h" | |
20 | #include "http/StatusCode.h" | |
21 | #include "ip/Address.h" | |
22 | #include "ip/forward.h" | |
23 | #include "PeerSelectState.h" | |
24 | #include "ResolvedPeers.h" | |
25 | #include "security/forward.h" | |
26 | #if USE_OPENSSL | |
27 | #include "ssl/support.h" | |
28 | #endif | |
29 | ||
30 | /* forward decls */ | |
31 | ||
32 | class AccessLogEntry; | |
33 | typedef RefCount<AccessLogEntry> AccessLogEntryPointer; | |
34 | class HttpRequest; | |
35 | class PconnPool; | |
36 | class ResolvedPeers; | |
37 | typedef RefCount<ResolvedPeers> ResolvedPeersPointer; | |
38 | ||
39 | class HappyConnOpener; | |
40 | class HappyConnOpenerAnswer; | |
41 | ||
42 | /// Sets initial TOS value and Netfilter for the future outgoing connection. | |
43 | /// Updates the given Connection object, not the future transport connection. | |
44 | void GetMarkingsToServer(HttpRequest * request, Comm::Connection &conn); | |
45 | ||
46 | /// Recomputes and applies TOS value and Netfilter to the outgoing connection. | |
47 | /// Updates both the given Connection object and the transport connection. | |
48 | void ResetMarkingsToServer(HttpRequest *, Comm::Connection &); | |
49 | ||
50 | class HelperReply; | |
51 | ||
52 | /// Eliminates excessive Stopwatch pause() calls in a task with multiple code | |
53 | /// locations that pause a stopwatch. Ideally, there would be just one such | |
54 | /// location (e.g., a task class destructor), but current code idiosyncrasies | |
55 | /// necessitate this state. For simplicity sake, this class currently manages a | |
56 | /// Stopwatch at a hard-coded location: HttpRequest::hier.totalPeeringTime. | |
57 | class PeeringActivityTimer | |
58 | { | |
59 | public: | |
60 | PeeringActivityTimer(const HttpRequestPointer &); ///< resumes timer | |
61 | ~PeeringActivityTimer(); ///< \copydoc stop() | |
62 | ||
63 | /// pauses timer if stop() has not been called | |
64 | void stop() | |
65 | { | |
66 | if (!stopped) { | |
67 | timer().pause(); | |
68 | stopped = true; | |
69 | } | |
70 | } | |
71 | ||
72 | private: | |
73 | /// managed Stopwatch object within HierarchyLogEntry | |
74 | Stopwatch &timer(); | |
75 | ||
76 | /// the owner of managed HierarchyLogEntry | |
77 | HttpRequestPointer request; | |
78 | ||
79 | // We cannot rely on timer().ran(): This class eliminates excessive calls | |
80 | // within a single task (e.g., an AsyncJob) while the timer (and its ran() | |
81 | // state) may be shared/affected by multiple concurrent tasks. | |
82 | /// Whether the task is done participating in the managed activity. | |
83 | bool stopped = false; | |
84 | }; | |
85 | ||
86 | class FwdState: public RefCountable, public PeerSelectionInitiator | |
87 | { | |
88 | CBDATA_CHILD(FwdState); | |
89 | ||
90 | public: | |
91 | typedef RefCount<FwdState> Pointer; | |
92 | ~FwdState() override; | |
93 | static void initModule(); | |
94 | ||
95 | /// Initiates request forwarding to a peer or origin server. | |
96 | static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp); | |
97 | /// Same as Start() but no master xaction info (AccessLogEntry) available. | |
98 | static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *); | |
99 | /// time left to finish the whole forwarding process (which started at fwdStart) | |
100 | static time_t ForwardTimeout(const time_t fwdStart); | |
101 | /// Whether there is still time to re-try after a previous connection failure. | |
102 | /// \param fwdStart The start time of the peer selection/connection process. | |
103 | static bool EnoughTimeToReForward(const time_t fwdStart); | |
104 | ||
105 | /// This is the real beginning of server connection. Call it whenever | |
106 | /// the forwarding server destination has changed and a new one needs to be opened. | |
107 | /// Produces the cannot-forward error on fail if no better error exists. | |
108 | void useDestinations(); | |
109 | ||
110 | void fail(ErrorState *err); | |
111 | void unregister(Comm::ConnectionPointer &conn); | |
112 | void unregister(int fd); | |
113 | void complete(); | |
114 | ||
115 | /// Mark reply as written to Store in its entirety, including the header and | |
116 | /// any body. If the reply has a body, the entire body has to be stored. | |
117 | void markStoredReplyAsWhole(const char *whyWeAreSure); | |
118 | ||
119 | void handleUnregisteredServerEnd(); | |
120 | int reforward(); | |
121 | void serverClosed(); | |
122 | void connectStart(); | |
123 | void connectDone(const Comm::ConnectionPointer & conn, Comm::Flag status, int xerrno); | |
124 | bool checkRetry(); | |
125 | bool checkRetriable(); | |
126 | void dispatch(); | |
127 | ||
128 | void pconnPush(Comm::ConnectionPointer & conn, const char *domain); | |
129 | ||
130 | bool dontRetry() { return flags.dont_retry; } | |
131 | ||
132 | void dontRetry(bool val) { flags.dont_retry = val; } | |
133 | ||
134 | /// get rid of a to-server connection that failed to become serverConn | |
135 | void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason); | |
136 | ||
137 | /** return a ConnectionPointer to the current server connection (may or may not be open) */ | |
138 | Comm::ConnectionPointer const & serverConnection() const { return serverConn; }; | |
139 | ||
140 | private: | |
141 | // hidden for safer management of self; use static fwdStart | |
142 | FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp); | |
143 | void start(Pointer aSelf); | |
144 | void stopAndDestroy(const char *reason); | |
145 | ||
146 | /* PeerSelectionInitiator API */ | |
147 | void noteDestination(Comm::ConnectionPointer conn) override; | |
148 | void noteDestinationsEnd(ErrorState *selectionError) override; | |
149 | ||
150 | bool transporting() const; | |
151 | ||
152 | void noteConnection(HappyConnOpenerAnswer &); | |
153 | ||
154 | #if STRICT_ORIGINAL_DST | |
155 | void selectPeerForIntercepted(); | |
156 | #endif | |
157 | static void logReplyStatus(int tries, const Http::StatusCode status); | |
158 | void doneWithRetries(); | |
159 | void completed(); | |
160 | void retryOrBail(); | |
161 | ||
162 | void usePinned(); | |
163 | ||
164 | /// whether a pinned to-peer connection can be replaced with another one | |
165 | /// (in order to retry or reforward a failed request) | |
166 | bool pinnedCanRetry() const; | |
167 | ||
168 | template <typename StepStart> | |
169 | void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep); | |
170 | ||
171 | ErrorState *makeConnectingError(const err_type type) const; | |
172 | void connectedToPeer(Security::EncryptorAnswer &answer); | |
173 | static void RegisterWithCacheManager(void); | |
174 | ||
175 | void establishTunnelThruProxy(const Comm::ConnectionPointer &); | |
176 | void tunnelEstablishmentDone(Http::TunnelerAnswer &answer); | |
177 | void secureConnectionToPeerIfNeeded(const Comm::ConnectionPointer &); | |
178 | void secureConnectionToPeer(const Comm::ConnectionPointer &); | |
179 | void successfullyConnectedToPeer(const Comm::ConnectionPointer &); | |
180 | ||
181 | /// stops monitoring server connection for closure and updates pconn stats | |
182 | void closeServerConnection(const char *reason); | |
183 | ||
184 | void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused); | |
185 | void syncHierNote(const Comm::ConnectionPointer &server, const char *host); | |
186 | ||
187 | /// whether we have used up all permitted forwarding attempts | |
188 | bool exhaustedTries() const; | |
189 | void updateAttempts(int); | |
190 | ||
191 | /// \returns the time left for this connection to become connected or 1 second if it is less than one second left | |
192 | time_t connectingTimeout(const Comm::ConnectionPointer &conn) const; | |
193 | ||
194 | void cancelStep(const char *reason); | |
195 | ||
196 | void notifyConnOpener(); | |
197 | void reactToZeroSizeObject(); | |
198 | ||
199 | void updateAleWithFinalError(); | |
200 | ||
201 | public: | |
202 | StoreEntry *entry; | |
203 | HttpRequest *request; | |
204 | AccessLogEntryPointer al; ///< info for the future access.log entry | |
205 | ||
206 | /// called by Store if the entry is no longer usable | |
207 | static void HandleStoreAbort(FwdState *); | |
208 | ||
209 | private: | |
210 | Pointer self; | |
211 | ErrorState *err; | |
212 | Comm::ConnectionPointer clientConn; ///< a possibly open connection to the client. | |
213 | time_t start_t; | |
214 | int n_tries; ///< the number of forwarding attempts so far | |
215 | ||
216 | struct { | |
217 | bool connected_okay; ///< TCP link ever opened properly. This affects retry of POST,PUT,CONNECT,etc | |
218 | bool dont_retry; | |
219 | bool forward_completed; | |
220 | bool destinationsFound; ///< at least one candidate path found | |
221 | } flags; | |
222 | ||
223 | /// waits for a transport connection to the peer to be established/opened | |
224 | JobWait<HappyConnOpener> transportWait; | |
225 | ||
226 | /// waits for the established transport connection to be secured/encrypted | |
227 | JobWait<Security::PeerConnector> encryptionWait; | |
228 | ||
229 | /// waits for an HTTP CONNECT tunnel through a cache_peer to be negotiated | |
230 | /// over the (encrypted, if needed) transport connection to that cache_peer | |
231 | JobWait<Http::Tunneler> peerWait; | |
232 | ||
233 | /// whether we are waiting for the last dispatch()ed activity to end | |
234 | bool waitingForDispatched; | |
235 | ||
236 | ResolvedPeersPointer destinations; ///< paths for forwarding the request | |
237 | Comm::ConnectionPointer serverConn; ///< a successfully opened connection to a server. | |
238 | PeerConnectionPointer destinationReceipt; ///< peer selection result (or nil) | |
239 | ||
240 | AsyncCall::Pointer closeHandler; ///< The serverConn close handler | |
241 | ||
242 | /// possible pconn race states | |
243 | typedef enum { raceImpossible, racePossible, raceHappened } PconnRace; | |
244 | PconnRace pconnRace; ///< current pconn race state | |
245 | ||
246 | /// Whether the entire reply (including any body) was written to Store. | |
247 | /// The string literal value is only used for debugging. | |
248 | const char *storedWholeReply_; | |
249 | ||
250 | /// Measures time spent on selecting and communicating with peers. | |
251 | PeeringActivityTimer peeringTimer; | |
252 | }; | |
253 | ||
254 | class acl_tos; | |
255 | tos_t aclMapTOS(acl_tos *, ACLChecklist *); | |
256 | ||
257 | Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *, ACLChecklist *); | |
258 | void getOutgoingAddress(HttpRequest *, const Comm::ConnectionPointer &); | |
259 | ||
260 | /// a collection of previously used persistent Squid-to-peer HTTP(S) connections | |
261 | extern PconnPool *fwdPconnPool; | |
262 | ||
263 | #endif /* SQUID_SRC_FWDSTATE_H */ | |
264 |