]>
Commit | Line | Data |
---|---|---|
482dcd01 | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
bbc27441 AJ |
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. | |
482dcd01 AJ |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 05 Socket Connection Opener */ |
10 | ||
f7f3304a | 11 | #include "squid.h" |
a011edee | 12 | #include "CachePeer.h" |
602d9612 | 13 | #include "comm.h" |
aed188fd | 14 | #include "comm/Connection.h" |
602d9612 | 15 | #include "comm/ConnOpener.h" |
8bbb16e3 | 16 | #include "comm/Loops.h" |
c4ad1349 | 17 | #include "fd.h" |
aed188fd | 18 | #include "fde.h" |
582c2af2 | 19 | #include "globals.h" |
aed188fd | 20 | #include "icmp/net_db.h" |
d9cbd42a | 21 | #include "ip/QosConfig.h" |
37abc165 | 22 | #include "ip/tools.h" |
602d9612 | 23 | #include "ipcache.h" |
4d5904f7 | 24 | #include "SquidConfig.h" |
aed188fd | 25 | |
1a30fdf5 | 26 | #include <cerrno> |
21d845b1 | 27 | |
a011edee FC |
28 | class CachePeer; |
29 | ||
a016163c | 30 | CBDATA_NAMESPACED_CLASS_INIT(Comm, ConnOpener); |
aed188fd | 31 | |
9b7992d9 | 32 | Comm::ConnOpener::ConnOpener(const Comm::ConnectionPointer &c, const AsyncCall::Pointer &handler, time_t ctimeout) : |
f53969cc | 33 | AsyncJob("Comm::ConnOpener"), |
aee3523a | 34 | host_(nullptr), |
f53969cc SM |
35 | temporaryFd_(-1), |
36 | conn_(c), | |
37 | callback_(handler), | |
38 | totalTries_(0), | |
39 | failRetries_(0), | |
40 | deadline_(squid_curtime + static_cast<time_t>(ctimeout)) | |
0ce8e93b EB |
41 | { |
42 | debugs(5, 3, "will connect to " << c << " with " << ctimeout << " timeout"); | |
2b6b1bcb AR |
43 | assert(conn_); // we know where to go |
44 | ||
45 | // Sharing a being-modified Connection object with the caller is dangerous, | |
46 | // but we cannot ban (or even check for) that using existing APIs. We do not | |
47 | // want to clone "just in case" because cloning is a bit expensive, and most | |
48 | // callers already have a non-owned Connection object to give us. Until the | |
49 | // APIs improve, we can only check that the connection is not open. | |
50 | assert(!conn_->isOpen()); | |
0ce8e93b | 51 | } |
aed188fd | 52 | |
4accd6d8 | 53 | Comm::ConnOpener::~ConnOpener() |
aed188fd | 54 | { |
5229395c | 55 | safe_free(host_); |
aed188fd AJ |
56 | } |
57 | ||
294775b5 | 58 | bool |
4accd6d8 | 59 | Comm::ConnOpener::doneAll() const |
294775b5 | 60 | { |
5229395c | 61 | // is the conn_ to be opened still waiting? |
aee3523a | 62 | if (conn_ == nullptr) { |
e3a4aecc | 63 | return AsyncJob::doneAll(); |
40d9f0fc | 64 | } |
294775b5 AJ |
65 | |
66 | // is the callback still to be called? | |
aee3523a | 67 | if (callback_ == nullptr || callback_->canceled()) { |
e3a4aecc | 68 | return AsyncJob::doneAll(); |
40d9f0fc | 69 | } |
294775b5 | 70 | |
923b75ce AR |
71 | // otherwise, we must be waiting for something |
72 | Must(temporaryFd_ >= 0 || calls_.sleep_); | |
e3a4aecc | 73 | return false; |
294775b5 AJ |
74 | } |
75 | ||
e52e78c4 | 76 | void |
4accd6d8 | 77 | Comm::ConnOpener::swanSong() |
e52e78c4 | 78 | { |
aee3523a | 79 | if (callback_ != nullptr) { |
923b75ce | 80 | // inform the still-waiting caller we are dying |
c8407295 | 81 | sendAnswer(Comm::ERR_CONNECT, 0, "Comm::ConnOpener::swanSong"); |
4590cc7d | 82 | } |
d146d17e | 83 | |
6ca3e20d | 84 | // did we abort with a temporary FD assigned? |
923b75ce AR |
85 | if (temporaryFd_ >= 0) |
86 | closeFd(); | |
87 | ||
2b6b1bcb AR |
88 | // did we abort while owning an open connection? |
89 | if (conn_ && conn_->isOpen()) | |
90 | conn_->close(); | |
91 | ||
6ca3e20d | 92 | // did we abort while waiting between retries? |
923b75ce AR |
93 | if (calls_.sleep_) |
94 | cancelSleep(); | |
a95ff429 | 95 | |
d146d17e | 96 | AsyncJob::swanSong(); |
e52e78c4 AJ |
97 | } |
98 | ||
aed188fd | 99 | void |
4accd6d8 | 100 | Comm::ConnOpener::setHost(const char * new_host) |
aed188fd | 101 | { |
85d2870d | 102 | // unset and erase if already set. |
aee3523a | 103 | if (host_ != nullptr) |
5229395c | 104 | safe_free(host_); |
85d2870d AJ |
105 | |
106 | // set the new one if given. | |
aee3523a | 107 | if (new_host != nullptr) |
5229395c | 108 | host_ = xstrdup(new_host); |
aed188fd AJ |
109 | } |
110 | ||
111 | const char * | |
4accd6d8 | 112 | Comm::ConnOpener::getHost() const |
aed188fd | 113 | { |
5229395c | 114 | return host_; |
aed188fd AJ |
115 | } |
116 | ||
5229395c AJ |
117 | /** |
118 | * Connection attempt are completed. One way or the other. | |
119 | * Pass the results back to the external handler. | |
120 | */ | |
aed188fd | 121 | void |
c8407295 | 122 | Comm::ConnOpener::sendAnswer(Comm::Flag errFlag, int xerrno, const char *why) |
aed188fd | 123 | { |
e884bbde | 124 | // only mark the address good/bad AFTER connect is finished. |
aee3523a | 125 | if (host_ != nullptr) { |
923b75ce | 126 | if (xerrno == 0) // XXX: should not we use errFlag instead? |
e884bbde AJ |
127 | ipcacheMarkGoodAddr(host_, conn_->remote); |
128 | else { | |
129 | ipcacheMarkBadAddr(host_, conn_->remote); | |
130 | #if USE_ICMP | |
131 | if (Config.onoff.test_reachability) | |
132 | netdbDeleteAddrNetwork(conn_->remote); | |
133 | #endif | |
134 | } | |
135 | } | |
136 | ||
aee3523a | 137 | if (callback_ != nullptr) { |
923b75ce AR |
138 | // avoid scheduling cancelled callbacks, assuming they are common |
139 | // enough to make this extra check an optimization | |
140 | if (callback_->canceled()) { | |
141 | debugs(5, 4, conn_ << " not calling canceled " << *callback_ << | |
142 | " [" << callback_->id << ']' ); | |
6ca3e20d | 143 | // TODO save the pconn to the pconnPool ? |
923b75ce | 144 | } else { |
2b6b1bcb AR |
145 | assert(conn_); |
146 | ||
147 | // free resources earlier and simplify recipients | |
148 | if (errFlag != Comm::OK) | |
149 | conn_->close(); // may not be opened | |
150 | else | |
151 | assert(conn_->isOpen()); | |
152 | ||
923b75ce AR |
153 | typedef CommConnectCbParams Params; |
154 | Params ¶ms = GetCommParams<Params>(callback_); | |
155 | params.conn = conn_; | |
2b6b1bcb | 156 | conn_ = nullptr; // release ownership; prevent closure by us |
923b75ce AR |
157 | params.flag = errFlag; |
158 | params.xerrno = xerrno; | |
159 | ScheduleCallHere(callback_); | |
160 | } | |
aee3523a | 161 | callback_ = nullptr; |
294775b5 AJ |
162 | } |
163 | ||
923b75ce AR |
164 | // The job will stop without this call because nil callback_ makes |
165 | // doneAll() true, but this explicit call creates nicer debugging. | |
166 | mustStop(why); | |
167 | } | |
168 | ||
169 | /// cleans up this job I/O state without closing temporaryFd | |
170 | /// required before closing temporaryFd or keeping it in conn_ | |
171 | /// leaves FD bare so must only be called via closeFd() or keepFd() | |
172 | void | |
173 | Comm::ConnOpener::cleanFd() | |
174 | { | |
2b6b1bcb | 175 | debugs(5, 4, conn_ << "; temp FD " << temporaryFd_); |
923b75ce AR |
176 | |
177 | Must(temporaryFd_ >= 0); | |
178 | fde &f = fd_table[temporaryFd_]; | |
179 | ||
180 | // Our write_handler was set without using Comm::Write API, so we cannot | |
181 | // use a cancellable Pointer-free job callback and simply cancel it here. | |
182 | if (f.write_handler) { | |
183 | ||
184 | /* XXX: We are about to remove write_handler, which was responsible | |
185 | * for deleting write_data, so we have to delete write_data | |
186 | * ourselves. Comm currently calls SetSelect handlers synchronously | |
187 | * so if write_handler is set, we know it has not been called yet. | |
188 | * ConnOpener converts that sync call into an async one, but only | |
189 | * after deleting ptr, so that is not a problem. | |
190 | */ | |
191 | ||
192 | delete static_cast<Pointer*>(f.write_data); | |
aee3523a AR |
193 | f.write_data = nullptr; |
194 | f.write_handler = nullptr; | |
923b75ce AR |
195 | } |
196 | // Comm::DoSelect does not do this when calling and resetting write_handler | |
3c862035 | 197 | // (because it expects more writes to come?). We could mimic that |
923b75ce AR |
198 | // optimization by resetting Comm "Select" state only when the FD is |
199 | // actually closed. | |
aee3523a | 200 | Comm::SetSelect(temporaryFd_, COMM_SELECT_WRITE, nullptr, nullptr, 0); |
3c862035 | 201 | |
aee3523a | 202 | if (calls_.timeout_ != nullptr) { |
923b75ce | 203 | calls_.timeout_->cancel("Comm::ConnOpener::cleanFd"); |
aee3523a | 204 | calls_.timeout_ = nullptr; |
923b75ce | 205 | } |
3c862035 | 206 | // Comm checkTimeouts() and commCloseAllSockets() do not clear .timeout |
923b75ce | 207 | // when calling timeoutHandler (XXX fix them), so we clear unconditionally. |
aee3523a | 208 | f.timeoutHandler = nullptr; |
923b75ce AR |
209 | f.timeout = 0; |
210 | ||
aee3523a | 211 | if (calls_.earlyAbort_ != nullptr) { |
923b75ce | 212 | comm_remove_close_handler(temporaryFd_, calls_.earlyAbort_); |
aee3523a | 213 | calls_.earlyAbort_ = nullptr; |
a95ff429 | 214 | } |
923b75ce AR |
215 | } |
216 | ||
217 | /// cleans I/O state and ends I/O for temporaryFd_ | |
218 | void | |
219 | Comm::ConnOpener::closeFd() | |
220 | { | |
221 | if (temporaryFd_ < 0) | |
222 | return; | |
223 | ||
224 | cleanFd(); | |
a95ff429 | 225 | |
923b75ce AR |
226 | // comm_close() below uses COMMIO_FD_WRITECB(fd)->active() to clear Comm |
227 | // "Select" state. It will not clear ours. XXX: It should always clear | |
228 | // because a callback may have been active but was called before comm_close | |
229 | // Update: we now do this in cleanFd() | |
230 | // Comm::SetSelect(temporaryFd_, COMM_SELECT_WRITE, NULL, NULL, 0); | |
231 | ||
232 | comm_close(temporaryFd_); | |
233 | temporaryFd_ = -1; | |
234 | } | |
235 | ||
236 | /// cleans I/O state and moves temporaryFd_ to the conn_ for long-term use | |
237 | void | |
238 | Comm::ConnOpener::keepFd() | |
239 | { | |
aee3523a | 240 | Must(conn_ != nullptr); |
923b75ce AR |
241 | Must(temporaryFd_ >= 0); |
242 | ||
243 | cleanFd(); | |
244 | ||
245 | conn_->fd = temporaryFd_; | |
246 | temporaryFd_ = -1; | |
aed188fd AJ |
247 | } |
248 | ||
a9870624 AJ |
249 | void |
250 | Comm::ConnOpener::start() | |
aed188fd | 251 | { |
aee3523a | 252 | Must(conn_ != nullptr); |
482dcd01 | 253 | |
923b75ce | 254 | /* outbound sockets have no need to be protocol agnostic. */ |
4dd643d5 AJ |
255 | if (!(Ip::EnableIpv6&IPV6_SPECIAL_V4MAPPING) && conn_->remote.isIPv4()) { |
256 | conn_->local.setIPv4(); | |
923b75ce AR |
257 | } |
258 | ||
8aec3e1b | 259 | conn_->noteStart(); |
923b75ce | 260 | if (createFd()) |
3d7ecaff | 261 | doConnect(); |
923b75ce AR |
262 | } |
263 | ||
264 | /// called at the end of Comm::ConnOpener::DelayedConnectRetry event | |
265 | void | |
3c862035 A |
266 | Comm::ConnOpener::restart() |
267 | { | |
923b75ce AR |
268 | debugs(5, 5, conn_ << " restarting after sleep"); |
269 | calls_.sleep_ = false; | |
270 | ||
271 | if (createFd()) | |
3d7ecaff | 272 | doConnect(); |
923b75ce AR |
273 | } |
274 | ||
3c862035 | 275 | /// Create a socket for the future connection or return false. |
923b75ce AR |
276 | /// If false is returned, done() is guaranteed to return true and end the job. |
277 | bool | |
278 | Comm::ConnOpener::createFd() | |
279 | { | |
280 | Must(temporaryFd_ < 0); | |
2b6b1bcb | 281 | assert(conn_); |
923b75ce | 282 | |
2f8abb64 | 283 | // our initiators signal abort by cancelling their callbacks |
aee3523a | 284 | if (callback_ == nullptr || callback_->canceled()) |
923b75ce AR |
285 | return false; |
286 | ||
c6f168c1 | 287 | temporaryFd_ = comm_openex(SOCK_STREAM, IPPROTO_TCP, conn_->local, conn_->flags, host_); |
a95ff429 | 288 | if (temporaryFd_ < 0) { |
c8407295 | 289 | sendAnswer(Comm::ERR_CONNECT, 0, "Comm::ConnOpener::createFd"); |
923b75ce | 290 | return false; |
aed188fd AJ |
291 | } |
292 | ||
c6f168c1 CT |
293 | // Set TOS if needed. |
294 | if (conn_->tos && | |
d9cbd42a | 295 | Ip::Qos::setSockTos(temporaryFd_, conn_->tos, conn_->remote.isIPv4() ? AF_INET : AF_INET6) < 0) |
c6f168c1 CT |
296 | conn_->tos = 0; |
297 | #if SO_MARK | |
298 | if (conn_->nfmark && | |
d9cbd42a | 299 | Ip::Qos::setSockNfmark(temporaryFd_, conn_->nfmark) < 0) |
c6f168c1 CT |
300 | conn_->nfmark = 0; |
301 | #endif | |
302 | ||
2d1bd082 CT |
303 | fd_table[temporaryFd_].tosToServer = conn_->tos; |
304 | fd_table[temporaryFd_].nfmarkToServer = conn_->nfmark; | |
c6f168c1 | 305 | |
2832d7c0 | 306 | typedef CommCbMemFunT<Comm::ConnOpener, CommCloseCbParams> abortDialer; |
802540f2 | 307 | calls_.earlyAbort_ = JobCallback(5, 4, abortDialer, this, Comm::ConnOpener::earlyAbort); |
a95ff429 | 308 | comm_add_close_handler(temporaryFd_, calls_.earlyAbort_); |
418b3087 | 309 | |
802540f2 AJ |
310 | typedef CommCbMemFunT<Comm::ConnOpener, CommTimeoutCbParams> timeoutDialer; |
311 | calls_.timeout_ = JobCallback(5, 4, timeoutDialer, this, Comm::ConnOpener::timeout); | |
923b75ce | 312 | debugs(5, 3, conn_ << " will timeout in " << (deadline_ - squid_curtime)); |
a95ff429 | 313 | |
923b75ce | 314 | // Update the fd_table directly because commSetConnTimeout() needs open conn_ |
a95ff429 AJ |
315 | assert(temporaryFd_ < Squid_MaxFD); |
316 | assert(fd_table[temporaryFd_].flags.open); | |
317 | typedef CommTimeoutCbParams Params; | |
318 | Params ¶ms = GetCommParams<Params>(calls_.timeout_); | |
319 | params.conn = conn_; | |
320 | fd_table[temporaryFd_].timeoutHandler = calls_.timeout_; | |
923b75ce | 321 | fd_table[temporaryFd_].timeout = deadline_; |
418b3087 | 322 | |
923b75ce | 323 | return true; |
418b3087 AJ |
324 | } |
325 | ||
326 | void | |
327 | Comm::ConnOpener::connected() | |
328 | { | |
923b75ce AR |
329 | Must(temporaryFd_ >= 0); |
330 | keepFd(); | |
a95ff429 | 331 | |
418b3087 AJ |
332 | /* |
333 | * stats.conn_open is used to account for the number of | |
a3c6762c | 334 | * connections that we have open to the CachePeer, so we can limit |
418b3087 AJ |
335 | * based on the max-conn option. We need to increment here, |
336 | * even if the connection may fail. | |
337 | */ | |
a3c6762c | 338 | if (CachePeer *peer=(conn_->getPeer())) |
b79bfaae | 339 | ++peer->stats.conn_open; |
418b3087 AJ |
340 | |
341 | lookupLocalAddress(); | |
342 | ||
343 | /* TODO: remove these fd_table accesses. But old code still depends on fd_table flags to | |
344 | * indicate the state of a raw fd object being passed around. | |
345 | * Also, legacy code still depends on comm_local_port() with no access to Comm::Connection | |
346 | * when those are done comm_local_port can become one of our member functions to do the below. | |
347 | */ | |
923b75ce | 348 | Must(fd_table[conn_->fd].flags.open); |
418b3087 | 349 | fd_table[conn_->fd].local_addr = conn_->local; |
923b75ce | 350 | |
c8407295 | 351 | sendAnswer(Comm::OK, 0, "Comm::ConnOpener::connected"); |
8968fd45 AJ |
352 | } |
353 | ||
923b75ce | 354 | /// Make an FD connection attempt. |
8968fd45 | 355 | void |
3d7ecaff | 356 | Comm::ConnOpener::doConnect() |
8968fd45 | 357 | { |
aee3523a | 358 | Must(conn_ != nullptr); |
923b75ce | 359 | Must(temporaryFd_ >= 0); |
878bfa63 | 360 | |
a2f5277a | 361 | ++ totalTries_; |
aed188fd | 362 | |
a95ff429 | 363 | switch (comm_connect_addr(temporaryFd_, conn_->remote) ) { |
aed188fd | 364 | |
c8407295 | 365 | case Comm::INPROGRESS: |
bf95c10a | 366 | debugs(5, 5, conn_ << ": Comm::INPROGRESS"); |
923b75ce | 367 | Comm::SetSelect(temporaryFd_, COMM_SELECT_WRITE, Comm::ConnOpener::InProgressConnectRetry, new Pointer(this), 0); |
aed188fd AJ |
368 | break; |
369 | ||
c8407295 | 370 | case Comm::OK: |
bf95c10a | 371 | debugs(5, 5, conn_ << ": Comm::OK - connected"); |
418b3087 | 372 | connected(); |
aed188fd AJ |
373 | break; |
374 | ||
923b75ce AR |
375 | default: { |
376 | const int xerrno = errno; | |
377 | ||
a2f5277a | 378 | ++failRetries_; |
923b75ce AR |
379 | debugs(5, 7, conn_ << ": failure #" << failRetries_ << " <= " << |
380 | Config.connect_retries << ": " << xstrerr(xerrno)); | |
aed188fd | 381 | |
923b75ce | 382 | if (failRetries_ < Config.connect_retries) { |
bf95c10a | 383 | debugs(5, 5, conn_ << ": * - try again"); |
f6c0d1ab | 384 | retrySleep(); |
e884bbde | 385 | return; |
aed188fd AJ |
386 | } else { |
387 | // send ERROR back to the upper layer. | |
bf95c10a | 388 | debugs(5, 5, conn_ << ": * - ERR tried too many times already."); |
294e1994 | 389 | sendAnswer(Comm::ERR_CONNECT, xerrno, "Comm::ConnOpener::doConnect"); |
aed188fd AJ |
390 | } |
391 | } | |
923b75ce AR |
392 | } |
393 | } | |
394 | ||
395 | /// Close and wait a little before trying to open and connect again. | |
396 | void | |
f6c0d1ab | 397 | Comm::ConnOpener::retrySleep() |
3c862035 | 398 | { |
923b75ce AR |
399 | Must(!calls_.sleep_); |
400 | closeFd(); | |
401 | calls_.sleep_ = true; | |
402 | eventAdd("Comm::ConnOpener::DelayedConnectRetry", | |
403 | Comm::ConnOpener::DelayedConnectRetry, | |
404 | new Pointer(this), 0.05, 0, false); | |
405 | } | |
406 | ||
407 | /// cleans up this job sleep state | |
408 | void | |
409 | Comm::ConnOpener::cancelSleep() | |
410 | { | |
411 | if (calls_.sleep_) { | |
3c862035 A |
412 | // It would be nice to delete the sleep event, but it might be out of |
413 | // the event queue and in the async queue already, so (a) we do not know | |
414 | // whether we can safely delete the call ptr here and (b) eventDelete() | |
415 | // will assert if the event went async. Thus, we let the event run so | |
416 | // that it deletes the call ptr [after this job is gone]. Note that we | |
417 | // are called only when the job ends so this "hanging event" will do | |
418 | // nothing but deleting the call ptr. TODO: Revise eventDelete() API. | |
419 | // eventDelete(Comm::ConnOpener::DelayedConnectRetry, calls_.sleep); | |
420 | calls_.sleep_ = false; | |
421 | debugs(5, 9, conn_ << " stops sleeping"); | |
923b75ce | 422 | } |
aed188fd AJ |
423 | } |
424 | ||
dd829807 AJ |
425 | /** |
426 | * Lookup local-end address and port of the TCP link just opened. | |
427 | * This ensure the connection local details are set correctly | |
428 | */ | |
429 | void | |
430 | Comm::ConnOpener::lookupLocalAddress() | |
431 | { | |
aee3523a | 432 | struct addrinfo *addr = nullptr; |
851614a8 | 433 | Ip::Address::InitAddr(addr); |
dd829807 AJ |
434 | |
435 | if (getsockname(conn_->fd, addr->ai_addr, &(addr->ai_addrlen)) != 0) { | |
b69e9ffa AJ |
436 | int xerrno = errno; |
437 | debugs(50, DBG_IMPORTANT, "ERROR: Failed to retrieve TCP/UDP details for socket: " << conn_ << ": " << xstrerr(xerrno)); | |
851614a8 | 438 | Ip::Address::FreeAddr(addr); |
dd829807 AJ |
439 | return; |
440 | } | |
441 | ||
442 | conn_->local = *addr; | |
851614a8 | 443 | Ip::Address::FreeAddr(addr); |
bf95c10a | 444 | debugs(5, 6, conn_); |
dd829807 AJ |
445 | } |
446 | ||
5229395c AJ |
447 | /** Abort connection attempt. |
448 | * Handles the case(s) when a partially setup connection gets closed early. | |
449 | */ | |
aed188fd | 450 | void |
2832d7c0 | 451 | Comm::ConnOpener::earlyAbort(const CommCloseCbParams &io) |
aed188fd | 452 | { |
bf95c10a | 453 | debugs(5, 3, io.conn); |
aee3523a | 454 | calls_.earlyAbort_ = nullptr; |
923b75ce | 455 | // NP: is closing or shutdown better? |
c8407295 | 456 | sendAnswer(Comm::ERR_CLOSING, io.xerrno, "Comm::ConnOpener::earlyAbort"); |
aed188fd AJ |
457 | } |
458 | ||
5229395c AJ |
459 | /** |
460 | * Handles the case(s) when a partially setup connection gets timed out. | |
8d77a37c | 461 | * NP: When commSetConnTimeout accepts generic CommCommonCbParams this can die. |
5229395c | 462 | */ |
aed188fd | 463 | void |
418b3087 | 464 | Comm::ConnOpener::timeout(const CommTimeoutCbParams &) |
aed188fd | 465 | { |
bf95c10a | 466 | debugs(5, 5, conn_ << ": * - ERR took too long to receive response."); |
aee3523a | 467 | calls_.timeout_ = nullptr; |
c8407295 | 468 | sendAnswer(Comm::TIMEOUT, ETIMEDOUT, "Comm::ConnOpener::timeout"); |
aed188fd AJ |
469 | } |
470 | ||
c8407295 | 471 | /* Legacy Wrapper for the retry event after Comm::INPROGRESS |
294e1994 | 472 | * XXX: As soon as Comm::SetSelect() accepts Async calls we can use a ConnOpener::doConnect call |
5229395c | 473 | */ |
aed188fd | 474 | void |
ced8def3 | 475 | Comm::ConnOpener::InProgressConnectRetry(int, void *data) |
aed188fd | 476 | { |
9e64d84e AR |
477 | Pointer *ptr = static_cast<Pointer*>(data); |
478 | assert(ptr); | |
479 | if (ConnOpener *cs = ptr->valid()) { | |
42628300 A |
480 | // Ew. we are now outside the all AsyncJob protections. |
481 | // get back inside by scheduling another call... | |
482 | typedef NullaryMemFunT<Comm::ConnOpener> Dialer; | |
294e1994 | 483 | AsyncCall::Pointer call = JobCallback(5, 4, Dialer, cs, Comm::ConnOpener::doConnect); |
42628300 | 484 | ScheduleCallHere(call); |
9e64d84e AR |
485 | } |
486 | delete ptr; | |
418b3087 AJ |
487 | } |
488 | ||
489 | /* Legacy Wrapper for the retry event with small delay after errors. | |
923b75ce | 490 | * XXX: As soon as eventAdd() accepts Async calls we can use a ConnOpener::restart call |
418b3087 AJ |
491 | */ |
492 | void | |
493 | Comm::ConnOpener::DelayedConnectRetry(void *data) | |
494 | { | |
9e64d84e AR |
495 | Pointer *ptr = static_cast<Pointer*>(data); |
496 | assert(ptr); | |
497 | if (ConnOpener *cs = ptr->valid()) { | |
42628300 A |
498 | // Ew. we are now outside the all AsyncJob protections. |
499 | // get back inside by scheduling another call... | |
500 | typedef NullaryMemFunT<Comm::ConnOpener> Dialer; | |
923b75ce | 501 | AsyncCall::Pointer call = JobCallback(5, 4, Dialer, cs, Comm::ConnOpener::restart); |
42628300 | 502 | ScheduleCallHere(call); |
9e64d84e AR |
503 | } |
504 | delete ptr; | |
aed188fd | 505 | } |
f53969cc | 506 |