host/pinger.cpp
host/pingerfactory.cpp
host/pinginterval.cpp
+ host/pingnumber.cpp
host/pingprotocol.cpp
host/pingscheduler.cpp
tools/pcap.cpp
}
+void HostStatus::set_n_parallel_pings(const int n_parallel_pings)
+{
+ if (NParallelPingers != n_parallel_pings)
+ {
+ NParallelPingers = n_parallel_pings;
+ reset_ping_counters();
+ }
+ GlobalLogger.debug() << log_prefix() << "#pingers set";
+}
+
+
std::string HostStatus::log_prefix()
{
std::stringstream temp;
<< PingsFailedCount << " fail," << PingCongestionCount << " cong/"
<< PingsPerformedCount << " pings/" << ResolvedIpCount << "*"
<< NParallelPingers << " IPs: ";
+ return temp.str();
}
/**
void HostStatus::update_ping_statistics( const PingStatus &result,
const long ping_duration_us )
{
- float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.;
+ float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.0f;
GlobalLogger.debug() << log_prefix() << "add ping with result "
<< to_string(result) << " which took " << ping_duration_ms << " ms";
bool exceeded_ping_congestion_limit() const;
void update_ping_statistics( const PingStatus &ping_success,
const long ping_duration_us );
+ void set_n_parallel_pings(const int n_parallel_pings);
private:
void update_fail_stats( const PingStatus &ping_success );
BOOST_ASSERT( 0 < Interval );
}
+/** returns true if have not speeded up yet */
bool PingInterval::can_speed_up() const
{
- PingIntervalType half_original = OriginalInterval / 2;
-
- return ( Interval > half_original );
+ return Interval == OriginalInterval;
}
--- /dev/null
+/*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
+#include "host/pingnumber.h"
+
+#include "boost_assert_handler.h"
+
+//-----------------------------------------------------------------------------
+// PingNumber
+//-----------------------------------------------------------------------------
+
+PingNumber::PingNumber(
+ const PingNumberType number
+) :
+ OriginalNumber( number ),
+ Number( number )
+{
+ BOOST_ASSERT( 0 < number );
+}
+
+PingNumber::~PingNumber()
+{
+}
+
+PingNumber::operator PingNumberType() const
+{
+ BOOST_ASSERT( 0 < Number );
+
+ return Number;
+}
+
+void PingNumber::back_to_original()
+{
+ Number = OriginalNumber;
+
+ BOOST_ASSERT( 0 < Number );
+}
+
+void PingNumber::increase()
+{
+ BOOST_ASSERT( 0 < Number );
+
+ if ( can_increase() )
+ {
+ Number = Number * 5;
+ }
+
+ BOOST_ASSERT( 0 < Number );
+}
+
+/** returns true if have not increased yet */
+bool PingNumber::can_increase() const
+{
+ return Number == OriginalNumber;
+}
--- /dev/null
+/*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
+#ifndef PING_NUMBER_H
+#define PING_NUMBER_H
+
+//-----------------------------------------------------------------------------
+// PingNumberType
+//-----------------------------------------------------------------------------
+
+typedef int PingNumberType;
+
+//-----------------------------------------------------------------------------
+// PingNumber
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief Class designed to behave like a scalar type (i.e. int, long), but
+ * with helper methods to encapsulate a increase of ping number and a return
+ * to the original number
+ *
+ * Scope: one object per host.
+ */
+class PingNumber
+{
+public:
+ PingNumber( const PingNumberType number );
+ ~PingNumber();
+
+ operator PingNumberType() const;
+
+ void back_to_original();
+ void increase();
+
+private:
+ bool can_increase() const;
+
+private:
+ /// the original number to ping, unchangeable
+ const PingNumberType OriginalNumber;
+ /// the actual number exported by this object
+ PingNumberType Number;
+
+};
+
+#endif // PING_NUMBER_H
Protocols( ping_protocol_list ),
ProtocolIter(),
PingIntervalInSec( ping_interval_in_sec ),
+ NPingers( n_parallel_pings ),
FirstDelay( first_delay ),
NextPingTimer( *io_serv ),
TimeSentLastPing( microsec_clock::universal_time() ),
link_analyzer ),
Resolver(),
Pingers(),
- NPingers( n_parallel_pings ),
NPingersDone( 0 ),
ParallelPingDelay( parallel_ping_delay ),
DelayedPingTimer( *io_serv ),
update_log_prefix();
init_ping_protocol();
+
+ // start resolving already so we are prepared to ping
+ update_dns_resolver();
+
}
/**
return;
}
else if ( !Resolver )
+ {
// should not happen, but check anyway
GlobalLogger.warning() << LogPrefix << "Have no resolver!";
+ return;
+ }
GlobalLogger.info() << LogPrefix << "start ping";
WantToPing = false;
}
else
{
+ // create new pingers
+ for (int count=0; count<NPingers; ++count)
+ Pingers.push_back(
+ PingerFactory::createPinger(*ProtocolIter, IoService,
+ NetworkInterfaceName,
+ PingReplyTimeout) );
+
+ // remember when pinging started
+ TimeSentLastPing = microsec_clock::universal_time();
+
+ // get actual IP
boost::asio::ip::address actual_ip = ip.get_ip();
GlobalLogger.info() << LogPrefix << "pinging IP " << actual_ip
<< " with TTL " << ip.get_ttl().get_updated_value() << "s";
- delayed_ping(boost::system::error_code(), actual_ip, 0);
NPingersDone = 0;
- TimeSentLastPing = microsec_clock::universal_time();
+ delayed_ping(boost::system::error_code(), actual_ip, 0);
}
}
void PingScheduler::delayed_ping( const boost::system::error_code &error,
- const boost::asio::ip::address &ip,
+ const boost::asio::ip::address ip,
const int pinger_index )
{
if (error)
<< error;
return;
}
- if (pinger_index == NPingers)
- {
- GlobalLogger.debug() << LogPrefix << "started all delayed pings";
- return;
- }
GlobalLogger.debug() << LogPrefix << "starting delayed ping index "
<< pinger_index;
DestinationPort,
boost::bind(&PingScheduler::ping_done_handler,
this, _1, _2) );
- DelayedPingTimer.expires_from_now( milliseconds(ParallelPingDelay) );
- DelayedPingTimer.async_wait( bind( &PingScheduler::delayed_ping,
+ if (pinger_index >= NPingers-1)
+ GlobalLogger.debug() << LogPrefix << "started all delayed pings";
+ else
+ {
+ DelayedPingTimer.expires_from_now( milliseconds(ParallelPingDelay) );
+ DelayedPingTimer.async_wait( bind( &PingScheduler::delayed_ping,
this, boost::asio::placeholders::error, ip, pinger_index+1) );
+ }
}
// prepare next ping only after all pingers are done
if (NPingersDone == NPingers)
+ {
+ // stop and destruct all pingers
+ clear_pingers();
+
+ GlobalLogger.debug() << LogPrefix
+ << "--------------------------------------------------------------";
+
+ // update variables for next ping: number of pings, delay, protocol
+ update_ping_protocol();
+ update_ping_interval();
+ update_ping_number();
+
prepare_next_ping();
+ }
}
void PingScheduler::prepare_next_ping()
{
- update_ping_interval();
-
- // get next protocol, possibly start resolving IPs
- update_ping_protocol();
+ // start DNS resolve if necessary
+ update_dns_resolver();
// schedule next ping
int seconds_since_last_ping = (microsec_clock::universal_time()
}
}
+/** in case of congested line, increase number of pings
+ *
+ * CAUTION! Only call this after clear_pingers !!!
+ * */
+void PingScheduler::update_ping_number()
+{
+ // make sure we do not loose track of pingers here
+ if ( NPingersDone != NPingers || !Pingers.empty() )
+ {
+ GlobalLogger.warning() << LogPrefix << "Should only change number of "
+ << "pingers when all are finished and deleted! Have " << NPingers
+ << " pingers, " << NPingersDone << " of which are done and "
+ << Pingers.size() << " in listDone! Will not change NPingers.";
+ return;
+ }
+
+ if ( HostAnalyzer.exceeded_ping_congestion_limit() )
+ {
+ NPingers.increase();
+
+ GlobalLogger.debug() << LogPrefix << "- Increasing ping number to: "
+ << NPingers;
+ }
+ else
+ {
+ NPingers.back_to_original();
+
+ GlobalLogger.debug() << LogPrefix << "- Stick to the original ping "
+ << "number: " << NPingers;
+ }
+
+ HostAnalyzer.set_n_parallel_pings(NPingers);
+}
+
//------------------------------------------------------------------------------
// Ping Protocol Rotation
//------------------------------------------------------------------------------
void PingScheduler::get_next_ping_protocol()
{
- // stop and destruct all pingers
- clear_pingers();
- GlobalLogger.debug() << LogPrefix
- << "------------------------------------------------------------------";
-
- // get next 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
-
- // create new pingers
- for (int count=0; count<NPingers; ++count)
- Pingers.push_back( PingerFactory::createPinger(ping_protocol, IoService,
- NetworkInterfaceName, PingReplyTimeout) );
-
- update_dns_resolver( ping_protocol );
}
bool PingScheduler::can_change_ping_protocol() const
LogPrefix = temp.str();
}
-void PingScheduler::update_dns_resolver( PingProtocol current_protocol )
+void PingScheduler::update_dns_resolver()
{
if (Resolver && Resolver->is_resolving())
cancel_resolve(false);
// probably just return an existing resolver with already resolved IPs for
// requested protocol ( ICMP/TCP is ignored, only IPv4/v6 is important)
Resolver = DnsMaster::get_instance()->get_resolver_for(DestinationAddress,
- current_protocol);
+ *ProtocolIter);
// get number of up-to-date IPs
// TODO should check here, if they will be up to date in PingIntervalInSec
#include "host/pingstatus.h"
#include "host/pinger.h"
#include "host/pinginterval.h"
+#include "host/pingnumber.h"
#include "host/pingprotocol.h"
#include "dns/resolverbase.h"
void ping_done_handler(const PingStatus &result,
const long ping_duration_us);
void update_ping_interval();
+ void update_ping_number();
void init_ping_protocol();
void update_ping_protocol();
bool can_change_ping_protocol() const;
void prepare_next_ping();
- void update_dns_resolver( PingProtocol current_protocol );
+ void update_dns_resolver();
void ping_when_ready();
void delayed_ping( const boost::system::error_code &error,
- const boost::asio::ip::address &ip,
+ const boost::asio::ip::address ip,
const int pinger_index );
void dns_resolve_callback(const bool was_success,
const int recursion_count);
PingProtocolList::const_iterator ProtocolIter;
/// Interval between each ping to the same host
PingInterval PingIntervalInSec;
+ /// number of pingers that work in parallel
+ PingNumber NPingers;
/// delay for very first ping to avoid lots of simultaneous pings at startup
int FirstDelay;
/// Timer to trigger the next ping
ResolverItem Resolver;
/// vector of pingers
pinger_vec Pingers;
- /// number of pingers that work in parallel
- int NPingers;
/// number of results from pingers
int NPingersDone;
/// delay (in ms) between pings to same IP
// get delay for this scheduler and update assigned delays
int current_delay = boost::math::iround(delays[ping_interval_in_sec]);
delays[ping_interval_in_sec] += delay_shifts[ping_interval_in_sec];
- int n_parallel_pings = 10;
+ int n_parallel_pings = 2;
int parallel_ping_delay = 100; // ms
int congestion_duration_thresh = 10; // seconds
int congestion_percentage_thresh = 75;