ping/boostpinger.cpp
ping/host.cpp
ping/icmpheader.cpp
+ ping/icmppacket.cpp
ping/ipv4header.cpp
ping/pingcheck.cpp
ping/pinger.cpp
#include <sys/socket.h>
#include <sys/types.h>
-#include "icmpdata.h"
#include "icmpchecksumcalculator.h"
+#include "icmpdata.h"
#include "icmpheader.h"
#include "ipv4header.h"
#include "boostpinger.h"
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
{
}
}
-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 );
// 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 )
++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<uint16_t> ( ::getpid() );
#include <boost/asio.hpp>
+#include "icmppacket.h"
#include "pinger.h"
using boost::asio::ip::address;
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();
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<char*> ( 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<const char*> ( 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 )
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;
--- /dev/null
+#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;
+}
--- /dev/null
+#ifndef ICMPPACKET_H
+#define ICMPPACKET_H
+
+#include <istream>
+#include <ostream>
+#include <stdint.h>
+
+#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 */
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<char*> ( header.Rep ), 20 );
if ( header.get_version() != 4 )
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;