< Adding C++ ICMP For Ipv4 Header Definition Class 3 | Main | Adding C++ UDP Header Definition Class 5 >

 


 

Chapter 8 Part 11:

Client (and Server) Sockets Communication

 

 

What do we have in this chapter 8 Part 11?

  1. Creating Protocols Header Definition Class (C++) 4

 

Creating Protocols Header Definition Class (C++) 4

 

Next, add the ICMP for Ipv6 class.

 

public ref class Icmpv6Header : ProtocolHeader

{

private:

    Byte icmpType;

    Byte icmpCode;

    unsigned short icmpChecksum;

 

public:

     Ipv6Header^ ipv6Header;

 

    // Common values for the ICMPv6 type and code fields

public:

    static Byte Icmpv6EchoRequestType = 128;      // ICMPv6 echo request type

    static Byte Icmpv6EchoRequestCode = 0;        // ICMPv6 echo request code

    static Byte Icmpv6EchoReplyType = 129;      // ICMPv6 echo reply type

    static Byte Icmpv6EchoReplyCode = 0;        // ICMPv6 echo reply code

    static int Icmpv6HeaderLength = 4;             // ICMPv6 header length

 

    /// <summary>

    /// Simple constructor for the ICMPv6 protocol header.

    /// </summary>

public:

    Icmpv6Header()

    {

        icmpType = 0;

        icmpCode = 0;

        icmpChecksum = 0;

    }

 

    /// <summary>

    /// Constructor for the ICMPv6 header which also takes a reference to the

    /// encompassing IPv6 header. This is necessary since the IPv6 protocol

    /// defines a pseudo header checksum which requires the checksum to be

    /// calculated over fields in the ICMPv6 header and payload as well as

    /// fields from the IPv6 packet.

    /// </summary>

    /// <param name="packetHeader">Reference to the Ipv6Header object encompassing the ICMPv6 packet</param>

public:

    Icmpv6Header(Ipv6Header^ packetHeader)

    {

        icmpType = 0;

        icmpCode = 0;

        icmpChecksum = 0;

        ipv6Header = packetHeader;

    }

 

    /// <summary>

    /// Sets the ICMPv6 message type.

    /// </summary>

public:

    property Byte Type

    {

        Byte get()

        {

            return icmpType;

        }

        void set(Byte value)

        {

            icmpType = value;

        }

    }

 

    /// <summary>

    /// Sets the ICMPv6 code type.

    /// </summary>

public:

    property Byte Code

    {

        Byte get()

        {

            return icmpCode;

        }

        void set(Byte value)

        {

            icmpCode = value;

        }

    }

 

    /// <summary>

    /// The ICMPv6 checksum value. This value is computed over the ICMPv6 header, payload,

    /// and the IPv6 header as well.

    /// </summary>

public:

    property unsigned short Checksum

    {

        unsigned short get()

        {

             return (unsigned short)IPAddress::NetworkToHostOrder((short)icmpChecksum);

        }

        void set(unsigned short value)

        {

             icmpChecksum = (unsigned short)IPAddress::HostToNetworkOrder((short)value);

        }

    }

 

    /// <summary>

    /// This routine creates an instance of the Icmpv6Header class from a byte

    /// array that is a received IGMP packet. This is useful when a packet

    /// is received from the network and the header object needs to be

    /// constructed from those values.

    /// </summary>

    /// <param name="icmpv6Packet">Byte array containing the binary ICMPv6 header</param>

    /// <param name="bytesCopied">Number of bytes used in header</param>

    /// <returns>Returns the Icmpv6Header object created from the byte array</returns>

    public:

    static Icmpv6Header^ Create(array<Byte>^ icmpv6Packet, int bytesCopied)

    {

        Icmpv6Header^ icmpv6Header = gcnew Icmpv6Header();

        int offset = 0;

 

        // Verify buffer is large enough to contain an ICMPv6 header

        if (icmpv6Packet->Length < Icmpv6Header::Icmpv6HeaderLength)

            return nullptr;

 

        icmpv6Header->icmpType = icmpv6Packet[offset++];

        icmpv6Header->icmpCode = icmpv6Packet[offset++];

        icmpv6Header->icmpChecksum = BitConverter::ToUInt16(icmpv6Packet, offset);

        bytesCopied = Icmpv6Header::Icmpv6HeaderLength;

        return icmpv6Header;

    }

 

    /// <summary>

    /// This routine builds the ICMPv6 packet and payload into a byte array.

    /// It also computes the IPv6 pseudo header checksum that appears in the

    /// ICMPv6 packet.

    /// </summary>

    /// <param name="payLoad">A byte array representing the ICMPv6 payload</param>

    /// <returns>A byte array of the ICMPv6 packet and payload</returns>

    public:

    virtual array<Byte>^ GetProtocolPacketBytes(array<Byte>^ payLoad) override

    {

        array<Byte>^ icmpv6Packet;

        array<Byte>^ pseudoHeader;

        array<Byte>^ byteValue;

        int offset = 0, payLoadLength;

 

        // Build the ICMPv6 packet first since its required in the pseudo header calculation

        icmpv6Packet = gcnew array<Byte>(Icmpv6HeaderLength + payLoad->Length);

 

        offset = 0;

        icmpv6Packet[offset++] = icmpType;

        icmpv6Packet[offset++] = icmpCode;

        icmpv6Packet[offset++] = 0;

        icmpv6Packet[offset++] = 0;

 

        // Copy the payload into the build ICMPv6 packet

        Array::Copy(payLoad, 0, icmpv6Packet, offset, payLoad->Length);

 

        // Now build the pseudo header

        pseudoHeader = gcnew array<Byte>(40 + icmpv6Packet->Length);

        offset = 0;

 

        byteValue = ipv6Header->SourceAddress->GetAddressBytes();

        Array::Copy(byteValue, 0, pseudoHeader, offset, byteValue->Length);

        offset += byteValue->Length;

 

        byteValue = ipv6Header->DestinationAddress->GetAddressBytes();

        Array::Copy(byteValue, 0, pseudoHeader, offset, byteValue->Length);

        offset += byteValue->Length;

 

        // Packet total length

        payLoadLength = IPAddress::HostToNetworkOrder(Icmpv6HeaderLength + payLoad->Length);

        byteValue = BitConverter::GetBytes(payLoadLength);

        Array::Copy(byteValue, 0, pseudoHeader, offset, byteValue->Length);

        offset += byteValue->Length;

 

        // 3 bytes of zero padding

        pseudoHeader[offset++] = (Byte)0;

        pseudoHeader[offset++] = (Byte)0;

        pseudoHeader[offset++] = (Byte)0;

        pseudoHeader[offset++] = (Byte)ipv6Header->NextHeader;

 

        // Next is the icmpv6 header and its payload

        Array::Copy(icmpv6Packet, 0, pseudoHeader, offset, icmpv6Packet->Length);

        offset += icmpv6Packet->Length;

 

        // Compute checksum on pseudo header

        Checksum = ComputeChecksum(pseudoHeader);

 

        // Go back and put the checksum value into the marshalled byte array

        byteValue = BitConverter::GetBytes(icmpChecksum);

        Array::Copy(byteValue, 0, icmpv6Packet, 2, byteValue->Length);

 

        return icmpv6Packet;

    }

};

 

 

 

Next, add the ICMP for Ipv6 echo request class.

 

/// <summary>

/// Class representing the ICMPv6 echo request header. Since the ICMPv6 protocol is

/// used for a variety of different functions other than "ping", this header is

/// broken out from the base ICMPv6 header that is common across all of its functions

/// (such as Multicast Listener Discovery, Neighbor Discovery, etc.).

/// </summary>

public ref class Icmpv6EchoRequest : ProtocolHeader

{

private:

    unsigned short echoId;

    unsigned short echoSequence;

public:

    static int Icmpv6EchoRequestLength = 4;

 

    /// <summary>

    /// Simple constructor for the ICMPv6 echo request header

    /// </summary>

public:

    Icmpv6EchoRequest()

    {

        echoId = 0;

        echoSequence = 0;

    }

 

    /// <summary>

    /// Gets and sets the ID field. Also performs the necessary byte order conversion.

    /// </summary>

public:

    property unsigned short Id

    {

        unsigned short get()

        {

            return (unsigned short)IPAddress::NetworkToHostOrder((short)echoId);

        }

        void set(unsigned short value)

        {

            echoId = (unsigned short)IPAddress::HostToNetworkOrder((short)value);

        }

    }

 

    /// <summary>

    /// Gets and sets the echo sequence field. Also performs the necessary byte order conversion.

    /// </summary>

public:

    property unsigned short Sequence

    {

        unsigned short get()

        {

            return (unsigned short)IPAddress::NetworkToHostOrder((short)echoSequence);

        }

        void set(unsigned short value)

        {

            echoSequence = (unsigned short)IPAddress::HostToNetworkOrder((short)value);

        }

    }

 

    /// <summary>

    /// This routine creates an instance of the Icmpv6EchoRequest class from a byte

    /// array that is a received IGMP packet. This is useful when a packet

    /// is received from the network and the header object needs to be

    /// constructed from those values.

    /// </summary>

    /// <param name="echoData">Byte array containing the binary ICMPv6 echo request header</param>

    /// <param name="bytesCopied">Number of bytes used in header</param>

    /// <returns>Returns the Icmpv6EchoRequest object created from the byte array</returns>

public:

    static Icmpv6EchoRequest^ Create(array<Byte>^ echoData, int bytesCopied)

    {

        Icmpv6EchoRequest^ icmpv6EchoRequestHeader = gcnew Icmpv6EchoRequest();

        // Verify buffer is large enough

        if (echoData->Length < Icmpv6EchoRequest::Icmpv6EchoRequestLength)

            return nullptr;

 

        // Properties are stored in network byte order so just grab the bytes

        //    from the buffer

        icmpv6EchoRequestHeader->echoId = BitConverter::ToUInt16(echoData, 0);

        icmpv6EchoRequestHeader->echoSequence = BitConverter::ToUInt16(echoData, 2);

        bytesCopied = Icmpv6EchoRequest::Icmpv6EchoRequestLength;

        return icmpv6EchoRequestHeader;

    }

 

    /// <summary>

    /// This method builds the byte array representation of the ICMPv6 echo request header

    /// as it would appear on the wire.

    /// </summary>

    /// <param name="payLoad">Payload to appear after the ICMPv6 echo request header</param>

    /// <returns>Returns the byte array representing the packet and payload</returns>

public:

    virtual array<Byte>^ GetProtocolPacketBytes(array<Byte>^ payLoad) override

    {

        array<Byte>^ icmpv6EchoRequestHeader = gcnew array<Byte>(Icmpv6EchoRequestLength + payLoad->Length);

        array<Byte>^ byteValue;

        int offset = 0;

 

        byteValue = BitConverter::GetBytes(echoId);

        Array::Copy(byteValue, 0, icmpv6EchoRequestHeader, offset, byteValue->Length);

        offset += byteValue->Length;

 

        byteValue = BitConverter::GetBytes(echoSequence);

        Array::Copy(byteValue, 0, icmpv6EchoRequestHeader, offset, byteValue->Length);

        offset += byteValue->Length;

        Array::Copy(payLoad, 0, icmpv6EchoRequestHeader, offset, payLoad->Length);

        return icmpv6EchoRequestHeader;

    }

};

 

 

 


 

< Adding C++ ICMP For Ipv4 Header Definition Class 3 | Main | Adding C++ UDP Header Definition Class 5 >