// Boost pinger (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG // Based upon work copyright (c) 2003-2010 Christopher M. Kohlhoff (ping.cpp) // Modified 2014 by Christian Herdtweck, Intra2net AG // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef ICMP_PINGER_H #define ICMP_PINGER_H #include #include #include #include #include #include #include "host/pinger.h" #include "host/pingstatus.h" #include "icmp/icmppacket.h" using boost::asio::ip::icmp; class IcmpPinger; typedef boost::shared_ptr IcmpPingerItem; class IcmpPacketDistributor; typedef boost::shared_ptr IcmpPacketDistributorItem; typedef boost::shared_ptr SocketItem; //----------------------------------------------------------------------------- // IcmpPacketDistributor //----------------------------------------------------------------------------- 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: /// Network layer protocol used to ping, IPv4 or IPv6 icmp::socket::protocol_type Protocol; /// The socket object SocketItem Socket; /// The buffer where the data received will be placed boost::asio::streambuf ReplyBuffer; std::set PingerList; // for each IP protocol (v4/v6) and each network interface (string), // there can only be one IcmpPacketDistributor instance typedef std::pair DistributorInstanceIdentifier; struct InstanceIdentifierComparator { bool operator() ( const DistributorInstanceIdentifier &a, const DistributorInstanceIdentifier &b ) const ; }; typedef std::map map_type; /// Instances, one for each (protocol, interface) - pair static map_type Instances; }; //----------------------------------------------------------------------------- // IcmpPinger //----------------------------------------------------------------------------- /** * @brief This class performs an ICMP ping to host using Boost Asio. * Scope: one object per host. */ class IcmpPinger : public Pinger { public: static PingerItem create( const IoServiceItem io_serv, const boost::asio::ip::icmp::socket::protocol_type &protocol, const std::string &source_network_interface, const int echo_reply_timeout_in_sec ); virtual ~IcmpPinger(); virtual void ping( const boost::asio::ip::address &destination_ip, const uint16_t destination_port, boost::function ping_done_callback ); virtual void stop_pinging(); bool handle_receive_icmp_packet(const IcmpPacketItem icmp_packet, const size_t bytes_transferred ); private: IcmpPinger( const IoServiceItem io_serv, const boost::asio::ip::icmp::socket::protocol_type &protocol, const int echo_reply_timeout_in_sec, const IcmpPacketDistributorItem distributor ); void set_destination_endpoint(const boost::asio::ip::address &destination); bool start_send(); bool send_echo_request( const IcmpPacketItem icmp_packet ); void schedule_timeout_echo_reply(); void handle_timeout(const boost::system::error_code &error); void set_ping_status( PingStatus ping_status ); private: IcmpPacketDistributorItem PacketDistributor; /// The destination host boost::asio::ip::icmp::endpoint DestinationEndpoint; /// Network layer protocol used to ping, IPv4 or IPv6 boost::asio::ip::icmp::socket::protocol_type Protocol; /// The timer of ICMP packet receive, triggers the timeout to avoid infinite /// wait boost::asio::deadline_timer IcmpPacketReceiveTimer; /// ICMP packet identifier uint16_t Identifier; /// ICMP packet sequence_number uint16_t SequenceNumber; /// The time when the last ICMP packet was sent boost::posix_time::ptime TimeSent; /// Flag to indicate if we got a reply or not bool ReplyReceived; /// The amount of time to wait for the reply int EchoReplyTimeoutInSec; /// The status of the pinger PingStatus PingerStatus; /// Callback to notify when the ping is done (got reply/timeout) boost::function< void(PingStatus,long) > PingDoneCallback; /// prefix to logging output lines std::string LogPrefix; }; #endif // ICMP_PINGER_H