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