Commit | Line | Data |
---|---|---|
91fcc471 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
8f66f529 | 20 | #include "host/pingscheduler.h" |
9c55ecd3 | 21 | |
0d46491b | 22 | #include <iostream> |
1309d0e4 | 23 | #include <limits> |
0d46491b | 24 | |
9c55ecd3 | 25 | #include <boost/bind.hpp> |
26b0f687 | 26 | #include <boost/foreach.hpp> |
0d46491b | 27 | |
301610ca GMF |
28 | #include <logfunc.hpp> |
29 | ||
780b0bca | 30 | #include "boost_assert_handler.h" |
086e2cc0 | 31 | #include "host/pingerfactory.h" |
26b0f687 | 32 | #include "dns/dnsmaster.h" |
51cbc790 | 33 | #include "icmp/icmppinger.h" |
72e54d1c | 34 | #include "link/linkstatus.h" |
ced28dc7 | 35 | |
a7c2eb51 | 36 | using namespace std; |
2bf8720f GMF |
37 | using boost::asio::io_service; |
38 | using boost::bind; | |
101be5ce | 39 | using boost::date_time::time_resolution_traits_adapted64_impl; |
2bf8720f GMF |
40 | using boost::posix_time::microsec_clock; |
41 | using boost::posix_time::ptime; | |
42 | using boost::posix_time::seconds; | |
e58d7507 | 43 | using boost::shared_ptr; |
301610ca | 44 | using I2n::Logger::GlobalLogger; |
a7c2eb51 | 45 | |
4c2a5ab5 | 46 | //----------------------------------------------------------------------------- |
4bb97b45 | 47 | // PingScheduler |
4c2a5ab5 GMF |
48 | //----------------------------------------------------------------------------- |
49 | ||
086e2cc0 GMF |
50 | /** |
51 | * @brief Parameterized constructor. | |
52 | * | |
ab2cb1ef | 53 | * @param io_serv The one @c io_serv object that controls async processing |
c1abff61 | 54 | * @param network_interface The name of the network interface sending the pings. |
086e2cc0 GMF |
55 | * @param destination_address The remote address to ping. |
56 | * @param destination_port The remote port to ping. | |
57 | * @param ping_protocol_list A list of protocols to use. | |
58 | * @param ping_interval_in_sec Amount of time between each ping. | |
59 | * @param ping_fail_percentage_limit Maximum amount of pings that can fail. | |
086e2cc0 | 60 | * @param link_analyzer The object to monitor the link status. |
365036be | 61 | * @param first_delay Delay in seconds from start_pinging to first ping attempt |
086e2cc0 | 62 | */ |
4bb97b45 | 63 | PingScheduler::PingScheduler( |
ab2cb1ef | 64 | const IoServiceItem io_serv, |
2bf8720f GMF |
65 | const string &network_interface, |
66 | const string &destination_address, | |
238da857 | 67 | const uint16_t destination_port, |
fe6a2f80 | 68 | const PingProtocolList &ping_protocol_list, |
c15a722d | 69 | const long ping_interval_in_sec, |
a341119a | 70 | const int ping_fail_percentage_limit, |
079d19ab | 71 | const int ping_reply_timeout, |
59733431 CH |
72 | LinkStatusItem link_analyzer, |
73 | const int first_delay | |
c5e4bfa1 | 74 | |
e39cc3da | 75 | ) : |
23f51766 CH |
76 | IoService( io_serv ), |
77 | NetworkInterfaceName( network_interface ), | |
23f51766 CH |
78 | DestinationAddress( destination_address ), |
79 | DestinationPort( destination_port ), | |
26b0f687 CH |
80 | Protocols( ping_protocol_list ), |
81 | ProtocolIter(), | |
82 | PingIntervalInSec( ping_interval_in_sec ), | |
83 | FirstDelay( first_delay ), | |
ab2cb1ef | 84 | NextPingTimer( *io_serv ), |
e39cc3da | 85 | TimeSentLastPing( microsec_clock::universal_time() ), |
26b0f687 | 86 | PingReplyTimeout( ping_reply_timeout ), |
c1abff61 CH |
87 | HostAnalyzer( destination_address, ping_fail_percentage_limit, |
88 | link_analyzer ), | |
26b0f687 CH |
89 | Resolver(), |
90 | Ping(), | |
91 | WantToPing( false ), | |
92 | LogPrefix(), | |
8d26221d | 93 | ContinueOnOutdatedIps( false ) |
ced28dc7 | 94 | { |
475ad07c GMF |
95 | BOOST_ASSERT( !network_interface.empty() ); |
96 | BOOST_ASSERT( !destination_address.empty() ); | |
23f51766 CH |
97 | BOOST_ASSERT( ( 0 < destination_port ) && |
98 | ( destination_port < numeric_limits<uint16_t>::max() ) ); | |
f71cb7e1 | 99 | BOOST_ASSERT( 0 < ping_interval_in_sec ); |
23f51766 CH |
100 | BOOST_ASSERT( (0 <= ping_fail_percentage_limit) && |
101 | ( ping_fail_percentage_limit <= 100) ); | |
102 | ||
26b0f687 | 103 | update_log_prefix(); |
23f51766 CH |
104 | |
105 | init_ping_protocol(); | |
2d591235 | 106 | } |
ced28dc7 | 107 | |
086e2cc0 GMF |
108 | /** |
109 | * @brief Destructor. | |
110 | */ | |
4bb97b45 | 111 | PingScheduler::~PingScheduler() |
2d591235 | 112 | { |
ced28dc7 GMF |
113 | } |
114 | ||
c1d776ba | 115 | void PingScheduler::stop_pinging() |
ced28dc7 | 116 | { |
c1abff61 CH |
117 | // stop pinger and resolver |
118 | GlobalLogger.debug() << LogPrefix << "scheduler: stop pinging"; | |
5a9bc2d1 | 119 | Ping->stop_pinging(); |
72be9e7d | 120 | cancel_resolve(true); |
f076f8d4 | 121 | |
c1abff61 CH |
122 | // now cancel the own timer in case that pinger cancelation called callback |
123 | GlobalLogger.debug() << LogPrefix << "scheduler: cancel timer"; | |
f076f8d4 | 124 | NextPingTimer.cancel(); |
c1d776ba CH |
125 | } |
126 | ||
127 | /** | |
23f51766 | 128 | * @brief Start into infinite loop of calls to ping |
cad0b08d CH |
129 | * |
130 | * Does not start yet but set NextPingTimer (possibly to 0), so action starts | |
131 | * when io_service is started | |
c1d776ba CH |
132 | */ |
133 | void PingScheduler::start_pinging() | |
134 | { | |
c1d776ba | 135 | if ( FirstDelay > 0 ) |
c1abff61 CH |
136 | GlobalLogger.info() << LogPrefix << "Delaying first ping by " |
137 | << FirstDelay << "s"; | |
59733431 | 138 | else |
c1abff61 | 139 | GlobalLogger.info() << LogPrefix << "Schedule ping as soon as possible"; |
cad0b08d CH |
140 | |
141 | (void) NextPingTimer.expires_from_now( seconds( FirstDelay ) ); | |
23f51766 | 142 | NextPingTimer.async_wait( bind( &PingScheduler::ping, this, |
cad0b08d | 143 | boost::asio::placeholders::error ) ); |
09de3c4b GMF |
144 | } |
145 | ||
4e91c69a | 146 | |
c1d776ba | 147 | /** |
23f51766 | 148 | * @brief call Ping::ping and schedule a call to ping_done_handler when finished |
c1d776ba | 149 | */ |
23f51766 | 150 | void PingScheduler::ping(const boost::system::error_code &error) |
823623d9 | 151 | { |
d26dce11 | 152 | if ( error ) |
f076f8d4 | 153 | { // get here, e.g. by NextPingTimer.cancel in stop_pinging |
d26dce11 | 154 | if ( error == boost::asio::error::operation_aborted ) |
c1abff61 CH |
155 | GlobalLogger.error() << LogPrefix << "Timer for ping was cancelled!" |
156 | << " --> Stopping"; | |
d26dce11 | 157 | else |
c1abff61 CH |
158 | GlobalLogger.error() << LogPrefix << "Received error " << error |
159 | << " waiting for ping! Stopping"; | |
d26dce11 CH |
160 | return; |
161 | } | |
162 | ||
23f51766 CH |
163 | // ping as soon as dns is ready |
164 | WantToPing = true; | |
8d26221d | 165 | ping_when_ready(); |
23f51766 CH |
166 | } |
167 | ||
c1d776ba | 168 | |
8d26221d | 169 | void PingScheduler::ping_when_ready() |
23f51766 CH |
170 | { |
171 | if ( !WantToPing ) | |
823623d9 | 172 | { |
2a4dde8b | 173 | GlobalLogger.info() << LogPrefix << "waiting for ping request " |
f8918bd5 | 174 | << "(should take no more than than " << PingIntervalInSec << "s)"; |
23f51766 | 175 | return; |
823623d9 | 176 | } |
23f51766 CH |
177 | else if ( Resolver && Resolver->is_resolving() ) |
178 | { | |
fd62d09f | 179 | GlobalLogger.info() << LogPrefix << "waiting for DNS to finish"; |
23f51766 CH |
180 | return; |
181 | } | |
182 | else if ( !Resolver ) | |
183 | // should not happen, but check anyway | |
184 | GlobalLogger.warning() << LogPrefix << "Have no resolver!"; | |
09de3c4b | 185 | |
c1abff61 | 186 | GlobalLogger.info() << LogPrefix << "start ping"; |
23f51766 | 187 | WantToPing = false; |
09de3c4b | 188 | |
fd62d09f CH |
189 | // try to get an up-to-date IP (ContinueOnOutdatedIps may only be set |
190 | // because a CNAME was out of date -- IPs may still be current) | |
26b0f687 | 191 | HostAddress ip = Resolver->get_next_ip(); |
8d26221d | 192 | |
fd62d09f CH |
193 | if ( !ip.is_valid() ) |
194 | { // this can happen in 2 cases: if ContinueOnOutdatedIps==true | |
195 | // or when ip went out of date between resolve and now | |
196 | // --> try to use outdated IP | |
26b0f687 CH |
197 | GlobalLogger.info() << LogPrefix << "Checking for outdated IPs"; |
198 | bool check_up_to_date = false; | |
199 | ip = Resolver->get_next_ip(check_up_to_date); | |
200 | } | |
fd62d09f | 201 | if ( !ip.is_valid() ) |
b44a5f96 CH |
202 | { // Do not even have an outdated IP! |
203 | // This happens if have no cached IPs and resolve failed | |
204 | GlobalLogger.info() << LogPrefix << "Not even outdated IP to ping " | |
205 | << "-- treat like a failed ping."; | |
fd62d09f CH |
206 | |
207 | // skip the ping and directly call ping_done_handler | |
838e0acf CH |
208 | HostAnalyzer.set_resolved_ip_count(1); // must have been 0 --> failed |
209 | // ping would create failed assumption (nPings > nIPs) | |
fd62d09f | 210 | ping_done_handler(false); |
838e0acf | 211 | HostAnalyzer.set_resolved_ip_count(0); // set back |
fd62d09f CH |
212 | } |
213 | else | |
214 | { | |
215 | uint32_t ttl = ip.get_ttl().get_updated_value(); | |
2a4dde8b CH |
216 | std::string expiry; |
217 | if (ttl == 0) | |
218 | expiry = "out of date!"; | |
219 | else | |
220 | { | |
221 | boost::posix_time::ptime now = | |
fd62d09f | 222 | boost::posix_time::second_clock::local_time(); |
2a4dde8b CH |
223 | expiry = boost::posix_time::to_simple_string(now + seconds(ttl)); |
224 | } | |
fd62d09f CH |
225 | |
226 | GlobalLogger.info() << LogPrefix << "pinging IP " << ip.get_ip() | |
2a4dde8b | 227 | << " with TTL " << ttl << "s (" << expiry << ")"; |
72be9e7d CH |
228 | Ping->ping( ip.get_ip(), |
229 | DestinationPort, | |
230 | boost::bind(&PingScheduler::ping_done_handler, this, _1) ); | |
26b0f687 | 231 | } |
3f6ba924 CH |
232 | } |
233 | ||
166fd9e9 | 234 | |
23f51766 CH |
235 | //------------------------------------------------------------------------------ |
236 | // Post Processing of Ping result | |
237 | //------------------------------------------------------------------------------ | |
e58d7507 | 238 | |
c1d776ba CH |
239 | /** |
240 | * @brief called when Ping::ping is done; calls functions to update | |
241 | * statistics, ping interval and elapsed time; | |
23f51766 | 242 | * schedules a call to ping, thereby closing the loop |
c1d776ba CH |
243 | */ |
244 | void PingScheduler::ping_done_handler( const bool ping_success ) | |
502b6af0 | 245 | { |
f8918bd5 CH |
246 | GlobalLogger.info() << LogPrefix << "Ping done with success = " |
247 | << ping_success; | |
248 | ||
c1d776ba | 249 | // post-processing |
079d19ab CH |
250 | // You must call these 3 methods exactly in this order |
251 | // TODO Fix this method, once it has a semantic dependency with the | |
c1d776ba | 252 | // update_ping_statistics method, because it depends on the PingAnalyzer |
a341119a | 253 | // statistics to update the exceeded_ping_failed_limit |
c1d776ba | 254 | HostAnalyzer.update_ping_statistics( ping_success ); |
d8a91bd6 | 255 | update_ping_interval(); |
c1d776ba CH |
256 | update_ping_elapsed_time(); |
257 | ||
72be9e7d CH |
258 | if (ping_success) |
259 | { // reset ContinueOnOutdatedIps | |
260 | ContinueOnOutdatedIps = false; | |
261 | update_log_prefix(); | |
262 | } | |
263 | ||
23f51766 CH |
264 | // get next protocol, possibly start resolving IPs |
265 | update_ping_protocol(); | |
266 | ||
c1d776ba CH |
267 | // schedule next ping |
268 | (void) NextPingTimer.expires_from_now( seconds( PingIntervalInSec ) ); | |
23f51766 | 269 | NextPingTimer.async_wait( bind( &PingScheduler::ping, this, |
d26dce11 | 270 | boost::asio::placeholders::error ) ); |
d8a91bd6 GMF |
271 | } |
272 | ||
273 | void PingScheduler::update_ping_interval() | |
274 | { | |
c1d776ba | 275 | // have to ping more often? |
fb469ffa | 276 | if ( HostAnalyzer.exceeded_ping_failed_limit() ) |
d8a91bd6 GMF |
277 | { |
278 | PingIntervalInSec.speed_up(); | |
279 | ||
c1abff61 CH |
280 | GlobalLogger.debug() << LogPrefix << "- Speeding up ping interval to: " |
281 | << PingIntervalInSec << "s"; | |
d8a91bd6 GMF |
282 | } |
283 | else | |
284 | { | |
285 | PingIntervalInSec.back_to_original(); | |
286 | ||
c1abff61 CH |
287 | GlobalLogger.debug() << LogPrefix << "- Stick to the original ping " |
288 | << "interval: " << PingIntervalInSec << "s"; | |
d8a91bd6 | 289 | } |
ced28dc7 GMF |
290 | } |
291 | ||
502b6af0 | 292 | void PingScheduler::update_ping_elapsed_time() |
ced28dc7 | 293 | { |
e5706968 | 294 | ptime now = microsec_clock::universal_time(); |
101be5ce GMF |
295 | time_resolution_traits_adapted64_impl::int_type elapsed_time_in_sec = |
296 | (now - TimeSentLastPing).total_seconds(); | |
c1abff61 CH |
297 | GlobalLogger.debug() << LogPrefix << "- Time elapsed since last ping: " |
298 | << elapsed_time_in_sec << "s"; | |
e5706968 GMF |
299 | |
300 | TimeSentLastPing = microsec_clock::universal_time(); | |
e39cc3da | 301 | } |
c1d776ba | 302 | |
23f51766 CH |
303 | |
304 | //------------------------------------------------------------------------------ | |
305 | // Ping Protocol Rotation | |
306 | //------------------------------------------------------------------------------ | |
307 | ||
26b0f687 | 308 | void PingScheduler::init_ping_protocol() |
23f51766 | 309 | { |
26b0f687 | 310 | ProtocolIter = Protocols.end(); |
23f51766 CH |
311 | get_next_ping_protocol(); |
312 | } | |
313 | ||
26b0f687 | 314 | void PingScheduler::update_ping_protocol() |
23f51766 CH |
315 | { |
316 | if ( can_change_ping_protocol() ) | |
317 | { | |
318 | get_next_ping_protocol(); | |
319 | } | |
320 | } | |
321 | ||
26b0f687 | 322 | void PingScheduler::get_next_ping_protocol() |
23f51766 | 323 | { |
8f00b3df CH |
324 | if (Ping) |
325 | { | |
326 | Ping->stop_pinging(); | |
327 | Ping.reset(); | |
328 | } | |
329 | ||
fd62d09f CH |
330 | GlobalLogger.debug() << LogPrefix |
331 | << "------------------------------------------------------------------"; | |
26b0f687 CH |
332 | ++ProtocolIter; |
333 | if (ProtocolIter == Protocols.end()) | |
334 | ProtocolIter = Protocols.begin(); | |
335 | PingProtocol ping_protocol = *ProtocolIter; | |
72be9e7d | 336 | // --> ProtocolIter still points to currently used protocol which is |
26b0f687 | 337 | // required in dns_resolve_callback |
23f51766 | 338 | |
23f51766 CH |
339 | Ping = PingerFactory::createPinger(ping_protocol, IoService, |
340 | NetworkInterfaceName, PingReplyTimeout); | |
341 | ||
342 | update_dns_resolver( ping_protocol ); | |
72be9e7d | 343 | |
23f51766 CH |
344 | } |
345 | ||
26b0f687 | 346 | bool PingScheduler::can_change_ping_protocol() const |
23f51766 | 347 | { |
c1abff61 CH |
348 | // TODO can_change_ping_protocol() and get_next_ping_protocol() may be |
349 | // implemented in a Algorithm class that can be exchanged in this class to | |
350 | // provide an algorithm neutral class | |
23f51766 CH |
351 | return true; |
352 | } | |
353 | ||
354 | //------------------------------------------------------------------------------ | |
355 | // DNS host name resolution | |
356 | //------------------------------------------------------------------------------ | |
26b0f687 CH |
357 | |
358 | // show "!" after host name if running on outdated IPs | |
8d26221d | 359 | void PingScheduler::update_log_prefix() |
26b0f687 CH |
360 | { |
361 | std::stringstream temp; | |
72be9e7d | 362 | temp << "Sched(" << DestinationAddress; |
26b0f687 CH |
363 | if (ContinueOnOutdatedIps) |
364 | temp << "!"; | |
365 | temp << "): "; | |
366 | LogPrefix = temp.str(); | |
367 | } | |
368 | ||
369 | void PingScheduler::update_dns_resolver( PingProtocol current_protocol ) | |
23f51766 CH |
370 | { |
371 | if (Resolver && Resolver->is_resolving()) | |
72be9e7d CH |
372 | cancel_resolve(false); |
373 | ||
374 | if (ContinueOnOutdatedIps) | |
23f51766 | 375 | { |
72be9e7d CH |
376 | ContinueOnOutdatedIps = false; |
377 | update_log_prefix(); | |
23f51766 CH |
378 | } |
379 | ||
380 | // DNS master caches created resolvers and resolved IPs, so this will | |
381 | // probably just return an existing resolver with already resolved IPs for | |
382 | // requested protocol ( ICMP/TCP is ignored, only IPv4/v6 is important) | |
383 | Resolver = DnsMaster::get_instance()->get_resolver_for(DestinationAddress, | |
384 | current_protocol); | |
fd62d09f CH |
385 | |
386 | // get number of up-to-date IPs | |
2a4dde8b | 387 | // TODO should check here, if they will be up to date in PingIntervalInSec |
fd62d09f CH |
388 | bool check_up_to_date = true; |
389 | int ip_count = Resolver->get_resolved_ip_count(check_up_to_date); | |
390 | if (ip_count > 0) | |
23f51766 | 391 | { |
fd62d09f | 392 | GlobalLogger.info() << LogPrefix << "Set resolved_ip_count to " |
f8918bd5 | 393 | << ip_count << " (IPs may be outdated=" << !check_up_to_date << ")"; |
fd62d09f CH |
394 | HostAnalyzer.set_resolved_ip_count( ip_count ); |
395 | ||
72be9e7d | 396 | if (Resolver->is_resolving()) |
c1abff61 | 397 | GlobalLogger.warning() << LogPrefix << "have up to date IPs but " |
23f51766 CH |
398 | << "resolver seems to be resolving all the same... " |
399 | << "Start pinging anyway!"; | |
8d26221d | 400 | ping_when_ready(); |
23f51766 CH |
401 | } |
402 | else | |
2a4dde8b CH |
403 | { |
404 | GlobalLogger.info() << LogPrefix | |
405 | << "No up-to-date IPs --> start resolve"; | |
23f51766 | 406 | start_resolving_ping_address(); |
2a4dde8b CH |
407 | // set resolved_ip_count will be called in resolve callback |
408 | } | |
23f51766 CH |
409 | } |
410 | ||
26b0f687 | 411 | void PingScheduler::start_resolving_ping_address() |
23f51766 | 412 | { |
26b0f687 | 413 | Resolver->async_resolve( boost::bind(&PingScheduler::dns_resolve_callback, |
23f51766 CH |
414 | this, _1, _2) ); |
415 | } | |
416 | ||
26b0f687 | 417 | void PingScheduler::dns_resolve_callback(const bool was_success, |
cd71d095 | 418 | const int recursion_count) |
23f51766 | 419 | { |
c1abff61 | 420 | GlobalLogger.info() << LogPrefix << "dns resolution finished " |
23f51766 | 421 | << "with success = " << was_success << " " |
cd71d095 | 422 | << "after " << recursion_count << " recursions"; |
23f51766 | 423 | |
26b0f687 CH |
424 | if ( was_success ) |
425 | { | |
fd62d09f CH |
426 | // trust that a successfull DNS resolve means we have an IP with TTL>0 |
427 | int ip_count = Resolver->get_resolved_ip_count(!ContinueOnOutdatedIps); | |
428 | if (ip_count == 0) | |
429 | { // this will create trouble in HostAnalyzer | |
430 | GlobalLogger.warning() << LogPrefix | |
431 | << "Should not have reached this case: resolve was " | |
432 | << "successfull but still have no IPs (up-to-date=" | |
433 | << !ContinueOnOutdatedIps << ")!"; | |
434 | if (DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() > 0) | |
435 | GlobalLogger.warning() << LogPrefix << "This probably happened " | |
436 | << "because you specified a TTL threshold > 0 but resolving" | |
437 | << " had no effect on TTLs since external cache is only " | |
438 | << "updated when TTL=0 is reached."; | |
439 | } | |
440 | else | |
441 | { | |
442 | GlobalLogger.info() << LogPrefix << "Set resolved_ip_count to " | |
f8918bd5 CH |
443 | << ip_count << " (IPs may be outdated=" |
444 | << ContinueOnOutdatedIps << ") --> could ping now"; | |
fd62d09f CH |
445 | HostAnalyzer.set_resolved_ip_count( ip_count ); |
446 | } | |
8d26221d | 447 | ping_when_ready(); |
26b0f687 CH |
448 | } |
449 | else | |
450 | { // host name resolution failed; try again bypassing first outdated CNAME | |
8d26221d | 451 | // or using cached IP |
26b0f687 | 452 | std::string skip_host = Resolver->get_skip_cname(); |
23f51766 CH |
453 | |
454 | if (skip_host.empty()) | |
838e0acf | 455 | { // try to continue with cached IPs |
fd62d09f | 456 | int ip_count = Resolver->get_resolved_ip_count(false); |
838e0acf CH |
457 | |
458 | if (ip_count == 0) | |
459 | GlobalLogger.notice() << LogPrefix << "DNS failed " | |
460 | << "and have no cached IPs either --> cannot ping"; | |
461 | // ping_when_ready will deal with this case | |
462 | else | |
463 | { | |
464 | ContinueOnOutdatedIps = true; | |
465 | update_log_prefix(); | |
466 | ||
467 | GlobalLogger.notice() << LogPrefix << "DNS failed, " | |
468 | << "try anyway with cached data"; | |
469 | } | |
470 | ||
fd62d09f | 471 | GlobalLogger.info() << LogPrefix << "Set resolved_ip_count to " |
f8918bd5 | 472 | << ip_count << " (IPs may be outdated=" << true << ")"; |
fd62d09f CH |
473 | HostAnalyzer.set_resolved_ip_count( ip_count ); |
474 | ||
8d26221d | 475 | ping_when_ready(); |
23f51766 CH |
476 | } |
477 | else | |
8d26221d | 478 | { // have CNAME to continue |
838e0acf CH |
479 | ContinueOnOutdatedIps = true; |
480 | update_log_prefix(); | |
23f51766 CH |
481 | GlobalLogger.notice() << LogPrefix << "DNS failed, " |
482 | << "try again skipping a CNAME and resolving " | |
483 | << skip_host << " directly"; | |
72be9e7d CH |
484 | |
485 | cancel_resolve(false); | |
486 | ||
487 | // now create new resolver | |
23f51766 | 488 | Resolver = DnsMaster::get_instance() |
26b0f687 | 489 | ->get_resolver_for(skip_host, *ProtocolIter); |
23f51766 CH |
490 | start_resolving_ping_address(); |
491 | } | |
492 | } | |
23f51766 | 493 | } |
72be9e7d CH |
494 | |
495 | /** | |
496 | * cancel resolver if force_cancel or if it is not resolving DestinationAddress | |
497 | * | |
498 | * Resolvers have a life on their own: they are cached by DnsMaster so never go | |
499 | * out of scope and even after calling callbacks, there might still be a | |
500 | * longterm timer active to re-try resolving. | |
501 | * We want to cancel that long-term timer only if the Resolver is not for our | |
502 | * real, original DestinationAddress but a CNAME, which can happen when trying | |
503 | * to skip cnames and working on out-dated IPs | |
504 | */ | |
505 | void PingScheduler::cancel_resolve(const bool force_cancel) | |
506 | { | |
507 | if (force_cancel) | |
508 | { | |
509 | GlobalLogger.info() << "Cancelling resolver (forced)"; | |
510 | Resolver->cancel_resolve(); | |
511 | } | |
512 | else if ( Resolver->get_hostname() == DestinationAddress ) | |
513 | GlobalLogger.info() << LogPrefix | |
514 | << "Leave original resolver active in background"; | |
515 | else | |
516 | { | |
517 | GlobalLogger.info() << LogPrefix << "Cancel resolver for " | |
518 | << Resolver->get_hostname() << " since is not the original " | |
519 | << DestinationAddress; | |
520 | Resolver->cancel_resolve(); | |
521 | } | |
522 | } | |
523 |