#include "icmp/icmpdata.h"
#include "icmp/icmpheader.h"
#include "icmp/icmppacket.h"
+#include "icmp/icmptype.h"
#include "icmp/ipv4header.h"
using namespace std;
IoService( io_serv ),
DestinationEndpoint(),
Socket( io_serv, icmp::v4() ),
- Timer( io_serv ),
+ IcmpPacketReceiveTimer( io_serv ),
SequenceNumber( 0 ),
TimeSent( microsec_clock::universal_time() ),
ReplyBuffer(),
{
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() );
{
// 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 )
);
}
{
// 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()
// 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;
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();
}
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();
<< " 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;
{
PingStatus_NotSent,
PingStatus_SuccessReply,
- PingStatus_FailureTimeout
+ PingStatus_FailureTimeout,
+ PingStatus_FailureDestinationUnreachable
};
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 );
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;