Refactoring the ICMP message parsing
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@intra2net.com>
Fri, 8 Apr 2011 13:25:27 +0000 (15:25 +0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@intra2net.com>
Fri, 8 Apr 2011 13:54:22 +0000 (15:54 +0200)
- IcmpType enum separated from the IcmpHeader class, thus it has its own header without requiring to add the IcmpHeader's header file
- the IcmpHeader class delegates the parsing polymorphically to specialized IcmpMessage classes  (i.e. allowing the parsing of Destination unreachable messages)
- IcmpHeader class does not requires the Payload member variable anymore, once it delegates the parsing to IcmpMessage classes

16 files changed:
src/CMakeLists.txt
src/icmp/icmpdestinationunreachablemessage.cpp [new file with mode: 0644]
src/icmp/icmpdestinationunreachablemessage.h [new file with mode: 0644]
src/icmp/icmpechoreplymessage.cpp [new file with mode: 0644]
src/icmp/icmpechoreplymessage.h [new file with mode: 0644]
src/icmp/icmpechorequestmessage.cpp [new file with mode: 0644]
src/icmp/icmpechorequestmessage.h [new file with mode: 0644]
src/icmp/icmpgenericmessage.cpp [new file with mode: 0644]
src/icmp/icmpgenericmessage.h [new file with mode: 0644]
src/icmp/icmpheader.cpp
src/icmp/icmpheader.h
src/icmp/icmpmessage.cpp [new file with mode: 0644]
src/icmp/icmpmessage.h [new file with mode: 0644]
src/icmp/icmppacket.cpp
src/icmp/icmppacket.h
src/icmp/icmptype.h [new file with mode: 0644]

index 5241752..c062424 100644 (file)
@@ -24,6 +24,11 @@ set(SOURCES
     config/host.cpp
     dns/dnsresolver.cpp
     dns/hostaddress.cpp
+    icmp/icmpdestinationunreachablemessage.cpp
+    icmp/icmpechoreplymessage.cpp
+    icmp/icmpechorequestmessage.cpp
+    icmp/icmpgenericmessage.cpp
+    icmp/icmpmessage.cpp
     icmp/icmpheader.cpp
     icmp/icmppacket.cpp
     icmp/ipv4header.cpp
diff --git a/src/icmp/icmpdestinationunreachablemessage.cpp b/src/icmp/icmpdestinationunreachablemessage.cpp
new file mode 100644 (file)
index 0000000..674ab43
--- /dev/null
@@ -0,0 +1,128 @@
+#include "icmp/icmpdestinationunreachablemessage.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// IcmpDestinationUnreachableMessage
+//-----------------------------------------------------------------------------
+
+const int IcmpDestinationUnreachableMessage::MessageSizeInBytes = 44;
+
+IcmpDestinationUnreachableMessage::IcmpDestinationUnreachableMessage()
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( IcmpType_InvalidLast );
+    set_code( 0 );
+    set_checksum( 0 );
+    set_identifier( 0 );
+    set_sequence_number( 0 );
+}
+
+IcmpDestinationUnreachableMessage::IcmpDestinationUnreachableMessage(
+        const IcmpType type,
+        const uint8_t code,
+        const uint16_t checksum,
+        const uint16_t identifier,
+        const uint16_t sequence_number
+)
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( type );
+    set_code( code );
+    set_checksum( checksum );
+    set_identifier( identifier );
+    set_sequence_number( sequence_number );
+}
+
+IcmpDestinationUnreachableMessage::~IcmpDestinationUnreachableMessage()
+{
+}
+
+IcmpType IcmpDestinationUnreachableMessage::get_type() const
+{
+    IcmpType type = static_cast<IcmpType> ( Payload[ 0 ] );
+
+    return type;
+}
+
+void IcmpDestinationUnreachableMessage::set_type( IcmpType type )
+{
+    uint8_t n = static_cast<uint8_t> ( type );
+
+    Payload[ 0 ] = n;
+}
+
+uint8_t IcmpDestinationUnreachableMessage::get_code() const
+{
+    return Payload[ 1 ];
+}
+
+void IcmpDestinationUnreachableMessage::set_code( uint8_t code )
+{
+    Payload[ 1 ] = code;
+}
+
+uint16_t IcmpDestinationUnreachableMessage::get_checksum() const
+{
+    return decode( 2, 3 );
+}
+
+void IcmpDestinationUnreachableMessage::set_checksum( uint16_t checksum )
+{
+    encode( 2, 3, checksum );
+}
+
+uint16_t IcmpDestinationUnreachableMessage::get_identifier() const
+{
+    return decode( 32, 33 );
+}
+
+void IcmpDestinationUnreachableMessage::set_identifier(
+        const uint16_t identifier
+)
+{
+    encode( 32, 33, identifier );
+}
+
+uint16_t IcmpDestinationUnreachableMessage::get_sequence_number() const
+{
+    return decode( 34, 35 );
+}
+
+void IcmpDestinationUnreachableMessage::set_sequence_number(
+        const uint16_t sequence_number
+)
+{
+    encode( 34, 35, sequence_number );
+}
+
+std::istream& IcmpDestinationUnreachableMessage::read( std::istream &is )
+{
+    return is.read(
+            reinterpret_cast<char *> ( Payload ),
+            IcmpDestinationUnreachableMessage::MessageSizeInBytes
+    );
+}
+
+std::ostream& IcmpDestinationUnreachableMessage::write(
+        std::ostream &os
+) const
+{
+    return os.write(
+            reinterpret_cast<const char *> ( Payload ),
+            IcmpDestinationUnreachableMessage::MessageSizeInBytes
+    );
+}
+
+uint16_t IcmpDestinationUnreachableMessage::decode( int left_byte, int right_byte ) const
+{
+    return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ];
+}
+
+void IcmpDestinationUnreachableMessage::encode( int left_byte, int right_byte, uint16_t value )
+{
+    Payload[ left_byte ] = static_cast<uint8_t> ( value >> 8 );
+    Payload[ right_byte ] = static_cast<uint8_t> ( value & 0xFF );
+}
diff --git a/src/icmp/icmpdestinationunreachablemessage.h b/src/icmp/icmpdestinationunreachablemessage.h
new file mode 100644 (file)
index 0000000..cc37291
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP
+#define ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include "icmp/icmpmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpDestinationUnreachableMessage
+//-----------------------------------------------------------------------------
+//
+// ICMP Destination Unreachable Message Format
+
+// 0               8               16                             31
+// +---------------+---------------+------------------------------+      ---
+// |               |               |                              |       ^
+// |     type      |     code      |          checksum            |       |
+// |               |               |                              |       |
+// +---------------+---------------+------------------------------+    8 bytes
+// |                                                              |       |
+// |                            unused                            |       |
+// |                                                              |       v
+// +-------------------------------+------------------------------+      ---
+// |                                                              |       ^
+// |                   Internet Protocol (IP) Header              |   20 bytes
+// |                                                              |       v
+// +-------------------------------+------------------------------+      ---
+// |                                                              |       ^
+// |                    Original ICMP Data Datagram               |   20 bytes
+// |                                                              |       v
+// +-------------------------------+------------------------------+      ---
+//
+//-----------------------------------------------------------------------------
+
+class IcmpDestinationUnreachableMessage : public IcmpMessage
+{
+public:
+    IcmpDestinationUnreachableMessage();
+    IcmpDestinationUnreachableMessage(
+            const IcmpType type,
+            const uint8_t code,
+            const uint16_t checksum,
+            const uint16_t identifier,
+            const uint16_t sequence_number
+    );
+    virtual ~IcmpDestinationUnreachableMessage();
+
+    IcmpType get_type() const;
+    void set_type( const IcmpType type );
+
+    uint8_t get_code() const;
+    void set_code( const uint8_t code );
+
+    uint16_t get_checksum() const;
+    void set_checksum( const uint16_t checksum );
+
+    uint16_t get_identifier() const;
+    void set_identifier( const uint16_t identifier );
+
+    uint16_t get_sequence_number() const;
+    void set_sequence_number( const uint16_t sequence_number );
+
+    std::istream& read( std::istream &is );
+    std::ostream& write( std::ostream &os ) const;
+
+private:
+    uint16_t decode( int left_byte, int right_byte ) const;
+    void encode( int left_byte, int right_byte, uint16_t value );
+
+private:
+    static const int MessageSizeInBytes;
+    uint8_t Payload[ 44 ];
+
+};
+
+#endif // ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP
diff --git a/src/icmp/icmpechoreplymessage.cpp b/src/icmp/icmpechoreplymessage.cpp
new file mode 100644 (file)
index 0000000..6d24456
--- /dev/null
@@ -0,0 +1,126 @@
+#include "icmp/icmpechoreplymessage.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// IcmpEchoReplyMessage
+//-----------------------------------------------------------------------------
+
+const int IcmpEchoReplyMessage::MessageSizeInBytes = 8;
+
+IcmpEchoReplyMessage::IcmpEchoReplyMessage()
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( IcmpType_InvalidLast );
+    set_code( 0 );
+    set_checksum( 0 );
+    set_identifier( 0 );
+    set_sequence_number( 0 );
+}
+
+IcmpEchoReplyMessage::IcmpEchoReplyMessage(
+        const IcmpType type,
+        const uint8_t code,
+        const uint16_t checksum,
+        const uint16_t identifier,
+        const uint16_t sequence_number
+)
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( type );
+    set_code( code );
+    set_checksum( checksum );
+    set_identifier( identifier );
+    set_sequence_number( sequence_number );
+}
+
+IcmpEchoReplyMessage::~IcmpEchoReplyMessage()
+{
+}
+
+IcmpType IcmpEchoReplyMessage::get_type() const
+{
+    IcmpType type = static_cast<IcmpType> ( Payload[ 0 ] );
+
+    return type;
+}
+
+void IcmpEchoReplyMessage::set_type( IcmpType type )
+{
+    uint8_t n = static_cast<uint8_t> ( type );
+
+    Payload[ 0 ] = n;
+}
+
+uint8_t IcmpEchoReplyMessage::get_code() const
+{
+    return Payload[ 1 ];
+}
+
+void IcmpEchoReplyMessage::set_code( uint8_t code )
+{
+    Payload[ 1 ] = code;
+}
+
+uint16_t IcmpEchoReplyMessage::get_checksum() const
+{
+    return decode( 2, 3 );
+}
+
+void IcmpEchoReplyMessage::set_checksum( uint16_t checksum )
+{
+    encode( 2, 3, checksum );
+}
+
+uint16_t IcmpEchoReplyMessage::get_identifier() const
+{
+    return decode( 4, 5 );
+}
+
+void IcmpEchoReplyMessage::set_identifier(
+        const uint16_t identifier
+)
+{
+    encode( 4, 5, identifier );
+}
+
+uint16_t IcmpEchoReplyMessage::get_sequence_number() const
+{
+    return decode( 6, 7 );
+}
+
+void IcmpEchoReplyMessage::set_sequence_number(
+        const uint16_t sequence_number
+)
+{
+    encode( 6, 7, sequence_number );
+}
+
+std::istream& IcmpEchoReplyMessage::read( std::istream &is )
+{
+    return is.read(
+            reinterpret_cast<char *> ( Payload ),
+            IcmpEchoReplyMessage::MessageSizeInBytes
+    );
+}
+
+std::ostream& IcmpEchoReplyMessage::write( std::ostream &os ) const
+{
+    return os.write(
+            reinterpret_cast<const char *> ( Payload ),
+            IcmpEchoReplyMessage::MessageSizeInBytes
+    );
+}
+
+uint16_t IcmpEchoReplyMessage::decode( int left_byte, int right_byte ) const
+{
+    return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ];
+}
+
+void IcmpEchoReplyMessage::encode( int left_byte, int right_byte, uint16_t value )
+{
+    Payload[ left_byte ] = static_cast<uint8_t> ( value >> 8 );
+    Payload[ right_byte ] = static_cast<uint8_t> ( value & 0xFF );
+}
diff --git a/src/icmp/icmpechoreplymessage.h b/src/icmp/icmpechoreplymessage.h
new file mode 100644 (file)
index 0000000..eef3579
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef ICMP_ECHO_REPLY_MESSAGE_HPP
+#define ICMP_ECHO_REPLY_MESSAGE_HPP
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include "icmp/icmpmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpEchoReplyMessage
+//-----------------------------------------------------------------------------
+//
+// ICMP Echo Reply Message Format
+//
+// 0               8               16                             31
+// +---------------+---------------+------------------------------+      ---
+// |               |               |                              |       ^
+// |     type      |     code      |          checksum            |       |
+// |               |               |                              |       |
+// +---------------+---------------+------------------------------+    8 bytes
+// |                               |                              |       |
+// |          identifier           |       sequence number        |       |
+// |                               |                              |       v
+// +-------------------------------+------------------------------+      ---
+// |                                                              |
+// |                           data (n bytes)                     |
+// |                                                              |
+// +-------------------------------+------------------------------+
+//
+//-----------------------------------------------------------------------------
+
+class IcmpEchoReplyMessage : public IcmpMessage
+{
+public:
+    IcmpEchoReplyMessage();
+    IcmpEchoReplyMessage(
+            const IcmpType type,
+            const uint8_t code,
+            const uint16_t checksum,
+            const uint16_t identifier,
+            const uint16_t sequence_number
+    );
+    virtual ~IcmpEchoReplyMessage();
+
+    IcmpType get_type() const;
+    void set_type( const IcmpType type );
+
+    uint8_t get_code() const;
+    void set_code( const uint8_t code );
+
+    uint16_t get_checksum() const;
+    void set_checksum( const uint16_t checksum );
+
+    uint16_t get_identifier() const;
+    void set_identifier( const uint16_t identifier );
+
+    uint16_t get_sequence_number() const;
+    void set_sequence_number( const uint16_t sequence_number );
+
+    std::istream& read( std::istream &is );
+    std::ostream& write( std::ostream &os ) const;
+
+private:
+    uint16_t decode( int left_byte, int right_byte ) const;
+    void encode( int left_byte, int right_byte, uint16_t value );
+
+private:
+    static const int MessageSizeInBytes;
+    uint8_t Payload[ 8 ];
+
+};
+
+#endif // ICMP_ECHO_REPLY_MESSAGE_HPP
diff --git a/src/icmp/icmpechorequestmessage.cpp b/src/icmp/icmpechorequestmessage.cpp
new file mode 100644 (file)
index 0000000..a196c7f
--- /dev/null
@@ -0,0 +1,126 @@
+#include "icmp/icmpechorequestmessage.h"
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// IcmpEchoRequestMessage
+//-----------------------------------------------------------------------------
+
+const int IcmpEchoRequestMessage::MessageSizeInBytes = 8;
+
+IcmpEchoRequestMessage::IcmpEchoRequestMessage()
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( IcmpType_InvalidLast );
+    set_code( 0 );
+    set_checksum( 0 );
+    set_identifier( 0 );
+    set_sequence_number( 0 );
+}
+
+IcmpEchoRequestMessage::IcmpEchoRequestMessage(
+        const IcmpType type,
+        const uint8_t code,
+        const uint16_t checksum,
+        const uint16_t identifier,
+        const uint16_t sequence_number
+)
+{
+    fill( Payload, Payload + sizeof(Payload), 0 );
+
+    set_type( type );
+    set_code( code );
+    set_checksum( checksum );
+    set_identifier( identifier );
+    set_sequence_number( sequence_number );
+}
+
+IcmpEchoRequestMessage::~IcmpEchoRequestMessage()
+{
+}
+
+IcmpType IcmpEchoRequestMessage::get_type() const
+{
+    IcmpType type = static_cast<IcmpType> ( Payload[ 0 ] );
+
+    return type;
+}
+
+void IcmpEchoRequestMessage::set_type( IcmpType type )
+{
+    uint8_t n = static_cast<uint8_t> ( type );
+
+    Payload[ 0 ] = n;
+}
+
+uint8_t IcmpEchoRequestMessage::get_code() const
+{
+    return Payload[ 1 ];
+}
+
+void IcmpEchoRequestMessage::set_code( uint8_t code )
+{
+    Payload[ 1 ] = code;
+}
+
+uint16_t IcmpEchoRequestMessage::get_checksum() const
+{
+    return decode( 2, 3 );
+}
+
+void IcmpEchoRequestMessage::set_checksum( uint16_t checksum )
+{
+    encode( 2, 3, checksum );
+}
+
+uint16_t IcmpEchoRequestMessage::get_identifier() const
+{
+    return decode( 4, 5 );
+}
+
+void IcmpEchoRequestMessage::set_identifier(
+        const uint16_t identifier
+)
+{
+    encode( 4, 5, identifier );
+}
+
+uint16_t IcmpEchoRequestMessage::get_sequence_number() const
+{
+    return decode( 6, 7 );
+}
+
+void IcmpEchoRequestMessage::set_sequence_number(
+        const uint16_t sequence_number
+)
+{
+    encode( 6, 7, sequence_number );
+}
+
+std::istream& IcmpEchoRequestMessage::read( std::istream &is )
+{
+    return is.read(
+            reinterpret_cast<char *> ( Payload ),
+            IcmpEchoRequestMessage::MessageSizeInBytes
+    );
+}
+
+std::ostream& IcmpEchoRequestMessage::write( std::ostream &os ) const
+{
+    return os.write(
+            reinterpret_cast<const char *> ( Payload ),
+            IcmpEchoRequestMessage::MessageSizeInBytes
+    );
+}
+
+uint16_t IcmpEchoRequestMessage::decode( int left_byte, int right_byte ) const
+{
+    return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ];
+}
+
+void IcmpEchoRequestMessage::encode( int left_byte, int right_byte, uint16_t value )
+{
+    Payload[ left_byte ] = static_cast<uint8_t> ( value >> 8 );
+    Payload[ right_byte ] = static_cast<uint8_t> ( value & 0xFF );
+}
diff --git a/src/icmp/icmpechorequestmessage.h b/src/icmp/icmpechorequestmessage.h
new file mode 100644 (file)
index 0000000..dfb2bda
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef ICMP_ECHO_REQUEST_MESSAGE_HPP
+#define ICMP_ECHO_REQUEST_MESSAGE_HPP
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include "icmp/icmpmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpEchoRequestMessage
+//-----------------------------------------------------------------------------
+//
+// ICMP Echo Request Message Format
+//
+// 0               8               16                             31
+// +---------------+---------------+------------------------------+      ---
+// |               |               |                              |       ^
+// |     type      |     code      |          checksum            |       |
+// |               |               |                              |       |
+// +---------------+---------------+------------------------------+    8 bytes
+// |                               |                              |       |
+// |          identifier           |       sequence number        |       |
+// |                               |                              |       v
+// +-------------------------------+------------------------------+      ---
+// |                                                              |
+// |                           data (n bytes)                     |
+// |                                                              |
+// +-------------------------------+------------------------------+
+//
+//-----------------------------------------------------------------------------
+
+class IcmpEchoRequestMessage : public IcmpMessage
+{
+public:
+    IcmpEchoRequestMessage();
+    IcmpEchoRequestMessage(
+            const IcmpType type,
+            const uint8_t code,
+            const uint16_t checksum,
+            const uint16_t identifier,
+            const uint16_t sequence_number
+    );
+    virtual ~IcmpEchoRequestMessage();
+
+    IcmpType get_type() const;
+    void set_type( const IcmpType type );
+
+    uint8_t get_code() const;
+    void set_code( const uint8_t code );
+
+    uint16_t get_checksum() const;
+    void set_checksum( const uint16_t checksum );
+
+    uint16_t get_identifier() const;
+    void set_identifier( const uint16_t identifier );
+
+    uint16_t get_sequence_number() const;
+    void set_sequence_number( const uint16_t sequence_number );
+
+    std::istream& read( std::istream &is );
+    std::ostream& write( std::ostream &os ) const;
+
+private:
+    uint16_t decode( int left_byte, int right_byte ) const;
+    void encode( int left_byte, int right_byte, uint16_t value );
+
+private:
+    static const int MessageSizeInBytes;
+    uint8_t Payload[ 8 ];
+
+};
+
+#endif // ICMP_ECHO_REQUEST_MESSAGE_HPP
diff --git a/src/icmp/icmpgenericmessage.cpp b/src/icmp/icmpgenericmessage.cpp
new file mode 100644 (file)
index 0000000..59418b4
--- /dev/null
@@ -0,0 +1,88 @@
+#include "icmp/icmpgenericmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpGenericMessage
+//-----------------------------------------------------------------------------
+
+IcmpGenericMessage::IcmpGenericMessage()
+{
+    set_type( IcmpType_InvalidLast );
+    set_code( 0 );
+    set_checksum( 0 );
+    set_identifier( 0 );
+    set_sequence_number( 0 );
+}
+
+IcmpGenericMessage::IcmpGenericMessage(
+        const IcmpType type,
+        const uint8_t code,
+        const uint16_t checksum,
+        const uint16_t identifier,
+        const uint16_t sequence_number
+)
+{
+    set_type( type );
+    set_code( code );
+    set_checksum( checksum );
+    set_identifier( identifier );
+    set_sequence_number( sequence_number );
+}
+
+IcmpGenericMessage::~IcmpGenericMessage()
+{
+}
+
+IcmpType IcmpGenericMessage::get_type() const
+{
+    return IcmpType_InvalidLast;
+}
+
+void IcmpGenericMessage::set_type( IcmpType )
+{
+}
+
+uint8_t IcmpGenericMessage::get_code() const
+{
+    return 0;
+}
+
+void IcmpGenericMessage::set_code( uint8_t )
+{
+}
+
+uint16_t IcmpGenericMessage::get_checksum() const
+{
+    return 0;
+}
+
+void IcmpGenericMessage::set_checksum( uint16_t )
+{
+}
+
+uint16_t IcmpGenericMessage::get_identifier() const
+{
+    return 0;
+}
+
+void IcmpGenericMessage::set_identifier( uint16_t )
+{
+}
+
+uint16_t IcmpGenericMessage::get_sequence_number() const
+{
+    return 0;
+}
+
+void IcmpGenericMessage::set_sequence_number( uint16_t )
+{
+}
+
+std::istream& IcmpGenericMessage::read( std::istream &is )
+{
+    return is;
+}
+
+std::ostream& IcmpGenericMessage::write( std::ostream &os ) const
+{
+    return os;
+}
diff --git a/src/icmp/icmpgenericmessage.h b/src/icmp/icmpgenericmessage.h
new file mode 100644 (file)
index 0000000..1c0bff9
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef ICMP_GENERIC_MESSAGE_HPP
+#define ICMP_GENERIC_MESSAGE_HPP
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include "icmp/icmpmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpGenericMessage
+//-----------------------------------------------------------------------------
+
+/**
+ * This class intends to handle ICMP messages that the application do not
+ * want to read. It acts like a stub.
+ */
+class IcmpGenericMessage : public IcmpMessage
+{
+public:
+    IcmpGenericMessage();
+    IcmpGenericMessage(
+            const IcmpType type,
+            const uint8_t code,
+            const uint16_t checksum,
+            const uint16_t identifier,
+            const uint16_t sequence_number
+    );
+    virtual ~IcmpGenericMessage();
+
+    IcmpType get_type() const;
+    void set_type( const IcmpType type );
+
+    uint8_t get_code() const;
+    void set_code( const uint8_t code );
+
+    uint16_t get_checksum() const;
+    void set_checksum( const uint16_t checksum );
+
+    uint16_t get_identifier() const;
+    void set_identifier( const uint16_t identifier );
+
+    uint16_t get_sequence_number() const;
+    void set_sequence_number( const uint16_t sequence_number );
+
+    std::istream& read( std::istream &is );
+    std::ostream& write( std::ostream &os ) const;
+
+};
+
+#endif // ICMP_GENERIC_MESSAGE_HPP
index 54d4124..c19b778 100644 (file)
@@ -1,23 +1,32 @@
 #include "icmp/icmpheader.h"
 
+#include "icmp/icmpdestinationunreachablemessage.h"
+#include "icmp/icmpechoreplymessage.h"
+#include "icmp/icmpechorequestmessage.h"
+#include "icmp/icmpgenericmessage.h"
+
+using namespace std;
+using boost::shared_ptr;
+
 //-----------------------------------------------------------------------------
 // IcmpHeader
 //-----------------------------------------------------------------------------
 
-IcmpHeader::IcmpHeader()
+IcmpHeader::IcmpHeader() :
+    MessageFormat()
 {
-    std::fill( Payload, Payload + sizeof(Payload), 0 );
 }
 
 IcmpHeader::IcmpHeader(
-        IcmpHeader::IcmpType type,
+        IcmpType type,
         uint8_t code,
         uint16_t checksum,
         uint16_t identifier,
         uint16_t sequence_number
-)
+) :
+    MessageFormat()
 {
-    std::fill( Payload, Payload + sizeof(Payload), 0 );
+    set_icmp_message_format( type );
 
     set_type( type );
     set_code( code );
@@ -26,59 +35,100 @@ IcmpHeader::IcmpHeader(
     set_sequence_number( sequence_number );
 }
 
-IcmpHeader::IcmpType IcmpHeader::get_type() const
+IcmpType IcmpHeader::get_type() const
 {
-    uint8_t n = Payload[ 0 ];
-    IcmpHeader::IcmpType type = static_cast<IcmpHeader::IcmpType> ( n );
-
-    return type;
+    return get_icmp_message_format()->get_type();
 }
 
-void IcmpHeader::set_type( IcmpHeader::IcmpType type )
+void IcmpHeader::set_type( IcmpType type )
 {
-    uint8_t n = type;
-
-    Payload[ 0 ] = n;
+    get_icmp_message_format()->set_type( type );
 }
 
 uint8_t IcmpHeader::get_code() const
 {
-    return Payload[ 1 ];
+    return get_icmp_message_format()->get_code();
 }
 
 void IcmpHeader::set_code( uint8_t code )
 {
-    Payload[ 1 ] = code;
+    get_icmp_message_format()->set_code( code );
 }
 
 uint16_t IcmpHeader::get_checksum() const
 {
-    return decode( 2, 3 );
+    return get_icmp_message_format()->get_checksum();
 }
 
 void IcmpHeader::set_checksum( uint16_t checksum )
 {
-    encode( 2, 3, checksum );
+    get_icmp_message_format()->set_checksum( checksum );
 }
 
 uint16_t IcmpHeader::get_identifier() const
 {
-    return decode( 4, 5 );
+    return get_icmp_message_format()->get_identifier();
 }
 
 void IcmpHeader::set_identifier( uint16_t identifier )
 {
-    encode( 4, 5, identifier );
+    get_icmp_message_format()->set_identifier( identifier );
 }
 
 uint16_t IcmpHeader::get_sequence_number() const
 {
-    return decode( 6, 7 );
+    return get_icmp_message_format()->get_sequence_number();
 }
 
 void IcmpHeader::set_sequence_number( uint16_t sequence_number )
 {
-    encode( 6, 7, sequence_number );
+    get_icmp_message_format()->set_sequence_number( sequence_number );
+}
+
+shared_ptr<IcmpMessage> IcmpHeader::get_icmp_message_format() const
+{
+    BOOST_ASSERT( MessageFormat.get() != NULL );
+
+    return MessageFormat;
+}
+
+void IcmpHeader::set_icmp_message_format( IcmpType type )
+{
+    BOOST_ASSERT( MessageFormat.get() == NULL );
+
+    if ( MessageFormat.get() == NULL )
+    {
+        switch ( type )
+        {
+            case IcmpType_EchoReply:
+                MessageFormat.reset( new IcmpEchoReplyMessage );
+                break;
+            case IcmpType_EchoRequest:
+                MessageFormat.reset( new IcmpEchoRequestMessage );
+                break;
+            case IcmpType_DestinationUnreachable:
+                MessageFormat.reset(
+                        new IcmpDestinationUnreachableMessage );
+                break;
+            default:
+                MessageFormat.reset( new IcmpGenericMessage );
+                break;
+        }
+    }
+}
+
+void IcmpHeader::set_icmp_message_format( std::istream &is )
+{
+    // read the first byte, which contains the type of the ICMP message
+    char first_byte;
+    is.read( &first_byte, 1 );
+
+    // must keep the stream intact, so place the read byte back
+    is.putback( first_byte );
+
+    // now select the message format for the given type
+    IcmpType header_type = static_cast<IcmpType> ( first_byte );
+    set_icmp_message_format( header_type );
 }
 
 std::istream& operator>>(
@@ -86,7 +136,11 @@ std::istream& operator>>(
         IcmpHeader &header
 )
 {
-    return is.read( reinterpret_cast<char *> ( header.Payload ), 8 );
+    // select the message format which will parse the fields
+    header.set_icmp_message_format( is );
+
+    // delegate the parsing of the fields to a specialized decoder
+    return header.get_icmp_message_format()->read( is );
 }
 
 std::ostream& operator<<(
@@ -94,16 +148,6 @@ std::ostream& operator<<(
         const IcmpHeader &header
 )
 {
-    return os.write( reinterpret_cast<const char *> ( header.Payload ), 8 );
-}
-
-uint16_t IcmpHeader::decode( int left_byte, int right_byte ) const
-{
-    return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ];
-}
-
-void IcmpHeader::encode( int left_byte, int right_byte, uint16_t value )
-{
-    Payload[ left_byte ] = static_cast<uint8_t> ( value >> 8 );
-    Payload[ right_byte ] = static_cast<uint8_t> ( value & 0xFF );
+    // delegate the writing of the fields to a specialized encoder
+    return header.get_icmp_message_format()->write( os );
 }
index 1a477d1..035b736 100644 (file)
@@ -6,45 +6,33 @@
 #include <istream>
 #include <ostream>
 
+#include <boost/shared_ptr.hpp>
+
+#include "icmp/icmpmessage.h"
+#include "icmp/icmptype.h"
+
 //-----------------------------------------------------------------------------
 // IcmpHeader
 //-----------------------------------------------------------------------------
-// ICMP header format
+//
+// ICMP Generic Header Format
 //
 // 0               8               16                             31
-// +---------------+---------------+------------------------------+      ---
-// |               |               |                              |       ^
-// |     type      |     code      |          checksum            |       |
-// |               |               |                              |       |
-// +---------------+---------------+------------------------------+    8 bytes
-// |                               |                              |       |
-// |          identifier           |       sequence number        |       |
-// |                               |                              |       v
-// +-------------------------------+------------------------------+      ---
+// +---------------+---------------+------------------------------+     ---
+// |               |               |                              |      ^
+// |     type      |     code      |          checksum            |   4 bytes
+// |               |               |                              |      v
+// +---------------+---------------+------------------------------+     ---
+// |                                                              |
+// |                     specific to each message                 |
+// |                                                              |
+// +-------------------------------+------------------------------+
 //
 //-----------------------------------------------------------------------------
 
 class IcmpHeader
 {
 public:
-    enum IcmpType
-    {
-        IcmpType_EchoReply = 0,
-        IcmpType_DestinationUnreachable = 3,
-        IcmpType_SourceQuench = 4,
-        IcmpType_Redirect = 5,
-        IcmpType_EchoRequest = 8,
-        IcmpType_TimeExceeded = 11,
-        IcmpType_ParameterProblem = 12,
-        IcmpType_TimestampRequest = 13,
-        IcmpType_TimestampReply = 14,
-        IcmpType_InfoRequest = 15,
-        IcmpType_InfoReply = 16,
-        IcmpType_AddressRequest = 17,
-        IcmpType_AddressReply = 18
-    };
-
-public:
     IcmpHeader();
     IcmpHeader(
             IcmpType type,
@@ -69,6 +57,10 @@ public:
     uint16_t get_sequence_number() const;
     void set_sequence_number( const uint16_t sequence_number );
 
+    boost::shared_ptr<IcmpMessage> get_icmp_message_format() const;
+    void set_icmp_message_format( IcmpType type );
+    void set_icmp_message_format( std::istream &is );
+
     friend std::istream& operator>>(
             std::istream &is,
             IcmpHeader &header
@@ -79,11 +71,7 @@ public:
     );
 
 private:
-    uint16_t decode( int left_byte, int right_byte ) const;
-    void encode( int left_byte, int right_byte, uint16_t value );
-
-private:
-    uint8_t Payload[ 8 ];
+    boost::shared_ptr<IcmpMessage> MessageFormat;
 
 };
 
diff --git a/src/icmp/icmpmessage.cpp b/src/icmp/icmpmessage.cpp
new file mode 100644 (file)
index 0000000..d7ead6e
--- /dev/null
@@ -0,0 +1,13 @@
+#include "icmp/icmpmessage.h"
+
+//-----------------------------------------------------------------------------
+// IcmpMessage
+//-----------------------------------------------------------------------------
+
+IcmpMessage::IcmpMessage()
+{
+}
+
+IcmpMessage::~IcmpMessage()
+{
+}
diff --git a/src/icmp/icmpmessage.h b/src/icmp/icmpmessage.h
new file mode 100644 (file)
index 0000000..02209ce
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef ICMP_MESSAGE_HPP
+#define ICMP_MESSAGE_HPP
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include "icmp/icmptype.h"
+
+//-----------------------------------------------------------------------------
+// IcmpMessage
+//-----------------------------------------------------------------------------
+
+class IcmpMessage
+{
+public:
+    IcmpMessage();
+    virtual ~IcmpMessage();
+
+    virtual IcmpType get_type() const = 0;
+    virtual void set_type( const IcmpType type ) = 0;
+
+    virtual uint8_t get_code() const = 0;
+    virtual void set_code( const uint8_t code ) = 0;
+
+    virtual uint16_t get_checksum() const = 0;
+    virtual void set_checksum( const uint16_t checksum ) = 0;
+
+    virtual uint16_t get_identifier() const = 0;
+    virtual void set_identifier( const uint16_t identifier ) = 0;
+
+    virtual uint16_t get_sequence_number() const = 0;
+    virtual void set_sequence_number( const uint16_t sequence_number ) = 0;
+
+    virtual std::istream& read( std::istream &is ) = 0;
+    virtual std::ostream& write( std::ostream &os ) const = 0;
+
+};
+
+#endif // ICMP_MESSAGE_HPP
index 43c1873..87f242f 100644 (file)
@@ -41,7 +41,7 @@ IcmpData IcmpPacket::get_icmp_data() const
 }
 
 bool IcmpPacket::match(
-        IcmpHeader::IcmpType type,
+        IcmpType type,
         uint16_t identifier,
         uint16_t sequence_number
 ) const
index 01ecac7..43e470b 100644 (file)
@@ -9,6 +9,7 @@
 #include "icmp/ipv4header.h"
 #include "icmp/icmpheader.h"
 #include "icmp/icmpdata.h"
+#include "icmp/icmptype.h"
 
 //-----------------------------------------------------------------------------
 // IcmpPacket
@@ -67,7 +68,7 @@ public:
     IcmpData get_icmp_data() const;
 
     bool match(
-            IcmpHeader::IcmpType type,
+            IcmpType type,
             uint16_t identifier,
             uint16_t sequence_number
     ) const;
diff --git a/src/icmp/icmptype.h b/src/icmp/icmptype.h
new file mode 100644 (file)
index 0000000..7407f5e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef ICMP_TYPE_H
+#define ICMP_TYPE_H
+
+enum IcmpType
+{
+    IcmpType_EchoReply = 0,
+    IcmpType_DestinationUnreachable = 3,
+    IcmpType_SourceQuench = 4,
+    IcmpType_Redirect = 5,
+    IcmpType_EchoRequest = 8,
+    IcmpType_TimeExceeded = 11,
+    IcmpType_ParameterProblem = 12,
+    IcmpType_TimestampRequest = 13,
+    IcmpType_TimestampReply = 14,
+    IcmpType_InfoRequest = 15,
+    IcmpType_InfoReply = 16,
+    IcmpType_AddressRequest = 17,
+    IcmpType_AddressReply = 18,
+    IcmpType_InvalidLast = 42
+};
+
+#endif /* ICMP_TYPE_H */