From: Guilherme Maciel Ferreira Date: Fri, 8 Apr 2011 14:34:53 +0000 (+0200) Subject: Pinger now handles ICMP Destination Unreachable messages X-Git-Tag: v1.0~90 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=2b5520bceb5296c704d8aa3c4923730d95500660;p=pingcheck Pinger now handles ICMP Destination Unreachable messages - handle_receive_echo_reply rename to handle_receive_icmp_packet, once it handles not just echo replies - timer member variable has a more meaningful name --- diff --git a/src/ping/boostpinger.cpp b/src/ping/boostpinger.cpp index 26b4f4c..4d77213 100644 --- a/src/ping/boostpinger.cpp +++ b/src/ping/boostpinger.cpp @@ -10,6 +10,7 @@ #include "icmp/icmpdata.h" #include "icmp/icmpheader.h" #include "icmp/icmppacket.h" +#include "icmp/icmptype.h" #include "icmp/ipv4header.h" using namespace std; @@ -29,7 +30,7 @@ BoostPinger::BoostPinger( IoService( io_serv ), DestinationEndpoint(), Socket( io_serv, icmp::v4() ), - Timer( io_serv ), + IcmpPacketReceiveTimer( io_serv ), SequenceNumber( 0 ), TimeSent( microsec_clock::universal_time() ), ReplyBuffer(), @@ -112,7 +113,7 @@ IcmpPacket BoostPinger::create_echo_request( { const IcmpData icmp_data( "ping-message" ); - IcmpHeader::IcmpType type = IcmpHeader::IcmpType_EchoRequest; + IcmpType type = IcmpType_EchoRequest; uint8_t code = 0; uint16_t identifier = get_identifier(); IcmpChecksumCalculator calculator( icmp_data.begin(), icmp_data.end() ); @@ -159,8 +160,10 @@ void BoostPinger::schedule_timeout_echo_reply() { // Wait up to N seconds for a reply. RepliesCount = 0; - (void) Timer.expires_at( TimeSent + seconds( EchoReplyTimeoutInSec ) ); - Timer.async_wait( + (void) IcmpPacketReceiveTimer.expires_at( + TimeSent + seconds( EchoReplyTimeoutInSec ) + ); + IcmpPacketReceiveTimer.async_wait( boost::bind( &BoostPinger::handle_timeout_echo_reply, this ) ); } @@ -181,8 +184,12 @@ void BoostPinger::schedule_next_echo_request() { // Requests must be sent no less than one second apart. const int echo_request_interval_in_sec = 1; - (void) Timer.expires_at( TimeSent + seconds( echo_request_interval_in_sec ) ); - Timer.async_wait( boost::bind( &BoostPinger::start_send, this ) ); + (void) IcmpPacketReceiveTimer.expires_at( + TimeSent + seconds( echo_request_interval_in_sec ) + ); + IcmpPacketReceiveTimer.async_wait( + boost::bind( &BoostPinger::start_send, this ) + ); } void BoostPinger::start_receive() @@ -193,30 +200,35 @@ void BoostPinger::start_receive() // Wait for a reply. We prepare the buffer to receive up to 64KB. Socket.async_receive( ReplyBuffer.prepare( 65536 ), - boost::bind( &BoostPinger::handle_receive_echo_reply, this, _2 ) + boost::bind( &BoostPinger::handle_receive_icmp_packet, this, _2 ) ); } -void BoostPinger::handle_receive_echo_reply( const size_t &bytes_transferred ) +void BoostPinger::handle_receive_icmp_packet( const size_t &bytes_transferred ) { // 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 ); - // Decode the reply packet. istream is( &ReplyBuffer ); + if ( !is ) + return; + + // Decode the reply packet. IcmpPacket icmp_packet; is >> icmp_packet; // We can receive all ICMP packets received by the host, so we need to // filter out only the echo replies that match the our identifier and // expected sequence number. - if ( is && icmp_packet.match( IcmpHeader::IcmpType_EchoReply, get_identifier(), SequenceNumber ) ) + if ( icmp_packet.match( + IcmpType_EchoReply, get_identifier(), SequenceNumber + ) ) { // If this is the first reply, interrupt the echo reply timeout. if ( RepliesCount == 0 ) { - (void) Timer.cancel(); + (void) IcmpPacketReceiveTimer.cancel(); } ++RepliesCount; @@ -225,6 +237,20 @@ void BoostPinger::handle_receive_echo_reply( const size_t &bytes_transferred ) set_ping_status( PingStatus_SuccessReply ); } + else if ( icmp_packet.match( + IcmpType_DestinationUnreachable, get_identifier(), SequenceNumber + ) ) + { + // If this is the first reply, interrupt the echo reply timeout. + if ( RepliesCount == 0 ) + { + (void) IcmpPacketReceiveTimer.cancel(); + } + + print_destination_unreachable( icmp_packet ); + + set_ping_status( PingStatus_FailureDestinationUnreachable ); + } start_receive(); } @@ -234,6 +260,8 @@ void BoostPinger::print_echo_reply( const size_t &bytes_transferred ) const { + BOOST_ASSERT( icmp_packet.get_icmp_header().get_type() == IcmpType_EchoReply ); + Ipv4Header ipv4_hdr = icmp_packet.get_ip_header(); IcmpHeader icmp_hdr = icmp_packet.get_icmp_header(); @@ -251,6 +279,23 @@ void BoostPinger::print_echo_reply( << " time=" << time << " ms" << endl; } +void BoostPinger::print_destination_unreachable( + const IcmpPacket &icmp_packet +) const +{ + BOOST_ASSERT( icmp_packet.get_icmp_header().get_type() == IcmpType_DestinationUnreachable ); + + Ipv4Header ipv4_hdr = icmp_packet.get_ip_header(); + IcmpHeader icmp_hdr = icmp_packet.get_icmp_header(); + + string local_address = ipv4_hdr.get_destination_address().to_string(); + int sequence_number = icmp_hdr.get_sequence_number(); + + cout << "From " << local_address + << " icmp_seq=" << sequence_number + << " Destination Net Unreachable" << endl; +} + void BoostPinger::set_ping_status( BoostPinger::PingStatus ping_status ) { PingerStatus = ping_status; diff --git a/src/ping/boostpinger.h b/src/ping/boostpinger.h index 766378c..bb96daf 100644 --- a/src/ping/boostpinger.h +++ b/src/ping/boostpinger.h @@ -30,7 +30,8 @@ private: { PingStatus_NotSent, PingStatus_SuccessReply, - PingStatus_FailureTimeout + PingStatus_FailureTimeout, + PingStatus_FailureDestinationUnreachable }; private: @@ -45,11 +46,14 @@ private: void schedule_next_echo_request(); void start_receive(); - void handle_receive_echo_reply( const std::size_t &bytes_transferred ); + void handle_receive_icmp_packet( const std::size_t &bytes_transferred ); void print_echo_reply( const IcmpPacket &icmp_packet, const std::size_t &bytes_transferred ) const; + void print_destination_unreachable( + const IcmpPacket &icmp_packet + ) const; void set_ping_status( BoostPinger::PingStatus ping_status ); @@ -63,7 +67,7 @@ private: boost::asio::io_service &IoService; boost::asio::ip::icmp::endpoint DestinationEndpoint; boost::asio::ip::icmp::socket Socket; - boost::asio::deadline_timer Timer; + boost::asio::deadline_timer IcmpPacketReceiveTimer; uint16_t SequenceNumber; boost::posix_time::ptime TimeSent; boost::asio::streambuf ReplyBuffer;