]>
Commit | Line | Data |
---|---|---|
55622953 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
55622953 CT |
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 | ||
18 | #include <iosfwd> | |
19 | ||
20 | class HappyConnOpener; | |
21 | class HappyOrderEnforcer; | |
22 | class JobGapEnforcer; | |
23 | class ResolvedPeers; | |
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 | ||
99ecc6a4 EB |
41 | CodeContext::Pointer codeContext; ///< requestor's context |
42 | ||
55622953 CT |
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 | Comm::ConnectionPointer 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 | /// AsyncCall dialer for our callback. Gives us access to callback Answer. | |
109 | template <class Initiator> | |
110 | class CbDialer: public CallDialer, public Answer { | |
111 | public: | |
112 | // initiator method to receive our answer | |
113 | typedef void (Initiator::*Method)(Answer &); | |
114 | ||
115 | CbDialer(Method method, Initiator *initiator): initiator_(initiator), method_(method) {} | |
116 | virtual ~CbDialer() = default; | |
117 | ||
118 | /* CallDialer API */ | |
119 | bool canDial(AsyncCall &) { return initiator_.valid(); } | |
120 | void dial(AsyncCall &) {((*initiator_).*method_)(*this); } | |
121 | virtual void print(std::ostream &os) const override { | |
122 | os << '(' << static_cast<const Answer&>(*this) << ')'; | |
123 | } | |
124 | ||
125 | private: | |
126 | CbcPointer<Initiator> initiator_; ///< object to deliver the answer to | |
127 | Method method_; ///< initiator_ method to call with the answer | |
128 | }; | |
129 | ||
130 | public: | |
131 | HappyConnOpener(const ResolvedPeersPointer &, const AsyncCall::Pointer &, HttpRequestPointer &, const time_t aFwdStart, int tries, const AccessLogEntryPointer &al); | |
132 | virtual ~HappyConnOpener() override; | |
133 | ||
134 | /// configures reuse of old connections | |
135 | void allowPersistent(bool permitted) { allowPconn_ = permitted; } | |
136 | ||
137 | /// configures whether the request may be retried later if things go wrong | |
138 | void setRetriable(bool retriable) { retriable_ = retriable; } | |
139 | ||
140 | /// configures the origin server domain name | |
141 | void setHost(const char *); | |
142 | ||
143 | /// reacts to changes in the destinations list | |
144 | void noteCandidatesChange(); | |
145 | ||
146 | /// reacts to expired happy_eyeballs_connect_timeout | |
147 | void noteGavePrimeItsChance(); | |
148 | ||
149 | /// reacts to satisfying happy_eyeballs_connect_gap and happy_eyeballs_connect_limit | |
150 | void noteSpareAllowance(); | |
151 | ||
152 | /// the start of the first connection attempt for the currentPeer | |
153 | HappyAbsoluteTime primeStart = 0; | |
154 | ||
155 | private: | |
156 | /// a connection opening attempt in progress (or falsy) | |
157 | class Attempt { | |
158 | public: | |
159 | explicit operator bool() const { return static_cast<bool>(path); } | |
160 | void clear() { path = nullptr; connector = nullptr; } | |
161 | ||
162 | Comm::ConnectionPointer path; ///< the destination we are connecting to | |
163 | AsyncCall::Pointer connector; ///< our Comm::ConnOpener callback | |
164 | }; | |
165 | ||
166 | /* AsyncJob API */ | |
167 | virtual void start() override; | |
168 | virtual bool doneAll() const override; | |
169 | virtual void swanSong() override; | |
170 | virtual const char *status() const override; | |
171 | ||
172 | void maybeOpenAnotherPrimeConnection(); | |
173 | ||
174 | void maybeGivePrimeItsChance(); | |
175 | void stopGivingPrimeItsChance(); | |
176 | void stopWaitingForSpareAllowance(); | |
177 | void maybeOpenSpareConnection(); | |
178 | ||
179 | void startConnecting(Attempt &, Comm::ConnectionPointer &); | |
180 | void openFreshConnection(Attempt &, Comm::ConnectionPointer &); | |
181 | bool reuseOldConnection(const Comm::ConnectionPointer &); | |
182 | ||
183 | void connectDone(const CommConnectCbParams &); | |
184 | ||
185 | void checkForNewConnection(); | |
186 | ||
187 | void updateSpareWaitAfterPrimeFailure(); | |
188 | ||
189 | void cancelSpareWait(const char *reason); | |
190 | ||
191 | bool ranOutOfTimeOrAttempts() const; | |
192 | ||
193 | ErrorState *makeError(const err_type type) const; | |
194 | Answer *futureAnswer(const Comm::ConnectionPointer &); | |
195 | void sendSuccess(const Comm::ConnectionPointer &conn, bool reused, const char *connKind); | |
196 | void sendFailure(); | |
197 | ||
198 | const time_t fwdStart; ///< requestor start time | |
199 | ||
200 | AsyncCall::Pointer callback_; ///< handler to be called on connection completion. | |
201 | ||
202 | /// Candidate paths. Shared with the initiator. May not be finalized yet. | |
203 | ResolvedPeersPointer destinations; | |
204 | ||
205 | /// current connection opening attempt on the prime track (if any) | |
206 | Attempt prime; | |
207 | ||
208 | /// current connection opening attempt on the spare track (if any) | |
209 | Attempt spare; | |
210 | ||
211 | /// CachePeer and IP address family of the peer we are trying to connect | |
212 | /// to now (or, if we are just waiting for paths to a new peer, nil) | |
213 | Comm::ConnectionPointer currentPeer; | |
214 | ||
215 | /// preconditions for an attempt to open a spare connection | |
216 | HappySpareWait spareWaiting; | |
217 | friend class HappyOrderEnforcer; | |
218 | ||
219 | AccessLogEntryPointer ale; ///< transaction details | |
220 | ||
221 | ErrorState *lastError = nullptr; ///< last problem details (or nil) | |
222 | Comm::ConnectionPointer lastFailedConnection; ///< nil if none has failed | |
223 | ||
224 | /// whether spare connection attempts disregard happy_eyeballs_* settings | |
225 | bool ignoreSpareRestrictions = false; | |
226 | ||
227 | /// whether we have received a permission to open a spare while spares are limited | |
228 | bool gotSpareAllowance = false; | |
229 | ||
230 | /// whether persistent connections are allowed | |
231 | bool allowPconn_ = true; | |
232 | ||
233 | /// whether we are opening connections for a request that may be resent | |
234 | bool retriable_ = true; | |
235 | ||
236 | /// origin server domain name (or equivalent) | |
237 | const char *host_ = nullptr; | |
238 | ||
239 | /// the request that needs a to-server connection | |
240 | HttpRequestPointer cause; | |
241 | ||
242 | /// number of connection opening attempts, including those in the requestor | |
243 | int n_tries; | |
244 | ||
245 | /// Reason to ran out of time or attempts | |
246 | mutable const char *ranOutOfTimeOrAttemptsEarlier_ = nullptr; | |
247 | }; | |
248 | ||
249 | #endif | |
250 |