#include <limits>
#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
#include <logfunc.hpp>
#include "boost_assert_handler.h"
#include "host/pingerfactory.h"
+#include "dns/dnsmaster.h"
#include "icmp/icmppinger.h"
#include "link/linkstatus.h"
const long ping_interval_in_sec,
const int ping_fail_percentage_limit,
const int ping_reply_timeout,
- const int resolved_ip_ttl_threshold,
LinkStatusItem link_analyzer,
const int first_delay
) :
IoService( io_serv ),
NetworkInterfaceName( network_interface ),
- Resolver(),
DestinationAddress( destination_address ),
DestinationPort( destination_port ),
+ Protocols( ping_protocol_list ),
+ ProtocolIter(),
+ PingIntervalInSec( ping_interval_in_sec ),
+ FirstDelay( first_delay ),
NextPingTimer( *io_serv ),
TimeSentLastPing( microsec_clock::universal_time() ),
- PingIntervalInSec( ping_interval_in_sec ),
+ PingReplyTimeout( ping_reply_timeout ),
HostAnalyzer( destination_address, ping_fail_percentage_limit, link_analyzer ),
- FirstDelay( first_delay ),
- Ping()
+ Resolver(),
+ Ping(),
+ WantToPing( false ),
+ LogPrefix(),
+ ContinueOnOutdatedIps( false );
{
BOOST_ASSERT( !network_interface.empty() );
BOOST_ASSERT( !destination_address.empty() );
BOOST_ASSERT( (0 <= ping_fail_percentage_limit) &&
( ping_fail_percentage_limit <= 100) );
- std::stringstream temp;
- temp << "PS(" << DestinationAddress << "): ";
- LogPrefix = temp.str();
-
- // fill circular buffer with protocols
- BOOST_FOREACH( const PingProtocol &prot, protocol_list )
- ProtocolRotate.push_back(prot);
+ update_log_prefix();
init_ping_protocol();
}
}
-void PingRotate::try_to_ping()
+void PingScheduler::try_to_ping()
{
if ( !WantToPing )
{
- GlobalLogger.info() << "PingRotate: not pinging yet (not requested to)";
+ GlobalLogger.info() << "PingScheduler: not pinging (not requested to)";
return;
}
else if ( Resolver && Resolver->is_resolving() )
{
- GlobalLogger.info() << "PingRotate: not pinging yet (DNS not finished)";
+ GlobalLogger.info() << "PingScheduler: not pinging (DNS not finished)";
return;
}
else if ( !Resolver )
// should not happen, but check anyway
GlobalLogger.warning() << LogPrefix << "Have no resolver!";
- GlobalLogger.info() << "PingRotate: start ping";
+ GlobalLogger.info() << "PingScheduler: start ping";
WantToPing = false;
- Ping->ping(
- Resolver->get_next_ip().get_ip(),
- DestinationPort,
- boost::bind(&PingScheduler::ping_done_handler, this, _1)
- );
+ HostAddress ip = Resolver->get_next_ip();
+ if ( !ip.is_valid() && ContinueOnOutdatedIps)
+ {
+ GlobalLogger.info() << LogPrefix << "Checking for outdated IPs";
+ bool check_up_to_date = false;
+ ip = Resolver->get_next_ip(check_up_to_date);
+ }
+ if ( ip.is_valid() )
+ Ping->ping(
+ Resolver->get_next_ip().get_ip(),
+ DestinationPort,
+ boost::bind(&PingScheduler::ping_done_handler, this, _1)
+ );
+ else
+ { // should not happen
+ GlobalLogger.error() << LogPrefix << "No IP to ping "
+ << "-- this should not have happened!!";
+ WantToPing = true;
+ if ( !Resolver.is_resolving() )
+ start_resolving_ping_address();
+ }
}
// Ping Protocol Rotation
//------------------------------------------------------------------------------
-void PingRotate::init_ping_protocol()
+void PingScheduler::init_ping_protocol()
{
+ ProtocolIter = Protocols.end();
get_next_ping_protocol();
}
-void PingRotate::update_ping_protocol()
+void PingScheduler::update_ping_protocol()
{
if ( can_change_ping_protocol() )
{
}
}
-void PingRotate::get_next_ping_protocol()
+void PingScheduler::get_next_ping_protocol()
{
- PingProtocol ping_protocol = ProtocolRotate.front();
- ProtocolRotate.pop_front();
- ProtocolRotate.push_back(ping_protocol);
+ ++ProtocolIter;
+ if (ProtocolIter == Protocols.end())
+ ProtocolIter = Protocols.begin();
+ PingProtocol ping_protocol = *ProtocolIter;
+ // --> ProtocolIter still points to currently used protocol which is
+ // required in dns_resolve_callback
if (Ping)
Ping->stop_pinging();
update_dns_resolver( ping_protocol );
}
-bool PingRotate::can_change_ping_protocol() const
+bool PingScheduler::can_change_ping_protocol() const
{
// TODO can_change_ping_protocol() and get_next_ping_protocol() may be implemented in a Algorithm
// class that can be exchanged in this class to provide an algorithm neutral class
//------------------------------------------------------------------------------
// DNS host name resolution
//------------------------------------------------------------------------------
-//
-void PingRotate::update_dns_resolver( PingProtocol current_protocol )
+
+// show "!" after host name if running on outdated IPs
+void update_log_prefix()
+{
+ std::stringstream temp;
+ temp << "PS(" << DestinationAddress;
+ if (ContinueOnOutdatedIps)
+ temp << "!";
+ temp << "): ";
+ LogPrefix = temp.str();
+}
+
+void PingScheduler::update_dns_resolver( PingProtocol current_protocol )
{
if (Resolver && Resolver->is_resolving())
{
if ( Resolver->have_up_to_date_ip() )
{
if (!Resolver->is_resolving())
- GlobalLogger.warning() << "PingRotate: have up to date IPs but "
+ GlobalLogger.warning() << "PingScheduler: have up to date IPs but "
<< "resolver seems to be resolving all the same... "
<< "Start pinging anyway!";
try_to_ping();
start_resolving_ping_address();
}
-void PingRotate::start_resolving_ping_address() //lint !e1762
+void PingScheduler::start_resolving_ping_address()
{
- Resolver->async_resolve( boost::bind(&PingRotate::dns_resolve_callback,
+ Resolver->async_resolve( boost::bind(&PingScheduler::dns_resolve_callback,
this, _1, _2) );
}
-void PingRotate::dns_resolve_callback(const bool was_success,
- const int cname_count)
+void PingScheduler::dns_resolve_callback(const bool was_success,
+ const int cname_count)
{
- GlobalLogger.info() << "PingRotate: dns resolution finished "
+ GlobalLogger.info() << "PingScheduler: dns resolution finished "
<< "with success = " << was_success << " "
<< "and cname_count = " << cname_count;
- if ( !was_success )
- { // host name resolution failed; try again bypassing first CNAME(s)
- std::string skip_host = Resolver->get_skipper();
+ // TODO this is too simple, but need to think more about how to update here!
+ // (may have to switch back some time to resolver for original host or so
+ ContinueOnOutdatedIps = true;
+ update_log_prefix();
+
+ if ( was_success )
+ {
+ HostAnalyzer.set_resolved_ip_count( Resolver->get_resolved_ip_count());
+ try_to_ping();
+ }
+ else
+ { // host name resolution failed; try again bypassing first outdated CNAME
+
+ std::string skip_host = Resolver->get_skip_cname();
if (skip_host.empty())
{
GlobalLogger.notice() << LogPrefix << "DNS failed, "
<< "try anyway with cached data";
- HostAnalyzer->set_resolved_ip_count(0);
+ HostAnalyzer.set_resolved_ip_count(0);
try_to_ping();
}
else
<< "try again skipping a CNAME and resolving "
<< skip_host << " directly";
Resolver = DnsMaster::get_instance()
- ->get_resolver_for(skip_host, PingRotate.back());
+ ->get_resolver_for(skip_host, *ProtocolIter);
+ // the original resolver is still alive and cached by DnsMaster
+ // and counting down the time to re-try on its own
start_resolving_ping_address();
}
}
- else
- {
- HostAnalyzer->set_resolved_ip_count( Resolver->get_resolved_ip_count());
- try_to_ping();
- }
}