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