Bring aboard ICMPv6 header class
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Tue, 25 Oct 2011 00:15:01 +0000 (22:15 -0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Tue, 25 Oct 2011 00:27:26 +0000 (22:27 -0200)
src/icmp/icmptype.h
src/icmp/icmpv6header.cpp [new file with mode: 0644]
src/icmp/icmpv6header.h [new file with mode: 0644]

index 0ecb645..b414731 100644 (file)
@@ -28,6 +28,7 @@ enum Icmpv4Type
 
 enum Icmpv6Type
 {
+    Icmpv6Type_First = 0,
     // ICMPv6 Error Messages
     Icmpv6Type_DestinationUnreachable = 1,
     Icmpv6Type_PacketTooBig = 2,
diff --git a/src/icmp/icmpv6header.cpp b/src/icmp/icmpv6header.cpp
new file mode 100644 (file)
index 0000000..47b3afa
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff
+// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG
+//
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+#include "icmp/icmpv6header.h"
+
+#include "icmp/icmpdestinationunreachablemessage.h"
+#include "icmp/icmpechoreplymessage.h"
+#include "icmp/icmpechorequestmessage.h"
+#include "icmp/icmpgenericmessage.h"
+
+using namespace std;
+using boost::shared_ptr;
+
+//-----------------------------------------------------------------------------
+// Icmpv6Header
+//-----------------------------------------------------------------------------
+
+Icmpv6Header::Icmpv6Header() :
+    MessageFormat()
+{
+}
+
+Icmpv6Header::Icmpv6Header(
+        Icmpv6Type type,
+        uint8_t code,
+        uint16_t checksum,
+        uint16_t identifier,
+        uint16_t sequence_number
+) :
+    MessageFormat()
+{
+    set_icmp_message_format( type );
+
+    set_type( type );
+    set_code( code );
+    set_checksum( checksum );
+    set_identifier( identifier );
+    set_sequence_number( sequence_number );
+}
+
+Icmpv6Type Icmpv6Header::get_type() const
+{
+    return get_icmp_message_format()->get_type_v6();
+}
+
+void Icmpv6Header::set_type( Icmpv6Type type )
+{
+    get_icmp_message_format()->set_type_v6( type );
+}
+
+uint8_t Icmpv6Header::get_code() const
+{
+    return get_icmp_message_format()->get_code();
+}
+
+void Icmpv6Header::set_code( uint8_t code )
+{
+    get_icmp_message_format()->set_code( code );
+}
+
+uint16_t Icmpv6Header::get_checksum() const
+{
+    return get_icmp_message_format()->get_checksum();
+}
+
+void Icmpv6Header::set_checksum( uint16_t checksum )
+{
+    get_icmp_message_format()->set_checksum( checksum );
+}
+
+uint16_t Icmpv6Header::get_identifier() const
+{
+    return get_icmp_message_format()->get_identifier();
+}
+
+void Icmpv6Header::set_identifier( uint16_t identifier )
+{
+    get_icmp_message_format()->set_identifier( identifier );
+}
+
+uint16_t Icmpv6Header::get_sequence_number() const
+{
+    return get_icmp_message_format()->get_sequence_number();
+}
+
+void Icmpv6Header::set_sequence_number( uint16_t sequence_number )
+{
+    get_icmp_message_format()->set_sequence_number( sequence_number );
+}
+
+shared_ptr<IcmpMessage> Icmpv6Header::get_icmp_message_format() const
+{
+    BOOST_ASSERT( MessageFormat.get() != NULL );
+
+    return MessageFormat;
+}
+
+void Icmpv6Header::set_icmp_message_format( const Icmpv6Type type )
+{
+    BOOST_ASSERT( MessageFormat.get() == NULL );
+
+    if ( MessageFormat.get() == NULL )
+    {
+        switch ( type )
+        {
+            case Icmpv6Type_EchoReply:
+                MessageFormat.reset( new IcmpEchoReplyMessage );
+                break;
+            case Icmpv6Type_EchoRequest:
+                MessageFormat.reset( new IcmpEchoRequestMessage );
+                break;
+            case Icmpv6Type_DestinationUnreachable:
+                MessageFormat.reset(
+                        new IcmpDestinationUnreachableMessage
+                );
+                break;
+            case Icmpv6Type_PacketTooBig:
+            case Icmpv6Type_TimeExceeded:
+            case Icmpv6Type_ParameterProblem:
+            case Icmpv6Type_RouterSolicitation:
+            case Icmpv6Type_RouterAdvertisement:
+            case Icmpv6Type_NeighborSolicitation:
+            case Icmpv6Type_NeighborAdvertisement:
+            case Icmpv6Type_RedirectMessage:
+            case Icmpv6Type_RouterRenumbering:
+            case Icmpv6Type_ICMPNodeInformationQuery:
+            case Icmpv6Type_ICMPNodeInformationResponse:
+            case Icmpv6Type_InverseNeighborDiscoverySolicitationMessage:
+            case Icmpv6Type_InverseNeighborDiscoveryAdvertisementMessage:
+            case Icmpv6Type_MulticastListenerDiscovery:
+            case Icmpv6Type_HomeAgentAddressDiscoveryRequestMessage:
+            case Icmpv6Type_HomeAgentAddressDiscoveryReplyMessage:
+            case Icmpv6Type_MobilePrefixSolicitation:
+            case Icmpv6Type_MobilePrefixAdvertisement:
+            case Icmpv6Type_CertificationPathSolicitation:
+            case Icmpv6Type_CertificationPathAdvertisement:
+            case Icmpv6Type_MulticastRouterAdvertisement:
+            case Icmpv6Type_MulticastRouterSolicitation:
+            case Icmpv6Type_MulticastRouterTermination:
+            case Icmpv6Type_Generic:
+                MessageFormat.reset( new IcmpGenericMessage );
+                break;
+            case Icmpv6Type_InvalidLast:
+            default:
+                BOOST_ASSERT( false );
+                break;
+        }
+
+        MessageFormat->init( type );
+    }
+
+    BOOST_ASSERT( MessageFormat.get() != NULL );
+    BOOST_ASSERT( MessageFormat->get_type_v6() != Icmpv6Type_InvalidLast );
+}
+
+void Icmpv6Header::set_icmp_message_format( std::istream &is )
+{
+    // read the first byte, which contains the type of the ICMP message
+    uint8_t first_byte = 0;
+    (void) is.read( reinterpret_cast<char *>(&first_byte), 1 );
+
+    // must keep the stream intact, so place the read byte back
+    (void) is.putback( first_byte );
+
+    // now select the message format for the given type
+    Icmpv6Type header_type = static_cast<Icmpv6Type>( first_byte );
+    set_icmp_message_format( header_type );
+}
+
+std::istream& operator>>(
+        std::istream &is,
+        Icmpv6Header &header
+)
+{
+    // 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<<(
+        std::ostream &os,
+        const Icmpv6Header &header
+)
+{
+    // delegate the writing of the fields to a specialized encoder
+    return header.get_icmp_message_format()->write( os );
+}
diff --git a/src/icmp/icmpv6header.h b/src/icmp/icmpv6header.h
new file mode 100644 (file)
index 0000000..227348d
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff
+// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG
+//
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+#ifndef ICMPV6_HEADER_H
+#define ICMPV6_HEADER_H
+
+#include <stdint.h>
+
+#include <istream>
+#include <ostream>
+
+#include <boost/shared_ptr.hpp>
+
+#include "icmp/icmpmessage.h"
+#include "icmp/icmptype.h"
+
+//-----------------------------------------------------------------------------
+// Icmpv6Header
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This class represents the ICMP version 6 Header.
+ *
+ * The ICMP Generic Header Format is:
+ *
+ * @code
+ * 0               8               16                             31
+ * +---------------+---------------+------------------------------+     ---
+ * |               |               |                              |      ^
+ * |     type      |     code      |          checksum            |   4 bytes
+ * |               |               |                              |      v
+ * +---------------+---------------+------------------------------+     ---
+ * |                                                              |
+ * |                     specific to each message                 |
+ * |                                                              |
+ * +-------------------------------+------------------------------+
+ * @endcode
+ */
+class Icmpv6Header
+{
+public:
+    Icmpv6Header();
+    Icmpv6Header(
+            Icmpv6Type type,
+            uint8_t code,
+            uint16_t checksum,
+            uint16_t identifier,
+            uint16_t sequence_number
+    );
+
+    Icmpv6Type get_type() const;
+    void set_type( const Icmpv6Type 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 );
+
+    boost::shared_ptr<IcmpMessage> get_icmp_message_format() const;
+    void set_icmp_message_format( const Icmpv6Type type );
+    void set_icmp_message_format( std::istream &is );
+
+    friend std::istream& operator>>(
+            std::istream &is,
+            Icmpv6Header &header
+    );
+    friend std::ostream& operator<<(
+            std::ostream &os,
+            const Icmpv6Header &header
+    );
+
+private:
+    /// Changeable pointer to different ICMP messages types.
+    boost::shared_ptr<IcmpMessage> MessageFormat;
+
+};
+
+#endif // ICMPV6_HEADER_H