< Adding C++ UDP Header Definition Class 5 | Main | Adding C# IPv4 Definition Class 2 >

 


 

Chapter 8 Part 13:

Client (and Server) Sockets Communication

 

 

What do we have in this chapter 8 Part 13?

23.                Creating Protocols Header Definition Class (C#) 1

 

 

Creating Protocols Header Definition Class (C#) 1

 

Create a new class library project and you might use ProtocolHeaderDefinition as the name. This class will be used in the next related TCP/IP program examples. It contains the header definition of the dominant protocols such as TCP, UDP and IP (for both IPv4 and IPv6). We will compile this class to make sure there is no error then we are ready to use the generated DLL or just the source file.

 

Creating Protocols Header Definition Class (C#) - invoking the New Project page through a menu

 

Creating Protocols Header Definition Class (C#) - a new class library project creation

 

Rename the source file to Protocol.cs.

 

Creating Protocols Header Definition Class (C#) - renaming the source file automatically renaming the class name

 

Add/edit the following using directives at the top of the file.

 

using System;

using System.Net;

using System.Net.Sockets;

using System.Collections;

 

Rename the class to WinsockIoctl.

 

Creating Protocols Header Definition Class (C#) - renaming the class using the Refactor context menu

 

Check all the three check boxes. Click Apply.

 

Creating Protocols Header Definition Class (C#) - the object rename VS 2008 IDE page

 

Click Apply to confirm and complete the renaming process.

 

Creating Protocols Header Definition Class (C#) - previewing the renaming process before confirmation

 

Add the following code for the WinsockIoctl class.

 

public class WinsockIoctl

    {

        /// <summary>

        /// An interface query takes the socket address of a remote destination and

        /// returns the local interface that destination is reachable on.

        /// </summary>

        public const int SIO_ROUTING_INTERFACE_QUERY = -939524076;  // otherwise equal to 0xc8000014

        /// <summary>

        /// The address list query returns a list of all local interface addresses.

        ///

        /// </summary>

        public const int SIO_ADDRESS_LIST_QUERY = 0x48000016;

    }

 

 

 

Add another class, SockaddrConvert.

 

    class SockaddrConvert

    {

        /// <summary>

        /// This routine converts an IPEndPoint into a byte array that represents the

        /// underlying sockaddr structure of the correct type. Currently this routine

        /// supports only IPv4 and IPv6 socket address structures.

        /// </summary>

        /// <param name="endPoint">IPEndPoint to convert to a binary form</param>

        /// <returns>Binary array of the serialized socket address structure</returns>

        static public byte[] GetSockaddrBytes(IPEndPoint endPoint)

        {

            SocketAddress socketAddress = endPoint.Serialize();

            byte[] sockaddrBytes;

 

            sockaddrBytes = new byte[socketAddress.Size];

 

            for (int i = 0; i < socketAddress.Size; i++)

            {

                sockaddrBytes[i] = socketAddress[i];

            }

            return sockaddrBytes;

        }

 

        /// <summary>

        /// This routine converts the binary representation of a sockaddr structure back

        /// into an IPEndPoint object. This is done by looking at the first 2 bytes of the

        /// serialized byte array which always indicate the address family of the underlying

        /// structure. From this we can construct the appropriate IPEndPoint object.

        /// </summary>

        /// <param name="sockaddrBytes"></param>

        /// <returns></returns>

        static public IPEndPoint GetEndPoint(byte[] sockaddrBytes)

        {

            IPEndPoint unpackedEndpoint = null;

            IPAddress unpackedAddress;

            ushort addressFamily,unpackedPort;

 

            // Reconstruct the 16-bit (short) value representing the address family    

            addressFamily = BitConverter.ToUInt16(sockaddrBytes, 0);

 

            if (addressFamily == 2)   // AF_INET

            {

                byte[] addressBytes = new byte[4];

 

                unpackedPort = BitConverter.ToUInt16(sockaddrBytes, 2);

                unpackedAddress = new IPAddress(BitConverter.ToUInt32(sockaddrBytes, 4));

                unpackedEndpoint = new IPEndPoint(unpackedAddress, unpackedPort);

            }

            else if (addressFamily == 23)     // AF_INET6

            {

                byte[] addressBytes = new byte[16];

 

                unpackedPort = BitConverter.ToUInt16(sockaddrBytes, 2);

 

                Array.Copy(sockaddrBytes, 8, addressBytes, 0, 16);

 

                unpackedAddress = new IPAddress(addressBytes);

 

                unpackedEndpoint = new IPEndPoint(unpackedAddress, unpackedPort);

            }

            else

            {

                Console.WriteLine("GetEndPoint: Unknown address family: {0}", addressFamily);

            }

 

            return unpackedEndpoint;

        }

    }

 

Next, add the abstract class, ProtocolHeader.

 

abstract class ProtocolHeader

    {

        /// <summary>

        /// This abstracted method returns a byte array that is the protocol

        /// header and the payload. This is used by the BuildPacket method

        /// to build the entire packet which may consist of multiple headers

        /// and data payload.

        /// </summary>

        /// <param name="payLoad">The byte array of the data encapsulated in this header</param>

        /// <returns>A byte array of the serialized header and payload</returns>

        abstract public byte[ ] GetProtocolPacketBytes(byte[ ] payLoad);

 

        /// <summary>

        /// This method builds the entire packet to be sent on the socket. It takes

        /// an ArrayList of all encapsulated headers as well as the payload. The

        /// ArrayList of headers starts with the outermost header towards the

        /// innermost. For example when sending an IPv4/UDP packet, the first entry

        /// would be the IPv4 header followed by the UDP header. The byte payload of

        /// the UDP packet is passed as the second parameter.

        /// </summary>

        /// <param name="headerList">An array list of all headers to build the packet from</param>

        /// <param name="payLoad">Data payload appearing after all the headers</param>

        /// <returns>Returns a byte array representing the entire packet</returns>

        public byte[ ] BuildPacket(ArrayList headerList, byte[ ] payLoad)

        {

            ProtocolHeader protocolHeader;

            byte[ ] newPayload = null;

 

            // Traverse the array in reverse order since the outer headers may need

            //    the inner headers and payload to compute checksums on.

            for (int i = headerList.Count - 1; i >= 0; i--)

            {

                protocolHeader = (ProtocolHeader)headerList[i];

                newPayload = protocolHeader.GetProtocolPacketBytes(payLoad);

 

                // The payLoad for the next iteration of the loop is now any

                //    encapsulated headers plus the original payload data.

                payLoad = newPayload;

            }

 

            return payLoad;

        /// and data payload.

        /// </summary>

        /// <param name="payLoad">The byte array of the data encapsulated in this header</param>

        /// <returns>A byte array of the serialized header and payload</returns>

        abstract public byte[ ] GetProtocolPacketBytes(byte[ ] payLoad);

 

        /// <summary>

        /// This method builds the entire packet to be sent on the socket. It takes

        /// an ArrayList of all encapsulated headers as well as the payload. The

        /// ArrayList of headers starts with the outermost header towards the

        /// innermost. For example when sending an IPv4/UDP packet, the first entry

        /// would be the IPv4 header followed by the UDP header. The byte payload of

        /// the UDP packet is passed as the second parameter.

        /// </summary>

        /// <param name="headerList">An array list of all headers to build the packet from</param>

        /// <param name="payLoad">Data payload appearing after all the headers</param>

        /// <returns>Returns a byte array representing the entire packet</returns>

        public byte[ ] BuildPacket(ArrayList headerList, byte[ ] payLoad)

        {

            ProtocolHeader protocolHeader;

            byte[ ] newPayload = null;

 

            // Traverse the array in reverse order since the outer headers may need

            //    the inner headers and payload to compute checksums on.

            for (int i = headerList.Count - 1; i >= 0; i--)

            {

                protocolHeader = (ProtocolHeader)headerList[i];

                newPayload = protocolHeader.GetProtocolPacketBytes(payLoad);

 

                // The payLoad for the next iteration of the loop is now any

                //    encapsulated headers plus the original payload data.

                payLoad = newPayload;

            }

 

            return payLoad;

        }

 

        /// <summary>

        /// This is a simple method for computing the 16-bit one's complement

        /// checksum of a byte buffer. The byte buffer will be padded with

        /// a zero byte if an uneven number.

        /// </summary>

        /// <param name="payLoad">Byte array to compute checksum over</param>

        /// <returns></returns>

        static public ushort ComputeChecksum(byte[ ] payLoad)

        {

            uint xsum = 0;

            ushort shortval = 0, hiword = 0, loword = 0;

 

            // Sum up the 16-bits

            for (int i = 0; i < payLoad.Length / 2; i++)

            {

                hiword = (ushort)(((ushort)payLoad[i * 2]) << 8);

                loword = (ushort)payLoad[(i * 2) + 1];

                shortval = (ushort)(hiword | loword);

                xsum = xsum + (uint)shortval;

            }

            // Pad if necessary

            if ((payLoad.Length % 2) != 0)

            {

                xsum += (uint)payLoad[payLoad.Length - 1];

            }

 

            xsum = ((xsum >> 16) + (xsum & 0xFFFF));

            xsum = (xsum + (xsum >> 16));

            shortval = (ushort)(~xsum);

 

            return shortval;

        }

 

        /// <summary>

        /// Utility function for printing a byte array into a series of 4 byte hex digits with

        /// four such hex digits displayed per line.

        /// </summary>

        /// <param name="printBytes">Byte array to display</param>

        static public void PrintByteArray(byte[ ] printBytes)

        {

            int index = 0;

 

            while (index < printBytes.Length)

            {

                for (int i = 0; i < 4; i++)

                {

                    if (index >= printBytes.Length)

                        break;

 

                    for (int j = 0; j < 4; j++)

                    {

                        if (index >= printBytes.Length)

                            break;

 

                        Console.Write("{0}", printBytes[index++].ToString("x2"));

                    }

                    Console.Write(" ");

                }

                Console.WriteLine("");

            }

        }

    }

 

 

 


 

< Adding C++ UDP Header Definition Class 5 | Main | Adding C# IPv4 Definition Class 2 >