From: Guilherme Maciel Ferreira Date: Mon, 28 Feb 2011 13:59:17 +0000 (+0100) Subject: Created an ICMP packet class abstraction and modularizing the BoostPinger X-Git-Tag: v1.0~172 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=cb60ed914e2018c4cb217caf0e67c3ca7afe6d72;p=pingcheck Created an ICMP packet class abstraction and modularizing the BoostPinger - Hide the ICMP packet management from BoostPinger class - Split functionality in other methods (e.g send_echo_request() and print_echo_reply() --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3f8d76..19c48e7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,7 @@ set( SOURCES ping/boostpinger.cpp ping/host.cpp ping/icmpheader.cpp + ping/icmppacket.cpp ping/ipv4header.cpp ping/pingcheck.cpp ping/pinger.cpp diff --git a/src/ping/boostpinger.cpp b/src/ping/boostpinger.cpp index 1adb386..75b7b92 100644 --- a/src/ping/boostpinger.cpp +++ b/src/ping/boostpinger.cpp @@ -7,8 +7,8 @@ #include #include -#include "icmpdata.h" #include "icmpchecksumcalculator.h" +#include "icmpdata.h" #include "icmpheader.h" #include "ipv4header.h" #include "boostpinger.h" @@ -53,26 +53,24 @@ void BoostPinger::ping( const std::string &destination ) void BoostPinger::start_send() { - IcmpData data( "ping message" ); + IcmpData icmp_data( "ping message" ); // Create an ICMP header for an echo request. SequenceNumber++; IcmpHeader::IcmpType type = IcmpHeader::EchoRequest; uint8_t code = 0; uint16_t identifier = get_identifier(); - IcmpChecksumCalculator calculator( data.begin(), data.end() ); + IcmpChecksumCalculator calculator( icmp_data.begin(), icmp_data.end() ); uint16_t checksum = calculator.compute( type, code, identifier, SequenceNumber ); - IcmpHeader echo_request( type, code, checksum, identifier, SequenceNumber ); + IcmpHeader icmp_header( type, code, checksum, identifier, SequenceNumber ); - // Encode the request packet. - boost::asio::streambuf request_buffer; - std::ostream os( &request_buffer ); - os << echo_request << data; + // Encode the ICMP header and data in an ICMP packet. + IcmpPacket icmp_echo_request_packet( icmp_header, icmp_data ); int ping_times = SequenceNumber; if ( ping_times < 4 ) { - send( request_buffer ); + send_echo_request( icmp_echo_request_packet ); } else { @@ -80,8 +78,12 @@ void BoostPinger::start_send() } } -void BoostPinger::send( const boost::asio::streambuf &request_buffer ) +void BoostPinger::send_echo_request( const IcmpPacket &icmp_packet ) { + boost::asio::streambuf request_buffer; + std::ostream os( &request_buffer ); + os << icmp_packet; + // Send the request. TimeSent = posix_time::microsec_clock::universal_time(); Socket.send_to( request_buffer.data(), DestinationEndpoint ); @@ -122,16 +124,13 @@ void BoostPinger::handle_receive( const std::size_t &length ) // Decode the reply packet. std::istream is( &ReplyBuffer ); - Ipv4Header ipv4_hdr; - IcmpHeader icmp_hdr; - is >> ipv4_hdr >> icmp_hdr; + 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_hdr.get_type() == IcmpHeader::EchoReply - && icmp_hdr.get_identifier() == get_identifier() - && icmp_hdr.get_sequence_number() == SequenceNumber ) + if ( is && icmp_packet.match( IcmpHeader::EchoReply, get_identifier(), SequenceNumber ) ) { // If this is the first reply, interrupt the five second timeout. if ( NumReplies == 0 ) @@ -140,17 +139,28 @@ void BoostPinger::handle_receive( const std::size_t &length ) ++NumReplies; // Print out some information about the reply packet. - posix_time::ptime now = posix_time::microsec_clock::universal_time(); - std::cout << length - ipv4_hdr.get_header_length() << " bytes from " - << ipv4_hdr.get_source_address() << ": icmp_seq=" - << icmp_hdr.get_sequence_number() << ", ttl=" - << ipv4_hdr.get_time_to_live() << ", time=" - << (now - TimeSent).total_milliseconds() << " ms" << std::endl; + print_echo_reply( icmp_packet, length ); } start_receive(); } +void BoostPinger::print_echo_reply( + const IcmpPacket &icmp_packet, + const std::size_t &length +) +{ + Ipv4Header ipv4_hdr = icmp_packet.get_ip_header(); + IcmpHeader icmp_hdr = icmp_packet.get_icmp_header(); + + posix_time::ptime now = posix_time::microsec_clock::universal_time(); + std::cout << ( length - ipv4_hdr.get_header_length() ) << " bytes from " + << ipv4_hdr.get_source_address() << ": icmp_seq=" + << icmp_hdr.get_sequence_number() << ", ttl=" + << ipv4_hdr.get_time_to_live() << ", time=" + << (now - TimeSent).total_milliseconds() << " ms" << std::endl; +} + uint16_t BoostPinger::get_identifier() { return static_cast ( ::getpid() ); diff --git a/src/ping/boostpinger.h b/src/ping/boostpinger.h index b4a1e40..1fdccfe 100644 --- a/src/ping/boostpinger.h +++ b/src/ping/boostpinger.h @@ -3,6 +3,7 @@ #include +#include "icmppacket.h" #include "pinger.h" using boost::asio::ip::address; @@ -23,11 +24,15 @@ public: private: void start_send(); - void send( const boost::asio::streambuf &request_buffer ); + void send_echo_request( const IcmpPacket &icmp_packet ); void handle_timeout(); void start_receive(); void handle_receive( const std::size_t &length ); + void print_echo_reply( + const IcmpPacket &icmp_packet, + const std::size_t &length + ); uint16_t get_identifier(); diff --git a/src/ping/icmpheader.cpp b/src/ping/icmpheader.cpp index d1ce175..9ca552c 100644 --- a/src/ping/icmpheader.cpp +++ b/src/ping/icmpheader.cpp @@ -81,19 +81,25 @@ void IcmpHeader::set_sequence_number( uint16_t sequence_number ) encode( 6, 7, sequence_number ); } -std::istream& operator>>( std::istream& is, IcmpHeader& header ) +std::istream& operator>>( + std::istream &is, + IcmpHeader &header +) { return is.read( reinterpret_cast ( header.Rep ), 8 ); } -std::ostream& operator<<( std::ostream& os, const IcmpHeader& header ) +std::ostream& operator<<( + std::ostream &os, + const IcmpHeader &header +) { return os.write( reinterpret_cast ( header.Rep ), 8 ); } uint16_t IcmpHeader::decode( int a, int b ) const { - return (Rep[ a ] << 8) + Rep[ b ]; + return ( Rep[ a ] << 8 ) + Rep[ b ]; } void IcmpHeader::encode( int a, int b, uint16_t n ) diff --git a/src/ping/icmpheader.h b/src/ping/icmpheader.h index 61e1b0e..ae354d3 100644 --- a/src/ping/icmpheader.h +++ b/src/ping/icmpheader.h @@ -68,11 +68,13 @@ public: void set_sequence_number( const uint16_t sequence_number ); friend std::istream& operator>>( - std::istream& is, - IcmpHeader& header ); + std::istream &is, + IcmpHeader &header + ); friend std::ostream& operator<<( - std::ostream& os, - const IcmpHeader& header ); + std::ostream &os, + const IcmpHeader &header + ); private: uint16_t decode( int a, int b ) const; diff --git a/src/ping/icmppacket.cpp b/src/ping/icmppacket.cpp new file mode 100644 index 0000000..a8ab37d --- /dev/null +++ b/src/ping/icmppacket.cpp @@ -0,0 +1,74 @@ +#include "icmppacket.h" + +//----------------------------------------------------------------------------- +// IcmpPacket +//----------------------------------------------------------------------------- + +IcmpPacket::IcmpPacket() : + IpHeader(), + IcmpPayloadHeader(), + IcmpPayloadData() +{ +} + +IcmpPacket::IcmpPacket( + const IcmpHeader &icmp_header, + const IcmpData &icmp_data +) : + IpHeader(), + IcmpPayloadHeader( icmp_header ), + IcmpPayloadData( icmp_data ) +{ +} + +IcmpPacket::~IcmpPacket() +{ +} + +Ipv4Header IcmpPacket::get_ip_header() const +{ + return IpHeader; +} + +IcmpHeader IcmpPacket::get_icmp_header() const +{ + return IcmpPayloadHeader; +} + +IcmpData IcmpPacket::get_icmp_data() const +{ + return IcmpPayloadData; +} + +bool IcmpPacket::match( + IcmpHeader::IcmpType type, + uint16_t identifier, + uint16_t sequence_number +) +{ + bool type_match = IcmpPayloadHeader.get_type() == type; + bool identifier_match = IcmpPayloadHeader.get_identifier() == identifier; + bool seq_num_match = IcmpPayloadHeader.get_sequence_number() == sequence_number; + + return ( type_match && identifier_match && seq_num_match ); +} + +std::istream& operator>>( + std::istream &is, + IcmpPacket &packet +) +{ + is >> packet.IpHeader >> packet.IcmpPayloadHeader >> packet.IcmpPayloadData; + + return is; +} + +std::ostream& operator<<( + std::ostream& os, + const IcmpPacket& packet +) +{ + os << packet.IcmpPayloadHeader << packet.IcmpPayloadData; + + return os; +} diff --git a/src/ping/icmppacket.h b/src/ping/icmppacket.h new file mode 100644 index 0000000..4ef7803 --- /dev/null +++ b/src/ping/icmppacket.h @@ -0,0 +1,89 @@ +#ifndef ICMPPACKET_H +#define ICMPPACKET_H + +#include +#include +#include + +#include "ipv4header.h" +#include "icmpheader.h" +#include "icmpdata.h" + +//----------------------------------------------------------------------------- +// IcmpPacket +//----------------------------------------------------------------------------- +// ICMP packet/message format: +// +// 0 8 16 31 +// +-------+-------+---------------+------------------------------+ --- +// | | | | | ^ +// |version|header | type of | total length in bytes | | +// | (4) | length| service | | | +// +-------+-------+---------------+-+-+-+------------------------+ | +// | | | | | | | +// | identification |0|D|M| fragment offset | | +// | | |F|F| | | +// +---------------+---------------+-+-+-+------------------------+ | +// | | | | | +// | time to live | protocol | header checksum | IPv4 Header +// | | | | 20 bytes +// +---------------+---------------+------------------------------+ | +// | | | +// | source IPv4 address | | +// | | | +// +--------------------------------------------------------------+ | +// | | | +// | destination IPv4 address | | +// | | v +// +---------------+---------------+------------------------------+ --- +// | | | | ^ +// | type | code | checksum | | +// | | | | | +// +---------------+---------------+------------------------------+ | +// | | | ICMP Payload +// | identifier | sequence number | (header + +// | | | data) +// +-------------------------------+------------------------------+ 8+ bytes +// | | | +// | data (optional) | | +// | | v +// +-------------------------------+------------------------------+ --- +// +//----------------------------------------------------------------------------- + +class IcmpPacket +{ +public: + IcmpPacket(); + IcmpPacket( + const IcmpHeader &icmp_header, + const IcmpData &icmp_data + ); + virtual ~IcmpPacket(); + + Ipv4Header get_ip_header() const; + IcmpHeader get_icmp_header() const; + IcmpData get_icmp_data() const; + + bool match( + IcmpHeader::IcmpType type, + uint16_t identifier, + uint16_t sequence_number + ); + + friend std::istream& operator>>( + std::istream &is, + IcmpPacket &packet + ); + friend std::ostream& operator<<( + std::ostream &os, + const IcmpPacket &packet + ); + +private: + Ipv4Header IpHeader; + IcmpHeader IcmpPayloadHeader; + IcmpData IcmpPayloadData; +}; + +#endif /* ICMPPACKET_H */ diff --git a/src/ping/ipv4header.cpp b/src/ping/ipv4header.cpp index 028b717..ed5ab10 100644 --- a/src/ping/ipv4header.cpp +++ b/src/ping/ipv4header.cpp @@ -84,7 +84,10 @@ boost::asio::ip::address_v4 Ipv4Header::get_destination_address() const return boost::asio::ip::address_v4( bytes ); } -std::istream& operator>>( std::istream& is, Ipv4Header& header ) +std::istream& operator>>( + std::istream &is, + Ipv4Header &header +) { is.read( reinterpret_cast ( header.Rep ), 20 ); if ( header.get_version() != 4 ) diff --git a/src/ping/ipv4header.h b/src/ping/ipv4header.h index 638a08a..f03e751 100644 --- a/src/ping/ipv4header.h +++ b/src/ping/ipv4header.h @@ -63,7 +63,10 @@ public: boost::asio::ip::address_v4 get_source_address() const; boost::asio::ip::address_v4 get_destination_address() const; - friend std::istream& operator>>( std::istream& is, Ipv4Header& header ); + friend std::istream& operator>>( + std::istream &is, + Ipv4Header &header + ); private: uint16_t decode( int a, int b ) const;