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