2 * Copyright (C) 1996-2023 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_SRC_HAPPYCONNOPENER_H
10 #define SQUID_SRC_HAPPYCONNOPENER_H
11 #include "base/AsyncCallbacks.h"
12 #include "base/JobWait.h"
13 #include "base/RefCount.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"
24 class HappyConnOpener
;
25 class HappyOrderEnforcer
;
27 typedef RefCount
<ResolvedPeers
> ResolvedPeersPointer
;
29 /// A FIFO queue of HappyConnOpener jobs waiting to open a spare connection.
30 typedef std::list
< CbcPointer
<HappyConnOpener
> > HappySpareWaitList
;
32 /// absolute time in fractional seconds; compatible with current_timed
33 typedef double HappyAbsoluteTime
;
35 /// keeps track of HappyConnOpener spare track waiting state
36 class HappySpareWait
{
38 explicit operator bool() const { return toGivePrimeItsChance
|| forSpareAllowance
|| forPrimesToFail
|| forNewPeer
; }
40 /// restores default-constructed state
41 /// nullifies but does not cancel the callback
42 void clear() { *this = HappySpareWait(); }
44 CodeContext::Pointer codeContext
; ///< requestor's context
46 /// a pending noteGavePrimeItsChance() or noteSpareAllowance() call
47 AsyncCall::Pointer callback
;
49 /// location on the toGivePrimeItsChance or forSpareAllowance wait list
50 /// invalidated when the callback is set
51 HappySpareWaitList::iterator position
;
53 /* The following four fields represent mutually exclusive wait reasons. */
55 /// Honoring happy_eyeballs_connect_timeout (once per currentPeer).
56 /// A prime connection failure ends this wait.
57 bool toGivePrimeItsChance
= false;
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;
65 /// Honors zero happy_eyeballs_connect_limit.
66 /// Prime exhaustion ends this wait (see ignoreSpareRestrictions).
67 bool forPrimesToFail
= false;
69 /// The current peer has no spares left to try.
70 /// Prime exhaustion ends this wait (by changing currentPeer).
71 bool forNewPeer
= false;
74 /// Final result (an open connection or an error) sent to the job initiator.
75 class HappyConnOpenerAnswer
78 ~HappyConnOpenerAnswer();
80 /// whether HappyConnOpener succeeded, returning a usable connection
81 bool success() const { return !error
; }
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
;
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)
91 /// The total number of attempts to establish a connection. Includes any
92 /// failed attempts and [always successful] persistent connection reuse.
95 /// whether conn was open earlier, by/for somebody else
99 /// reports Answer details (for AsyncCall parameter debugging)
100 std::ostream
&operator <<(std::ostream
&, const HappyConnOpenerAnswer
&);
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
107 CBDATA_CHILD(HappyConnOpener
);
109 typedef HappyConnOpenerAnswer Answer
;
112 HappyConnOpener(const ResolvedPeersPointer
&, const AsyncCallback
<Answer
> &, const HttpRequestPointer
&, time_t aFwdStart
, int tries
, const AccessLogEntryPointer
&);
113 ~HappyConnOpener() override
;
115 /// configures reuse of old connections
116 void allowPersistent(bool permitted
) { allowPconn_
= permitted
; }
118 /// configures whether the request may be retried later if things go wrong
119 void setRetriable(bool retriable
) { retriable_
= retriable
; }
121 /// configures the origin server domain name
122 void setHost(const char *);
124 /// reacts to changes in the destinations list
125 void noteCandidatesChange();
127 /// reacts to expired happy_eyeballs_connect_timeout
128 void noteGavePrimeItsChance();
130 /// reacts to satisfying happy_eyeballs_connect_gap and happy_eyeballs_connect_limit
131 void noteSpareAllowance();
133 /// the start of the first connection attempt for the currentPeer
134 HappyAbsoluteTime primeStart
= 0;
137 /// a connection opening attempt in progress (or falsy)
140 /// HappyConnOpener method implementing a ConnOpener callback
141 using CallbackMethod
= void (HappyConnOpener::*)(const CommConnectCbParams
&);
143 Attempt(const CallbackMethod method
, const char *methodName
);
145 explicit operator bool() const { return static_cast<bool>(path
); }
147 /// reacts to a natural attempt completion (successful or otherwise)
150 /// aborts an in-progress attempt
151 void cancel(const char *reason
);
153 PeerConnectionPointer path
; ///< the destination we are connecting to
155 /// waits for a connection to the peer to be established/opened
156 JobWait
<Comm::ConnOpener
> connWait
;
158 const CallbackMethod callbackMethod
; ///< ConnOpener calls this method
159 const char * const callbackMethodName
; ///< for callbackMethod debugging
161 friend std::ostream
&operator <<(std::ostream
&, const Attempt
&);
164 void start() override
;
165 bool doneAll() const override
;
166 void swanSong() override
;
167 const char *status() const override
;
169 void maybeOpenPrimeConnection();
170 void maybeOpenSpareConnection();
172 void maybeGivePrimeItsChance();
173 void stopGivingPrimeItsChance();
174 void stopWaitingForSpareAllowance();
176 void startConnecting(Attempt
&, PeerConnectionPointer
&);
177 void openFreshConnection(Attempt
&, PeerConnectionPointer
&);
178 bool reuseOldConnection(PeerConnectionPointer
&);
180 void notePrimeConnectDone(const CommConnectCbParams
&);
181 void noteSpareConnectDone(const CommConnectCbParams
&);
182 void handleConnOpenerAnswer(Attempt
&, const CommConnectCbParams
&, const char *connDescription
);
184 void checkForNewConnection();
186 void updateSpareWaitAfterPrimeFailure();
188 void cancelSpareWait(const char *reason
);
190 bool ranOutOfTimeOrAttempts() const;
192 ErrorState
*makeError(const err_type type
) const;
193 Answer
*futureAnswer(const PeerConnectionPointer
&);
194 void sendSuccess(const PeerConnectionPointer
&conn
, bool reused
, const char *connKind
);
196 void cancelAttempt(Attempt
&, const char *reason
);
198 const time_t fwdStart
; ///< requestor start time
200 /// answer destination
201 AsyncCallback
<Answer
> callback_
;
203 /// Candidate paths. Shared with the initiator. May not be finalized yet.
204 ResolvedPeersPointer destinations
;
206 /// current connection opening attempt on the prime track (if any)
209 /// current connection opening attempt on the spare track (if any)
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
;
216 /// preconditions for an attempt to open a spare connection
217 HappySpareWait spareWaiting
;
218 friend class HappyOrderEnforcer
;
220 AccessLogEntryPointer ale
; ///< transaction details
222 ErrorState
*lastError
= nullptr; ///< last problem details (or nil)
223 PeerConnectionPointer lastFailedConnection
; ///< nil if none has failed
225 /// whether spare connection attempts disregard happy_eyeballs_* settings
226 bool ignoreSpareRestrictions
= false;
228 /// whether we have received a permission to open a spare while spares are limited
229 bool gotSpareAllowance
= false;
231 /// whether persistent connections are allowed
232 bool allowPconn_
= true;
234 /// whether we are opening connections for a request that may be resent
235 bool retriable_
= true;
237 /// origin server domain name (or equivalent)
238 const char *host_
= nullptr;
240 /// the request that needs a to-server connection
241 HttpRequestPointer cause
;
243 /// number of our finished connection opening attempts (including pconn
244 /// reuses) plus previously finished attempts supplied by the requestor
247 /// Reason to ran out of time or attempts
248 mutable const char *ranOutOfTimeOrAttemptsEarlier_
= nullptr;
251 #endif /* SQUID_SRC_HAPPYCONNOPENER_H */