+++ /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 "icmppacketdistributor.h"
-
-#include <istream>
-#include <errno.h>
-#include <logfunc.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-
-#include "boost_assert_handler.h"
-#include "host/networkinterface.hpp"
-#include "icmp/icmppacketfactory.h"
-
-
-using I2n::Logger::GlobalLogger;
-using boost::asio::ip::icmp;
-
-static const std::size_t SOCKET_BUFFER_SIZE = 65536; // 64kB
-
-typedef std::set<IcmpPingerItem>::iterator PingerListIterator;
-
-
-bool IcmpPacketDistributor::InstanceIdentifierComparator::operator() (
- const IcmpPacketDistributor::DistributorInstanceIdentifier &a,
- const IcmpPacketDistributor::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 IcmpPacketDistributor
-//-----------------------------------------------------------------------------
-
-IcmpPacketDistributor::map_type IcmpPacketDistributor::Instances; // initialize
-
-
-IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface,
- const IoServiceItem io_serv )
-{
- IcmpPacketDistributor::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 IcmpPacketDistributor for interface "
- << network_interface << std::endl;
- IcmpPacketDistributorItem new_instance( new IcmpPacketDistributor(
- 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];
-}
-
-
-IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface )
-{
- IcmpPacketDistributor::DistributorInstanceIdentifier identifier(
- protocol, network_interface);
-
- BOOST_ASSERT( Instances.count(identifier) == 1 );
-
- // return the one instance for this protocol and interface
- return Instances[identifier];
-}
-
-
-IcmpPacketDistributor::IcmpPacketDistributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface,
- const IoServiceItem io_serv ):
- Protocol( protocol ),
- ReplyBuffer(),
- PingerList()
-{
- Socket = SocketItem( new icmp::socket(*io_serv, protocol) );
- NetworkInterface<icmp::socket, boost::asio::ip::icmp>
- NetInterface( network_interface, *Socket );
-
- if ( !NetInterface.bind() )
- {
- GlobalLogger.error()
- << "Trouble creating IcmpPacketDistributor for interface "
- << network_interface// << " and protocol " << protocol
- << ": could not bind the socket with the local interface. "
- << ::strerror( errno ) << std::endl;
- }
-
- register_receive_handler();
-}
-
-
-void IcmpPacketDistributor::register_receive_handler()
-{
- // wait for reply, prepare buffer to receive up to SOCKET_BUFFER_SIZE bytes
- Socket->async_receive(
- ReplyBuffer.prepare( SOCKET_BUFFER_SIZE ),
- boost::bind( &IcmpPacketDistributor::handle_receive, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred )
- );
-}
-
-void IcmpPacketDistributor::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 packet in distributor" << std::endl;
-
- try
- {
- std::istream is( &ReplyBuffer );
- if ( !is )
- {
- GlobalLogger.error() << "Can't handle ReplyBuffer" << std::endl;
- return;
- }
-
- // Decode the reply packet.
- IcmpPacketItem icmp_packet = IcmpPacketFactory::create_icmp_packet(
- Protocol, is );
- if ( !icmp_packet )
- {
- GlobalLogger.warning() << "Ignoring broken ICMP packet"
- << std::endl;
- }
-
- // check which pinger wants this packet
- bool packet_matches = false;
- BOOST_FOREACH( IcmpPingerItem pinger, PingerList )
- {
- packet_matches |= pinger->handle_receive_icmp_packet(icmp_packet,
- bytes_transferred);
- if (packet_matches)
- break;
- }
-
- if (!packet_matches)
- GlobalLogger.warning() << "Packet did not match any pinger"
- << std::endl;
- }
- catch ( ... )
- {
- GlobalLogger.notice() << "Exception during ICMP parse." << std::endl;
- }
-
- // re-register receive handler
- register_receive_handler();
-}
-
-bool IcmpPacketDistributor::register_pinger( const IcmpPingerItem &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 IcmpPacketDistributor"
- << std::endl;
- else
- GlobalLogger.warning()
- << "Pinger to register was already known in IcmpPacketDistributor"
- << std::endl;
- return was_new;
-}
-
-
-bool IcmpPacketDistributor::unregister_pinger( const IcmpPingerItem &old_pinger )
-{
- int n_erased = PingerList.erase(old_pinger);
- bool was_erased = n_erased > 0;
- if (was_erased)
- GlobalLogger.info() << "Removed pinger from IcmpPacketDistributor"
- << std::endl;
- else
- GlobalLogger.warning()
- << "Could not find pinger to remove from IcmpPacketDistributor"
- << std::endl;
- return was_erased;
-}
-
-/**
- * @brief for all instances: close sockets, unregister all pingers
- */
-void IcmpPacketDistributor::clean_up_all()
-{
- BOOST_FOREACH( IcmpPacketDistributor::map_type::value_type &instance,
- Instances )
- instance.second->clean_up();
-
- Instances.clear();
-}
-
-void IcmpPacketDistributor::clean_up()
-{
- if (PingerList.size() > 0)
- GlobalLogger.warning() << "There were still " << PingerList.size()
- << " pingers registered in IcmpPacketDistributor!" << std::endl;
- PingerList.clear();
-
- boost::system::error_code error;
- //Socket->shutdown(icmp::socket::shutdown_both, error); //both=send&receive
- //if ( error )
- // GlobalLogger.warning() << "Received error " << error
- // << " when shutting down ICMP socket";
- // always gave an error system:9 (probably EBADF: Bad file descriptor)
-
- Socket->close(error);
- if ( error )
- GlobalLogger.warning() << "Received error " << error
- << " when closing ICMP socket";
-}
-
-IcmpPacketDistributor::~IcmpPacketDistributor()
-{
- GlobalLogger.info() << "Destroying IcmpPacketDistributor" << std::endl;
-}
-
-SocketItem IcmpPacketDistributor::get_socket() const
-{
- return Socket;
-}
-// (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_PACKET_DISTRIBUTOR_H
-#define ICMP_PACKET_DISTRIBUTOR_H
-
-#include <set>
-#include <map>
-#include <boost/shared_ptr.hpp>
-#include <boost/asio.hpp>
-
-#include "icmp/icmppinger.h"
-
-using boost::asio::ip::icmp;
-
-typedef boost::shared_ptr<boost::asio::io_service> IoServiceItem;
-typedef boost::shared_ptr<icmp::socket> SocketItem;
-
-//-----------------------------------------------------------------------------
-// IcmpPacketDistributor
-//-----------------------------------------------------------------------------
-
-class IcmpPacketDistributor;
-typedef boost::shared_ptr<IcmpPacketDistributor> IcmpPacketDistributorItem;
-
-class IcmpPacketDistributor
-{
-public:
- bool register_pinger( const IcmpPingerItem &new_pinger );
- bool unregister_pinger( const IcmpPingerItem &old_pinger );
-
- SocketItem get_socket() const;
-
- static IcmpPacketDistributorItem get_distributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface,
- const IoServiceItem io_serv
- );
-
- static IcmpPacketDistributorItem get_distributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface
- );
-
- static void clean_up_all();
-
- ~IcmpPacketDistributor();
-
-private:
- // hide away constructor, copy constructor and assignment operator
- IcmpPacketDistributor(
- const icmp::socket::protocol_type &protocol,
- const std::string &network_interface,
- const IoServiceItem io_serv
- );
- IcmpPacketDistributor(IcmpPacketDistributor const&);
- void operator=(IcmpPacketDistributor const&);
-
- void register_receive_handler();
- void handle_receive( const boost::system::error_code &error,
- const size_t &bytes_transferred );
- void clean_up();
-
-
-private:
- /// The socket object
- SocketItem 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<IcmpPingerItem> PingerList;
-
- // for each IP protocol (v4/v6) and each network interface (string),
- // there can only be one IcmpPacketDistributor instance
- typedef std::pair<icmp::socket::protocol_type, std::string>
- DistributorInstanceIdentifier;
-
- struct InstanceIdentifierComparator
- {
- bool operator() ( const DistributorInstanceIdentifier &a,
- const DistributorInstanceIdentifier &b ) const ;
- };
-
- typedef std::map<DistributorInstanceIdentifier, IcmpPacketDistributorItem,
- InstanceIdentifierComparator> map_type;
- /// Instances, one for each (protocol, interface) - pair
- static map_type Instances;
-
-};
-
-#endif // ICMP_PACKET_DISTRIBUTOR_H
-
-// (created using vim -- the world's best text editor)
-