icmp/icmppacket.cpp
icmp/icmppacketfactory.cpp
icmp/icmppinger.cpp
+ icmp/icmppaketdistributor.cpp
ip/ipv4header.cpp
ip/ipv6header.cpp
link/linkstatus.cpp
boost::function<void(bool)> ping_done_callback
) = 0;
+ virtual void stop_pinging() = 0;
+
protected:
Pinger();
virtual ~Pinger();
#include <logfunc.hpp>
#include "boost_assert_handler.h"
+#include "icmp/icmppaketdistributor.h"
#include "icmp/icmppinger.h"
#include "tcp/tcppinger.h"
try
{
- switch ( protocol )
+ if (protocol == PingProtocol_ICMP)
{
- case PingProtocol_ICMP:
- return PingerItem(
+ PingerItem new_pinger(
new IcmpPinger( io_serv, icmp::v4(), network_interface, ping_reply_timeout )
);
- case PingProtocol_ICMPv6:
- return PingerItem(
+ IcmpPaketDistributor::get_distributor(icmp::v4(), network_interface, io_serv)
+ ->register_pinger(new_pinger);
+ return new_pinger;
+ }
+ else if (protocol == PingProtocol_ICMPv6)
+ {
+ PingerItem new_pinger(
new IcmpPinger( io_serv, icmp::v6(), network_interface, ping_reply_timeout )
);
- case PingProtocol_TCP:
+ IcmpPaketDistributor::get_distributor(icmp::v6(), network_interface, io_serv)
+ ->register_pinger(new_pinger);
+ return new_pinger;
+ }
+ else if (protocol == PingProtocol_TCP)
+ {
return PingerItem(
new TcpPinger( io_serv, tcp_raw_protocol::v4(), network_interface, ping_reply_timeout )
);
- case PingProtocol_TCP_IPv6:
+ }
+ else if (protocol == PingProtocol_TCP_IPv6)
+ {
return PingerItem(
new TcpPinger( io_serv, tcp_raw_protocol::v6(), network_interface, ping_reply_timeout )
);
- default:
+ }
+ else
+ {
BOOST_ASSERT( !"Try to create a pinger from an invalid protocol" ); //lint !e506
return PingerItem(); //lint !e527
}
);
}
+void PingRotate::stop_pinging()
+{
+ Ping->stop_pinging();
+}
+
bool PingRotate::resolve_ping_address() //lint !e1762
{
return IpList->resolve();
void ping( boost::function<void(bool)> ping_done_callback );
+ void stop_pinging();
+
bool resolve_ping_address();
int get_resolved_ip_count() const;
bool expired_resolved_ip() const;
void PingScheduler::stop_pinging()
{
+ Ping->stop_pinging();
}
/**
--- /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.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#include "icmppaketdistributor.h"
+
+#include <errno.h>
+#include <logfunc.hpp>
+#include <boost/bind.hpp>
+
+#include "boost_assert_handler.h"
+
+
+using I2n::Logger::GlobalLogger;
+using boost::asio::ip::icmp;
+
+static const std::size_t SOCKET_BUFFER_SIZE = 65536; // 64kB
+
+typedef std::set<PingerItem>::iterator PingerListIterator;
+
+
+bool IcmpPaketDistributorInstanceIdentifierComparator::operator() (
+ const DistributorInstanceIdentifier &a,
+ const DistributorInstanceIdentifier &b ) const
+{
+ if ( a.first == boost::asio::ip::icmp::v4() )
+ {
+ if ( b.first == boost::asio::ip::icmp::v4() )
+ return a.second < b.second; // v4 == v4
+ else
+ BOOST_ASSERT( b.first == boost::asio::ip::icmp::v6() );
+ return true; // a(v4) < b(b6)
+ }
+ else
+ {
+ BOOST_ASSERT( a.first == boost::asio::ip::icmp::v6() );
+
+ if ( b.first == boost::asio::ip::icmp::v4() )
+ return false; // a(v6) > b(v4)
+ else
+ BOOST_ASSERT( b.first == boost::asio::ip::icmp::v6() );
+ return a.second < b.second; // v6 == v6
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Definition of IcmpPaketDistributor
+//-----------------------------------------------------------------------------
+
+std::map<DistributorInstanceIdentifier, IcmpPaketDistributorItem,
+ IcmpPaketDistributorInstanceIdentifierComparator> IcmpPaketDistributor::Instances;
+
+IcmpPaketDistributorItem IcmpPaketDistributor::get_distributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface,
+ const IoServiceItem io_serv )
+{
+ DistributorInstanceIdentifier identifier(protocol, network_interface);
+
+ // check if there is an instance for this protocol and interface
+ if ( Instances.count(identifier) == 0 )
+ { // need to create an instance for this protocol and network interface
+ GlobalLogger.info() << "Creating IcmpPaketDistributor for interface "
+ << network_interface << std::endl;
+ IcmpPaketDistributorItem new_instance( new IcmpPaketDistributor(
+ protocol, network_interface, io_serv ) );
+ Instances[identifier] = new_instance;
+ }
+
+ BOOST_ASSERT( Instances.count(identifier) == 1 );
+
+ // return the one instance for this protocol and interface
+ return Instances[identifier];
+}
+
+
+IcmpPaketDistributorItem IcmpPaketDistributor::get_distributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface )
+{
+ DistributorInstanceIdentifier identifier(protocol, network_interface);
+
+ BOOST_ASSERT( Instances.count(identifier) == 1 );
+
+ // return the one instance for this protocol and interface
+ return Instances[identifier];
+}
+
+
+IcmpPaketDistributor::IcmpPaketDistributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface,
+ const IoServiceItem io_serv ):
+ Socket( *io_serv, protocol ),
+ Protocol( protocol ),
+ ReplyBuffer(),
+ PingerList()
+{
+ NetworkInterface<icmp::socket, boost::asio::ip::icmp>
+ NetInterface( network_interface, Socket );
+
+ if ( !NetInterface.bind() )
+ {
+ GlobalLogger.error()
+ << "Trouble creating IcmpPaketDistributor for interface "
+ << network_interface// << " and protocol " << protocol
+ << ": could not bind the socket with the local interface. "
+ << ::strerror( errno ) << std::endl;
+ }
+
+ register_receive_handler();
+}
+
+
+void IcmpPaketDistributor::register_receive_handler()
+{
+ // Waiting for a reply, We prepare the buffer to receive up to SOCKET_BUFFER_SIZE bytes
+ Socket.async_receive(
+ ReplyBuffer.prepare( SOCKET_BUFFER_SIZE ),
+ boost::bind( &IcmpPaketDistributor::handle_receive, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred )
+ );
+}
+
+void IcmpPaketDistributor::handle_receive( const boost::system::error_code &error,
+ const size_t &bytes_transferred )
+{
+ if ( error )
+ {
+ GlobalLogger.warning()
+ << ": Received error " << error
+ << " in ICMP packet distributor; end handler and schedule another.";
+ register_receive_handler();
+ return;
+ }
+
+ // The actual number of bytes received is committed to the buffer so that we
+ // can extract it using a std::istream object.
+ ReplyBuffer.commit( bytes_transferred );
+
+ GlobalLogger.info() << "received paket in distributor" << std::endl;
+
+ register_receive_handler();
+}
+
+bool IcmpPaketDistributor::register_pinger( const PingerItem new_pinger )
+{
+ std::pair<PingerListIterator, bool> result = PingerList.insert(new_pinger);
+ bool was_new = result.second;
+ if (was_new)
+ GlobalLogger.info() << "Register new pinger with IcmpPaketDistributor" << std::endl;
+ else
+ GlobalLogger.warning() << "Pinger to register was already known in IcmpPaketDistributor"
+ << std::endl;
+ return was_new;
+}
+
+
+bool IcmpPaketDistributor::unregister_pinger( const PingerItem old_pinger )
+{
+ int n_erased = PingerList.erase(old_pinger);
+ bool was_erased = n_erased > 0;
+ if (was_erased)
+ GlobalLogger.info() << "Removed pinger from IcmpPaketDistributor" << std::endl;
+ else
+ GlobalLogger.warning() << "Could not find pinger to remove from IcmpPaketDistributor"
+ << std::endl;
+ return was_erased;
+}
+
+// (created using vim -- the world's best text editor)
+
--- /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.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#ifndef ICMP_PAKET_DISTRIBUTOR_H
+#define ICMP_PAKET_DISTRIBUTOR_H
+
+#include <set>
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/asio.hpp>
+
+#include "host/pinger.h"
+#include "host/networkinterface.hpp"
+
+using boost::asio::ip::icmp;
+
+// for each IP protocol (v4/v6) and each network interface (string),
+// there can only be one IcmpPaketDistributor instance
+typedef std::pair<icmp::socket::protocol_type, std::string> DistributorInstanceIdentifier;
+
+struct IcmpPaketDistributorInstanceIdentifierComparator
+{
+ bool operator() ( const DistributorInstanceIdentifier &a,
+ const DistributorInstanceIdentifier &b ) const ;
+};
+
+class IcmpPaketDistributor;
+
+typedef boost::shared_ptr<IcmpPaketDistributor> IcmpPaketDistributorItem;
+
+//-----------------------------------------------------------------------------
+// IcmpPaketDistributor
+//-----------------------------------------------------------------------------
+
+class IcmpPaketDistributor
+{
+public:
+ bool register_pinger( const PingerItem new_pinger );
+ bool unregister_pinger( const PingerItem old_pinger );
+
+ static IcmpPaketDistributorItem get_distributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface,
+ const IoServiceItem io_serv );
+
+ static IcmpPaketDistributorItem get_distributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface );
+
+ ~IcmpPaketDistributor() {};
+
+private:
+ // hide away constructor, copy constructor and copy operator
+ IcmpPaketDistributor(
+ const icmp::socket::protocol_type &protocol,
+ const std::string &network_interface,
+ const IoServiceItem io_serv );
+ IcmpPaketDistributor(IcmpPaketDistributor const&);
+ void operator=(IcmpPaketDistributor const&);
+
+ void register_receive_handler();
+ void handle_receive( const boost::system::error_code &error,
+ const size_t &bytes_transferred );
+
+
+private:
+ /// The socket object
+ icmp::socket Socket;
+
+ /// Network layer protocol used to ping, IPv4 or IPv6
+ icmp::socket::protocol_type Protocol;
+
+ /// The buffer where the data received will be placed
+ boost::asio::streambuf ReplyBuffer;
+
+ std::set<PingerItem> PingerList;
+
+ /// Instances, one for each (protocol, interface) - pair
+ static std::map<DistributorInstanceIdentifier, IcmpPaketDistributorItem,
+ IcmpPaketDistributorInstanceIdentifierComparator> Instances;
+
+};
+
+
+#endif // ICMP_PAKET_DISTRIBUTOR_H
+
+// (created using vim -- the world's best text editor)
+
#include "boost_assert_handler.h"
#include "icmp/icmppacketfactory.h"
+#include "icmp/icmppaketdistributor.h"
using namespace std;
using boost::asio::const_buffers_1;
// there might still be an old handler in place... cancel?
}
+void IcmpPinger::stop_pinging()
+{
+ IcmpPaketDistributor::get_distributor(Protocol, NetInterface.get_name())
+ ->unregister_pinger(PingerItem(this));
+}
+
+
void IcmpPinger::set_destination_endpoint( const string &destination_ip )
{
BOOST_ASSERT( !destination_ip.empty() );
boost::function<void(bool)> ping_done_callback
);
+ virtual void stop_pinging();
+
private:
void set_destination_endpoint( const std::string &destination_ip );
start_receive();
}
+void TcpPinger::stop_pinging()
+{
+}
+
address TcpPinger::get_source_address() const
{
return NetInterface.get_address( Protocol );
boost::function<void(bool)> ping_done_callback
);
+ virtual void stop_pinging();
+
private:
boost::asio::ip::address get_source_address() const;
boost::asio::ip::address get_destination_address() const;