merged PingRotate into PingScheduler; fixed save/load of cache to/from file; started...
[pingcheck] / src / host / pingscheduler.cpp
index 2b476f4..694f6a7 100644 (file)
@@ -23,11 +23,13 @@ on this file might be covered by the GNU General Public License.
 #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"
 
@@ -67,22 +69,27 @@ PingScheduler::PingScheduler(
         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() );
@@ -92,13 +99,7 @@ PingScheduler::PingScheduler(
     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();
 }
@@ -164,30 +165,46 @@ void PingScheduler::ping(const boost::system::error_code &error)
 }
 
 
-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();
+    }
 }
 
 
@@ -254,12 +271,13 @@ void PingScheduler::update_ping_elapsed_time()
 // 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() )
     {
@@ -267,11 +285,14 @@ void PingRotate::update_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();
@@ -282,7 +303,7 @@ void PingRotate::get_next_ping_protocol()
     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
@@ -292,8 +313,19 @@ bool PingRotate::can_change_ping_protocol() const
 //------------------------------------------------------------------------------
 // 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())
     {
@@ -311,7 +343,7 @@ void PingRotate::update_dns_resolver( PingProtocol current_protocol )
     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();
@@ -320,28 +352,39 @@ void PingRotate::update_dns_resolver( PingProtocol current_protocol )
         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
@@ -350,13 +393,10 @@ void PingRotate::dns_resolve_callback(const bool was_success,
                 << "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();
-    }
 }