]> git.ipfire.org Git - thirdparty/squid.git/blob - src/HappyConnOpener.h
Maintenance: automate header guards 2/3 (#1655)
[thirdparty/squid.git] / src / HappyConnOpener.h
1 /*
2 * Copyright (C) 1996-2023 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_HAPPYCONNOPENER_H
10 #define SQUID_SRC_HAPPYCONNOPENER_H
11 #include "base/AsyncCallbacks.h"
12 #include "base/JobWait.h"
13 #include "base/RefCount.h"
14 #include "comm.h"
15 #include "comm/Connection.h"
16 #include "comm/ConnOpener.h"
17 #include "errorpage.h"
18 #include "http/forward.h"
19 #include "log/forward.h"
20 #include "ResolvedPeers.h"
21
22 #include <iosfwd>
23
24 class HappyConnOpener;
25 class HappyOrderEnforcer;
26 class JobGapEnforcer;
27 typedef RefCount<ResolvedPeers> ResolvedPeersPointer;
28
29 /// A FIFO queue of HappyConnOpener jobs waiting to open a spare connection.
30 typedef std::list< CbcPointer<HappyConnOpener> > HappySpareWaitList;
31
32 /// absolute time in fractional seconds; compatible with current_timed
33 typedef double HappyAbsoluteTime;
34
35 /// keeps track of HappyConnOpener spare track waiting state
36 class HappySpareWait {
37 public:
38 explicit operator bool() const { return toGivePrimeItsChance || forSpareAllowance || forPrimesToFail || forNewPeer; }
39
40 /// restores default-constructed state
41 /// nullifies but does not cancel the callback
42 void clear() { *this = HappySpareWait(); }
43
44 CodeContext::Pointer codeContext; ///< requestor's context
45
46 /// a pending noteGavePrimeItsChance() or noteSpareAllowance() call
47 AsyncCall::Pointer callback;
48
49 /// location on the toGivePrimeItsChance or forSpareAllowance wait list
50 /// invalidated when the callback is set
51 HappySpareWaitList::iterator position;
52
53 /* The following four fields represent mutually exclusive wait reasons. */
54
55 /// Honoring happy_eyeballs_connect_timeout (once per currentPeer).
56 /// A prime connection failure ends this wait.
57 bool toGivePrimeItsChance = false;
58
59 /// Honors happy_eyeballs_connect_gap and positive happy_eyeballs_connect_limit
60 /// (one allowance per spare path).
61 /// Does not start until there is a new spare path to try.
62 /// Prime exhaustion ends this wait (see ignoreSpareRestrictions).
63 bool forSpareAllowance = false;
64
65 /// Honors zero happy_eyeballs_connect_limit.
66 /// Prime exhaustion ends this wait (see ignoreSpareRestrictions).
67 bool forPrimesToFail = false;
68
69 /// The current peer has no spares left to try.
70 /// Prime exhaustion ends this wait (by changing currentPeer).
71 bool forNewPeer = false;
72 };
73
74 /// Final result (an open connection or an error) sent to the job initiator.
75 class HappyConnOpenerAnswer
76 {
77 public:
78 ~HappyConnOpenerAnswer();
79
80 /// whether HappyConnOpener succeeded, returning a usable connection
81 bool success() const { return !error; }
82
83 /// on success: an open, ready-to-use Squid-to-peer connection
84 /// on failure: either a closed failed Squid-to-peer connection or nil
85 PeerConnectionPointer conn;
86
87 // answer recipients must clear the error member in order to keep its info
88 // XXX: We should refcount ErrorState instead of cbdata-protecting it.
89 CbcPointer<ErrorState> error; ///< problem details (nil on success)
90
91 /// The total number of attempts to establish a connection. Includes any
92 /// failed attempts and [always successful] persistent connection reuse.
93 int n_tries = 0;
94
95 /// whether conn was open earlier, by/for somebody else
96 bool reused = false;
97 };
98
99 /// reports Answer details (for AsyncCall parameter debugging)
100 std::ostream &operator <<(std::ostream &, const HappyConnOpenerAnswer &);
101
102 /// A TCP connection opening algorithm based on Happy Eyeballs (RFC 8305).
103 /// Maintains two concurrent connection opening tracks: prime and spare.
104 /// Shares ResolvedPeers list with the job initiator.
105 class HappyConnOpener: public AsyncJob
106 {
107 CBDATA_CHILD(HappyConnOpener);
108 public:
109 typedef HappyConnOpenerAnswer Answer;
110
111 public:
112 HappyConnOpener(const ResolvedPeersPointer &, const AsyncCallback<Answer> &, const HttpRequestPointer &, time_t aFwdStart, int tries, const AccessLogEntryPointer &);
113 ~HappyConnOpener() override;
114
115 /// configures reuse of old connections
116 void allowPersistent(bool permitted) { allowPconn_ = permitted; }
117
118 /// configures whether the request may be retried later if things go wrong
119 void setRetriable(bool retriable) { retriable_ = retriable; }
120
121 /// configures the origin server domain name
122 void setHost(const char *);
123
124 /// reacts to changes in the destinations list
125 void noteCandidatesChange();
126
127 /// reacts to expired happy_eyeballs_connect_timeout
128 void noteGavePrimeItsChance();
129
130 /// reacts to satisfying happy_eyeballs_connect_gap and happy_eyeballs_connect_limit
131 void noteSpareAllowance();
132
133 /// the start of the first connection attempt for the currentPeer
134 HappyAbsoluteTime primeStart = 0;
135
136 private:
137 /// a connection opening attempt in progress (or falsy)
138 class Attempt {
139 public:
140 /// HappyConnOpener method implementing a ConnOpener callback
141 using CallbackMethod = void (HappyConnOpener::*)(const CommConnectCbParams &);
142
143 Attempt(const CallbackMethod method, const char *methodName);
144
145 explicit operator bool() const { return static_cast<bool>(path); }
146
147 /// reacts to a natural attempt completion (successful or otherwise)
148 void finish();
149
150 /// aborts an in-progress attempt
151 void cancel(const char *reason);
152
153 PeerConnectionPointer path; ///< the destination we are connecting to
154
155 /// waits for a connection to the peer to be established/opened
156 JobWait<Comm::ConnOpener> connWait;
157
158 const CallbackMethod callbackMethod; ///< ConnOpener calls this method
159 const char * const callbackMethodName; ///< for callbackMethod debugging
160 };
161 friend std::ostream &operator <<(std::ostream &, const Attempt &);
162
163 /* AsyncJob API */
164 void start() override;
165 bool doneAll() const override;
166 void swanSong() override;
167 const char *status() const override;
168
169 void maybeOpenPrimeConnection();
170 void maybeOpenSpareConnection();
171
172 void maybeGivePrimeItsChance();
173 void stopGivingPrimeItsChance();
174 void stopWaitingForSpareAllowance();
175
176 void startConnecting(Attempt &, PeerConnectionPointer &);
177 void openFreshConnection(Attempt &, PeerConnectionPointer &);
178 bool reuseOldConnection(PeerConnectionPointer &);
179
180 void notePrimeConnectDone(const CommConnectCbParams &);
181 void noteSpareConnectDone(const CommConnectCbParams &);
182 void handleConnOpenerAnswer(Attempt &, const CommConnectCbParams &, const char *connDescription);
183
184 void checkForNewConnection();
185
186 void updateSpareWaitAfterPrimeFailure();
187
188 void cancelSpareWait(const char *reason);
189
190 bool ranOutOfTimeOrAttempts() const;
191
192 ErrorState *makeError(const err_type type) const;
193 Answer *futureAnswer(const PeerConnectionPointer &);
194 void sendSuccess(const PeerConnectionPointer &conn, bool reused, const char *connKind);
195 void sendFailure();
196 void cancelAttempt(Attempt &, const char *reason);
197
198 const time_t fwdStart; ///< requestor start time
199
200 /// answer destination
201 AsyncCallback<Answer> callback_;
202
203 /// Candidate paths. Shared with the initiator. May not be finalized yet.
204 ResolvedPeersPointer destinations;
205
206 /// current connection opening attempt on the prime track (if any)
207 Attempt prime;
208
209 /// current connection opening attempt on the spare track (if any)
210 Attempt spare;
211
212 /// CachePeer and IP address family of the peer we are trying to connect
213 /// to now (or, if we are just waiting for paths to a new peer, nil)
214 Comm::ConnectionPointer currentPeer;
215
216 /// preconditions for an attempt to open a spare connection
217 HappySpareWait spareWaiting;
218 friend class HappyOrderEnforcer;
219
220 AccessLogEntryPointer ale; ///< transaction details
221
222 ErrorState *lastError = nullptr; ///< last problem details (or nil)
223 PeerConnectionPointer lastFailedConnection; ///< nil if none has failed
224
225 /// whether spare connection attempts disregard happy_eyeballs_* settings
226 bool ignoreSpareRestrictions = false;
227
228 /// whether we have received a permission to open a spare while spares are limited
229 bool gotSpareAllowance = false;
230
231 /// whether persistent connections are allowed
232 bool allowPconn_ = true;
233
234 /// whether we are opening connections for a request that may be resent
235 bool retriable_ = true;
236
237 /// origin server domain name (or equivalent)
238 const char *host_ = nullptr;
239
240 /// the request that needs a to-server connection
241 HttpRequestPointer cause;
242
243 /// number of our finished connection opening attempts (including pconn
244 /// reuses) plus previously finished attempts supplied by the requestor
245 int n_tries;
246
247 /// Reason to ran out of time or attempts
248 mutable const char *ranOutOfTimeOrAttemptsEarlier_ = nullptr;
249 };
250
251 #endif /* SQUID_SRC_HAPPYCONNOPENER_H */
252