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