/// <summary>
        ///		Send a new ping packet.
        /// </summary>
        /// <param name="destination">
        ///		The address to send the packet to.
        ///	</param>
        /// <param name="payload">
        ///		The data to send in the ping.
        ///	</param>
        /// <param name="async">
        ///		If this is true, SendPing will return immediately otherwise it will wait
        ///	</param>
        /// <param name="timeOutTime">
        ///		The number of milliseconds before the reply times out.
        ///	</param>
        /// <exception cref="ObjectDisposedException">
        ///		If the class has been disposed then an ObjectDisposedException will be thrown.
        ///	</exception>
        /// <exception cref="Exception">
        ///		If the class is already waiting for a ping reply then an exception will be thrown.
        ///		Use the CancelPing method first.
        ///	</exception>
        public void SendPing(IPAddress destination, byte[] payload, bool async, double timeOutTime)
        {
            if (m_disposed)
            {
                throw new ObjectDisposedException(this.ToString(), "This object has already been disposed");
            }

            // check if a ping is already in process
            if (m_id != 0)
            {
                throw new Exception("A ping request is already in process. Either wait for the reply, or cancel the request first");
            }

            Random   random = new Random();
            IcmpEcho echo   = new IcmpEcho();

            // generate random identifier and sequence number
            echo.Identifier     = (ushort)random.Next(ushort.MaxValue);
            echo.SequenceNumber = (ushort)random.Next(ushort.MaxValue);

            m_id             = echo.Identifier;
            m_remoteAddress  = destination;
            m_timer.Interval = timeOutTime;

            // store the payload
            echo.Data = payload;

            // build the icmp header
            IcmpPacket icmpHeader = echo.Serialize(false);

            // build the ip header
            IpV4Packet ipHeader = new IpV4Packet();

            ipHeader.TransportProtocol  = ProtocolType.Icmp;
            ipHeader.SourceAddress      = m_networkInterface;
            ipHeader.DestinationAddress = destination;
            ipHeader.Data = icmpHeader.Serialize();

            if (m_fragment)
            {
                IpV4Packet[] fragments = ipHeader.Fragment(8);

                // send each fragment
                for (int i = 0; i < fragments.Length; i++)
                {
                    byte[] packet = fragments[i].Serialize();
                    m_socket.SendTo(packet, 0, packet.Length, SocketFlags.None, new IPEndPoint(fragments[i].DestinationAddress, 0));
                }
            }
            else
            {
                // send the packet
                byte[] packet = ipHeader.Serialize();
                m_socket.SendTo(packet, 0, packet.Length, SocketFlags.None, new IPEndPoint(ipHeader.DestinationAddress, 0));
            }

            // save the time and  start the timeout timer
            m_start         = Environment.TickCount;
            m_timer.Enabled = true;

            // wait for the reply
            m_waitObject.Reset();

            if (!async)
            {
                m_waitObject.WaitOne();
            }
        }
        /// <summary>
        ///		Send the next request in order to find the next hop.
        /// </summary>
        private void SendRequest()
        {
            // generate a 32 byte payload
            string data = new string ('x', 32);

            byte[] payload = System.Text.ASCIIEncoding.ASCII.GetBytes(data);

            // fill in ip header fields
            IpV4Packet ipPacket = new IpV4Packet();

            ipPacket.DestinationAddress = m_remoteAddress;
            ipPacket.SourceAddress      = m_localAddress;
            ipPacket.TransportProtocol  = ProtocolType.Icmp;
            ipPacket.TimeToLive         = m_ttl;

            // save the identification
            m_ipId = ipPacket.Identification;

            // add routing options if any
            if (m_route != null)
            {
                ipPacket.Options = new IpV4Option[2];

                ipPacket.Options[0] = m_route.Serialize(m_strictRouting ? IpV4OptionNumber.StrictSourceRouting : IpV4OptionNumber.LooseSourceRouting);

                ipPacket.Options[1]            = new IpV4Option();
                ipPacket.Options[1].OptionType = IpV4OptionNumber.EndOfOptions;
                ipPacket.Options[1].IsCopied   = false;
                ipPacket.Options[1].Length     = 1;
                ipPacket.Options[1].Class      = IpV4OptionClass.Control;
                ipPacket.Options[1].Data       = null;
            }

            // create a new echo packet
            IcmpEcho echo = new IcmpEcho();

            echo.Identifier = m_id;
            echo.Data       = payload;

            // serialize the icmp packet
            IcmpPacket icmpPacket = echo.Serialize(false);

            ipPacket.Data = icmpPacket.Serialize();


            if (m_fragment)
            {
                IpV4Packet[] fragments = ipPacket.Fragment(8);

                // send each fragment
                for (int i = 0; i < fragments.Length; i++)
                {
                    byte[] packet = fragments[i].Serialize();
                    m_socket.SendTo(packet, 0, packet.Length, SocketFlags.None, new IPEndPoint(fragments[i].DestinationAddress, 0));
                }
            }
            else
            {
                // send the ip packet
                byte[] packet = ipPacket.Serialize();
                m_socket.SendTo(packet, 0, packet.Length, SocketFlags.None, new IPEndPoint(ipPacket.DestinationAddress, 0));
            }


            // grab the current time
            m_start = Environment.TickCount;

            // start the timeout timer
            m_timer.Enabled = true;
        }