ping.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Net / System / Net / NetworkInformation / ping.cs / 1 / ping.cs

                             
namespace System.Net.NetworkInformation {

    using System.Net;
    using System.Net.Sockets; 
    using System;
    using System.Runtime.InteropServices; 
    using System.Threading; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Security.Permissions;

    public delegate void PingCompletedEventHandler (object sender, PingCompletedEventArgs e);
 

    public class PingCompletedEventArgs: System.ComponentModel.AsyncCompletedEventArgs { 
        PingReply reply; 

        internal PingCompletedEventArgs (PingReply reply, Exception error, bool cancelled, object userToken):base(error,cancelled,userToken) { 
            this.reply = reply;
        }
        public PingReply Reply{get {return reply;}}
    } 

    public class Ping:Component,IDisposable 
    { 
        const int MaxUdpPacket = 0xFFFF + 256; // Marshal.SizeOf(typeof(Icmp6EchoReply)) * 2 + ip header info;
        const int MaxBufferSize = 65500; //artificial constraint due to win32 api limitations. 
        const int DefaultTimeout = 5000; //5 seconds same as ping.exe
        const int DefaultSendBufferSize = 32;  //same as ping.exe

        byte[] defaultSendBuffer = null; 
        bool ipv6 = false;
        bool inAsyncCall = false; 
        bool cancelled = false; 
        bool disposed = false;
 
        //used for icmpsendecho apis
        internal ManualResetEvent pingEvent = null;
        private RegisteredWaitHandle registeredWait = null;
        SafeLocalFree requestBuffer = null; 
        SafeLocalFree replyBuffer = null;
        int sendSize = 0;  //----s, but needed to determine what reply size is for ipv6 in callback 
 
        //used for downlevel calls
        const int TimeoutErrorCode = 0x274c; 
        const int PacketTooBigErrorCode = 0x2738;
        Socket pingSocket = null;
        byte[] downlevelReplyBuffer = null;
        SafeCloseIcmpHandle handlePingV4 = null; 
        SafeCloseIcmpHandle handlePingV6 = null;
        int startTime = 0; 
        IcmpPacket packet = null; 
        int llTimeout = 0;
 
        //new async event support
        AsyncOperation asyncOp = null;
        SendOrPostCallback onPingCompletedDelegate;
        public event PingCompletedEventHandler PingCompleted; 

 
        protected void OnPingCompleted(PingCompletedEventArgs e) 
        {
            if (PingCompleted != null) { 
                PingCompleted (this,e);
            }
        }
 
        void PingCompletedWaitCallback (object operationState) {
            OnPingCompleted((PingCompletedEventArgs)operationState); 
        } 

        public Ping () { 
            onPingCompletedDelegate = new SendOrPostCallback (PingCompletedWaitCallback);
        }

        //cancel pending async requests, close the handles 
        private void InternalDispose () {
            if (disposed) { 
                return; 
            }
 
            disposed = true;

            if (inAsyncCall) {
                SendAsyncCancel (); 
            }
 
            if (pingSocket != null) 
            {
                pingSocket.Close (); 
                pingSocket = null;
            }

            if (handlePingV4 != null) { 
                handlePingV4.Close ();
                handlePingV4 = null; 
            } 

            if (handlePingV6 != null) { 
                handlePingV6.Close ();
                handlePingV6 = null;
            }
 
            if (registeredWait != null)
            { 
                registeredWait.Unregister(null); 
            }
 
            if (pingEvent != null) {
                pingEvent.Close();
            }
 
            if (replyBuffer != null) {
                replyBuffer.Close(); 
            } 
        }
 

        /// 
        void IDisposable.Dispose () {
            InternalDispose (); 
        }
 
 
        //cancels pending async calls
        public void SendAsyncCancel() { 
            lock (this) {
                if (!inAsyncCall) {
                    return;
                } 

                cancelled = true; 
 
                if (handlePingV4 != null) {
                    handlePingV4.Close (); 
                    handlePingV4 = null;
                }

                if (handlePingV6 != null) { 
                    handlePingV6.Close ();
                    handlePingV6 = null; 
                } 

                if (pingSocket != null) { 
                    pingSocket.Close ();
                    pingSocket = null;
                }
            } 

            if (pingEvent != null) { 
                pingEvent.WaitOne(); 
            }
        } 


        //private callback invoked when icmpsendecho apis succeed
        private static void PingCallback (object state, bool signaled) 
        {
            Ping ping = (Ping)state; 
            PingCompletedEventArgs eventArgs = null; 
            bool cancelled = false;
            AsyncOperation asyncOp = null; 
            SendOrPostCallback onPingCompletedDelegate = null;

            try
            { 
                lock(ping) {
                    cancelled = ping.cancelled; 
                    asyncOp = ping.asyncOp; 
                    onPingCompletedDelegate = ping.onPingCompletedDelegate;
 
                    if (!cancelled) {
                        //parse reply buffer
                        SafeLocalFree buffer = ping.replyBuffer;
 
                        int error = 0;
                        if (ping.ipv6) { 
                            error = (int)UnsafeNetInfoNativeMethods.Icmp6ParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket); 
                        }
                        else { 
                            if (ComNetOS.IsPostWin2K) {
                                error = (int)UnsafeNetInfoNativeMethods.IcmpParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket);
                            }
                            else{ 
                                error = (int)UnsafeIcmpNativeMethods.IcmpParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket);
                            } 
                        } 

                        //looks like we get a lot of false failures here 
                        //if (error == 0){
                        //  error = Marshal.GetLastWin32Error();
                        //if (error != 0) {
                        //   throw new PingException(error);    looks like we get false failures here 
                        // if the status code isn't success.
                        //seems to be timing related 
                        // } 
                        //}
 
                        //marshals and constructs new reply
                        PingReply reply;

                        if (ping.ipv6) 
                        {
                            Icmp6EchoReply icmp6Reply = (Icmp6EchoReply)Marshal.PtrToStructure (buffer.DangerousGetHandle (), typeof(Icmp6EchoReply)); 
                            reply = new PingReply (icmp6Reply,buffer.DangerousGetHandle(),ping.sendSize); 
                        }
                        else { 
                            IcmpEchoReply icmpReply = (IcmpEchoReply)Marshal.PtrToStructure (buffer.DangerousGetHandle (), typeof(IcmpEchoReply));
                            reply = new PingReply (icmpReply);
                        }
 
                        eventArgs = new PingCompletedEventArgs (reply, null, false, asyncOp.UserSuppliedState);
                    } 
                } 
            }
            // in case of failure, create a failed event arg 
            catch (Exception e) {
                PingException pe = new PingException(SR.GetString(SR.net_ping), e);
                eventArgs = new PingCompletedEventArgs (null,pe, false, asyncOp.UserSuppliedState);
            } 
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                eventArgs = new PingCompletedEventArgs (null,pe, false, asyncOp.UserSuppliedState); 
            }
            finally { 
                ping.FreeUnmanagedStructures ();
                ping.inAsyncCall = false;
            }
 
            if (cancelled) {
                eventArgs = new PingCompletedEventArgs (null, null, true, asyncOp.UserSuppliedState); 
            } 
            asyncOp.PostOperationCompleted (onPingCompletedDelegate, eventArgs);
        } 


        //private callback invoked when downlevel send succeeds
        private static void PingSendCallback (IAsyncResult result) { 
            Ping ping = (Ping)(result.AsyncState);
            PingCompletedEventArgs eventArgs = null; 
 
            try {
                ping.pingSocket.EndSendTo (result); 
                PingReply reply = null;

                if (!ping.cancelled) {
                    // call blocking receive so we timeout normally. 
                    EndPoint endPoint = new IPEndPoint (0, 0);
 
                    int bytesReceived = 0; 

                    while (true) { 
                        bytesReceived = ping.pingSocket.ReceiveFrom (ping.downlevelReplyBuffer, ref endPoint);
                        if (CorrectPacket(ping.downlevelReplyBuffer,ping.packet)) {
                            break;
                        } 
                        if ((System.Environment.TickCount - ping.startTime) > ping.llTimeout) {
                            reply = new PingReply(IPStatus.TimedOut); 
                            break; 
                        }
                    } 
                    int rttTime = System.Environment.TickCount - ping.startTime; // stop timing
                    if (reply == null) {
                        reply = new PingReply (ping.downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, rttTime);
                    } 

                    //construct the reply 
                    eventArgs = new PingCompletedEventArgs (reply, null, false, ping.asyncOp.UserSuppliedState); 
                }
            } 

            // in case of failure, create a failed event arg
            catch (Exception e) {
                PingReply reply = null; 
                PingException pe = null;
                SocketException e2 = e as SocketException; 
 
                if (e2 != null) {
                    //timed out 
                    if (e2.ErrorCode == TimeoutErrorCode) {
                        reply = new PingReply(IPStatus.TimedOut);
                    }
                    //buffer is too big 
                    else if (e2.ErrorCode == PacketTooBigErrorCode) {
                        reply = new PingReply(IPStatus.PacketTooBig); 
                    } 
                }
                if (reply == null) { 
                    pe = new PingException(SR.GetString(SR.net_ping), e);
                }
                eventArgs = new PingCompletedEventArgs (reply, pe, false, ping.asyncOp.UserSuppliedState);
            } 
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                eventArgs = new PingCompletedEventArgs (null, pe, false, ping.asyncOp.UserSuppliedState); 
            }
 
            //otherwise, create real one
            try {
                if (ping.cancelled) {
                    eventArgs = new PingCompletedEventArgs (null, null, true, ping.asyncOp.UserSuppliedState); 
                }
                ping.asyncOp.PostOperationCompleted (ping.onPingCompletedDelegate, eventArgs); 
            } 
            finally {
                ping.inAsyncCall = false; 
            }
        }

        /*   private static void PingRecvCallback (IAsyncResult result) 
           {
               Ping ping = (Ping)result.AsyncState; 
               EndPoint endPoint = new IPEndPoint (0, 0); 
               int bytesReceived = ping.pingSocket.EndReceiveFrom (result, ref endPoint);
               PingReply reply = new PingReply (ping.downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, 0); 
               ping.inAsyncCall = false;
           }
   */
        public PingReply Send (string hostNameOrAddress) { 
            return Send (hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, null);
        } 
 

        public PingReply Send (string hostNameOrAddress, int timeout) { 
            return Send (hostNameOrAddress, timeout, DefaultSendBuffer, null);
        }

 
        public PingReply Send (IPAddress address) {
            return Send (address, DefaultTimeout, DefaultSendBuffer, null); 
        } 

        public PingReply Send (IPAddress address, int timeout) { 
            return Send (address, timeout, DefaultSendBuffer, null);
        }

        public PingReply Send (string hostNameOrAddress, int timeout, byte[] buffer) { 
            return Send (hostNameOrAddress, timeout, buffer, null);
        } 
 
        public PingReply Send (IPAddress address, int timeout, byte[] buffer) {
            return Send (address, timeout, buffer, null); 
        }

        public PingReply Send (string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) {
            if (ValidationHelper.IsBlankString(hostNameOrAddress)) { 
                throw new ArgumentNullException ("hostNameOrAddress");
            } 
 
            IPAddress address;
            try { 
                address = Dns.GetHostAddresses(hostNameOrAddress)[0];
            }
            catch (ArgumentException)
            { 
                throw;
            } 
            catch (Exception ex) { 
                throw new PingException(SR.GetString(SR.net_ping), ex);
            } 
            return Send(address, timeout, buffer, options);
        }

 
        public PingReply Send (IPAddress address, int timeout, byte[] buffer, PingOptions options) {
            if (buffer == null) { 
                throw new ArgumentNullException ("buffer"); 
            }
 
            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer");
            }
 
            if (timeout < 0) {
                throw new ArgumentOutOfRangeException ("timeout"); 
            } 

            if (address == null) { 
                throw new ArgumentNullException ("address");
            }

            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) 
            {
                throw new ArgumentException(SR.GetString(SR.net_invalid_ip_addr), "address"); 
            } 

            if (inAsyncCall == true) { 
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            }

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName);
            } 
 
            //
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission 
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that
            // always returns "localhost" or something.
            //
            IPAddress addressSnapshot; 
            if (address.AddressFamily == AddressFamily.InterNetwork)
            { 
                addressSnapshot = new IPAddress(address.GetAddressBytes()); 
            }
            else 
            {
                addressSnapshot = new IPAddress(address.GetAddressBytes(), address.ScopeId);
            }
 
            (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand();
 
            try { 
                return InternalSend (addressSnapshot, buffer, timeout, options, false);
            } 
            catch (Exception e) {
                throw new PingException(SR.GetString(SR.net_ping), e);
            }
            catch { 
                throw new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
            } 
        } 

 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, object userToken) {
            SendAsync (hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, userToken); 
        }
 
 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, object userToken) { 
            SendAsync (hostNameOrAddress, timeout, DefaultSendBuffer, userToken);
        }

 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, object userToken) { 
            SendAsync (address, DefaultTimeout, DefaultSendBuffer, userToken); 
        }
 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, int timeout, object userToken) {
            SendAsync (address, timeout, DefaultSendBuffer, userToken); 
        }
 
 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, byte[] buffer, object userToken) { 
            SendAsync (hostNameOrAddress, timeout, buffer, null, userToken);
        }

 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, int timeout, byte[] buffer, object userToken) { 
            SendAsync (address, timeout, buffer, null, userToken); 
        }
 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options, object userToken) {
            if (ValidationHelper.IsBlankString(hostNameOrAddress)) { 
                throw new ArgumentNullException ("hostNameOrAddress");
            } 
 
            if (buffer == null) {
                throw new ArgumentNullException ("buffer"); 
            }

            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer"); 
            }
 
            if (timeout < 0) { 
                throw new ArgumentOutOfRangeException ("timeout");
            } 

            if (inAsyncCall == true) {
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            } 

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName); 
            }
 
            IPAddress address;
            if (IPAddress.TryParse(hostNameOrAddress, out address))
            {
                SendAsync(address, timeout, buffer, options, userToken); 
                return;
            } 
 
            try {
                inAsyncCall = true; 
                asyncOp = AsyncOperationManager.CreateOperation (userToken);
                AsyncStateObject state = new AsyncStateObject(hostNameOrAddress,buffer,timeout,options,userToken);
                ThreadPool.QueueUserWorkItem(new WaitCallback(ContinueAsyncSend), state);
            } 
            catch (Exception e) {
                inAsyncCall = false; 
                throw new PingException(SR.GetString(SR.net_ping), e); 
            }
        } 



        [HostProtection(ExternalThreading=true)] 
        public void SendAsync (IPAddress address, int timeout, byte[] buffer, PingOptions options, object userToken) {
            if (buffer == null) { 
                throw new ArgumentNullException ("buffer"); 
            }
 
            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer");
            }
 
            if (timeout < 0) {
                throw new ArgumentOutOfRangeException ("timeout"); 
            } 

            if (address == null) { 
                throw new ArgumentNullException ("address");
            }

            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) 
            {
                throw new ArgumentException(SR.GetString(SR.net_invalid_ip_addr), "address"); 
            } 

            if (inAsyncCall == true) { 
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            }

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName);
            } 
 
            //
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission 
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that
            // always returns "localhost" or something.
            //
 
            IPAddress addressSnapshot;
            if (address.AddressFamily == AddressFamily.InterNetwork) 
            { 
                addressSnapshot = new IPAddress(address.GetAddressBytes());
            } 
            else
            {
                addressSnapshot = new IPAddress(address.GetAddressBytes(), address.ScopeId);
            } 

            (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand(); 
 
            try{
                inAsyncCall = true; 
                asyncOp = AsyncOperationManager.CreateOperation (userToken);
                InternalSend (addressSnapshot, buffer, timeout, options, true);
            }
 
            catch(Exception e){
                inAsyncCall = false; 
                throw new PingException(SR.GetString(SR.net_ping), e); 
            }
            catch { 
                inAsyncCall = false;
                throw new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
            }
        } 

 
        internal class AsyncStateObject{ 
            internal AsyncStateObject(string hostName, byte[] buffer, int timeout, PingOptions options, object userToken)
            { 
                this.hostName = hostName;
                this.buffer = buffer;
                this.timeout = timeout;
                this.options = options; 
                this.userToken = userToken;
            } 
 
            internal byte[] buffer;
            internal string hostName; 
            internal int timeout;
            internal PingOptions options;
            internal object userToken;
        } 

        private void ContinueAsyncSend(object state) { 
            // 
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that 
            // always returns "localhost" or something.
            //

            Debug.Assert(asyncOp != null, "Null AsyncOp?"); 

            AsyncStateObject stateObject = (AsyncStateObject) state; 
 
            try {
                IPAddress addressSnapshot = Dns.GetHostAddresses(stateObject.hostName)[0]; 

                (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand();
                InternalSend (addressSnapshot, stateObject.buffer, stateObject.timeout, stateObject.options, true);
            } 

            catch(Exception e){ 
                PingException pe = new PingException(SR.GetString(SR.net_ping), e); 
                PingCompletedEventArgs eventArgs = new PingCompletedEventArgs (null, pe, false, asyncOp.UserSuppliedState);
                inAsyncCall = false; 
                asyncOp.PostOperationCompleted(onPingCompletedDelegate, eventArgs);
            }
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                PingCompletedEventArgs eventArgs = new PingCompletedEventArgs (null, pe, false, asyncOp.UserSuppliedState);
                inAsyncCall = false; 
                asyncOp.PostOperationCompleted(onPingCompletedDelegate, eventArgs); 
            }
        } 



        // internal method responsible for sending echo request on win2k and higher 

        private PingReply InternalSend (IPAddress address, byte[] buffer, int timeout, PingOptions options, bool async) { 
            inAsyncCall = async; 
            cancelled = false;
 
            //for  llTimeout) { 
                        return new PingReply(IPStatus.TimedOut);
                    }
                }
 
                //construct and return the reply
                rttTime = System.Environment.TickCount - startTime; // stop timing 
                return new PingReply (downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, rttTime); 
            }
 
            catch (SocketException e)
            {
                //timed out, [....] is implied
                if (e.ErrorCode == TimeoutErrorCode) { 
                    return new PingReply(IPStatus.TimedOut);
                } 
                //buffer too big 
                else if (e.ErrorCode == PacketTooBigErrorCode) {
                    PingReply reply = new PingReply(IPStatus.PacketTooBig); 
                    if (!async) {
                        return reply;
                    }
                    PingCompletedEventArgs eventArgs = new PingCompletedEventArgs(reply,null, false, asyncOp.UserSuppliedState); 
                    asyncOp.PostOperationCompleted (onPingCompletedDelegate, eventArgs);
                    return null; 
 
                }
                else 
                    throw e;
            }
        }
        // copies sendbuffer into unmanaged memory for async icmpsendecho apis 
        private unsafe void SetUnmanagedStructures (byte[] buffer) {
            requestBuffer = SafeLocalFree.LocalAlloc(buffer.Length); 
            byte* dst = (byte*)requestBuffer.DangerousGetHandle(); 
            for (int i = 0; i < buffer.Length; ++i)
            { 
                dst[i] = buffer[i];
            }
        }
 
        // release the unmanaged memory after ping completion
        void FreeUnmanagedStructures () { 
            if (requestBuffer != null) { 
                requestBuffer.Close();
                requestBuffer = null; 
            }
        }

 
        // creates a default send buffer if a buffer wasn't specified.  This follows the
        // ping.exe model 
        private byte[] DefaultSendBuffer { 
            get {
                if (defaultSendBuffer == null) { 
                    defaultSendBuffer = new byte[DefaultSendBufferSize];
                    for (int i=0;i> 16) + (total & 0xffff); 
            total += (total >> 16); 
            return(~total);
        } 

        //converts the structure into a byte array
        internal byte[] GetBytes() {
            byte[] bytes = new byte[buffer.Length + 8]; 

            byte[] b_cksum = BitConverter.GetBytes (checkSum); 
            byte[] b_id = BitConverter.GetBytes (Identifier); 
            byte[] b_seq = BitConverter.GetBytes (sequenceNumber);
            bytes[0] = type ; 
            bytes[1] = subCode ;
            Array.Copy ( b_cksum , 0 , bytes , 2 , 2 ) ;
            Array.Copy ( b_id , 0 , bytes , 4 , 2 ) ;
            Array.Copy (b_seq, 0, bytes, 6, 2); 
            Array.Copy ( buffer , 0 , bytes , 8 , buffer . Length ) ;
            return bytes; 
        } 
    } // class IcmpPacket
} 



// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
 
namespace System.Net.NetworkInformation {

    using System.Net;
    using System.Net.Sockets; 
    using System;
    using System.Runtime.InteropServices; 
    using System.Threading; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Security.Permissions;

    public delegate void PingCompletedEventHandler (object sender, PingCompletedEventArgs e);
 

    public class PingCompletedEventArgs: System.ComponentModel.AsyncCompletedEventArgs { 
        PingReply reply; 

        internal PingCompletedEventArgs (PingReply reply, Exception error, bool cancelled, object userToken):base(error,cancelled,userToken) { 
            this.reply = reply;
        }
        public PingReply Reply{get {return reply;}}
    } 

    public class Ping:Component,IDisposable 
    { 
        const int MaxUdpPacket = 0xFFFF + 256; // Marshal.SizeOf(typeof(Icmp6EchoReply)) * 2 + ip header info;
        const int MaxBufferSize = 65500; //artificial constraint due to win32 api limitations. 
        const int DefaultTimeout = 5000; //5 seconds same as ping.exe
        const int DefaultSendBufferSize = 32;  //same as ping.exe

        byte[] defaultSendBuffer = null; 
        bool ipv6 = false;
        bool inAsyncCall = false; 
        bool cancelled = false; 
        bool disposed = false;
 
        //used for icmpsendecho apis
        internal ManualResetEvent pingEvent = null;
        private RegisteredWaitHandle registeredWait = null;
        SafeLocalFree requestBuffer = null; 
        SafeLocalFree replyBuffer = null;
        int sendSize = 0;  //----s, but needed to determine what reply size is for ipv6 in callback 
 
        //used for downlevel calls
        const int TimeoutErrorCode = 0x274c; 
        const int PacketTooBigErrorCode = 0x2738;
        Socket pingSocket = null;
        byte[] downlevelReplyBuffer = null;
        SafeCloseIcmpHandle handlePingV4 = null; 
        SafeCloseIcmpHandle handlePingV6 = null;
        int startTime = 0; 
        IcmpPacket packet = null; 
        int llTimeout = 0;
 
        //new async event support
        AsyncOperation asyncOp = null;
        SendOrPostCallback onPingCompletedDelegate;
        public event PingCompletedEventHandler PingCompleted; 

 
        protected void OnPingCompleted(PingCompletedEventArgs e) 
        {
            if (PingCompleted != null) { 
                PingCompleted (this,e);
            }
        }
 
        void PingCompletedWaitCallback (object operationState) {
            OnPingCompleted((PingCompletedEventArgs)operationState); 
        } 

        public Ping () { 
            onPingCompletedDelegate = new SendOrPostCallback (PingCompletedWaitCallback);
        }

        //cancel pending async requests, close the handles 
        private void InternalDispose () {
            if (disposed) { 
                return; 
            }
 
            disposed = true;

            if (inAsyncCall) {
                SendAsyncCancel (); 
            }
 
            if (pingSocket != null) 
            {
                pingSocket.Close (); 
                pingSocket = null;
            }

            if (handlePingV4 != null) { 
                handlePingV4.Close ();
                handlePingV4 = null; 
            } 

            if (handlePingV6 != null) { 
                handlePingV6.Close ();
                handlePingV6 = null;
            }
 
            if (registeredWait != null)
            { 
                registeredWait.Unregister(null); 
            }
 
            if (pingEvent != null) {
                pingEvent.Close();
            }
 
            if (replyBuffer != null) {
                replyBuffer.Close(); 
            } 
        }
 

        /// 
        void IDisposable.Dispose () {
            InternalDispose (); 
        }
 
 
        //cancels pending async calls
        public void SendAsyncCancel() { 
            lock (this) {
                if (!inAsyncCall) {
                    return;
                } 

                cancelled = true; 
 
                if (handlePingV4 != null) {
                    handlePingV4.Close (); 
                    handlePingV4 = null;
                }

                if (handlePingV6 != null) { 
                    handlePingV6.Close ();
                    handlePingV6 = null; 
                } 

                if (pingSocket != null) { 
                    pingSocket.Close ();
                    pingSocket = null;
                }
            } 

            if (pingEvent != null) { 
                pingEvent.WaitOne(); 
            }
        } 


        //private callback invoked when icmpsendecho apis succeed
        private static void PingCallback (object state, bool signaled) 
        {
            Ping ping = (Ping)state; 
            PingCompletedEventArgs eventArgs = null; 
            bool cancelled = false;
            AsyncOperation asyncOp = null; 
            SendOrPostCallback onPingCompletedDelegate = null;

            try
            { 
                lock(ping) {
                    cancelled = ping.cancelled; 
                    asyncOp = ping.asyncOp; 
                    onPingCompletedDelegate = ping.onPingCompletedDelegate;
 
                    if (!cancelled) {
                        //parse reply buffer
                        SafeLocalFree buffer = ping.replyBuffer;
 
                        int error = 0;
                        if (ping.ipv6) { 
                            error = (int)UnsafeNetInfoNativeMethods.Icmp6ParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket); 
                        }
                        else { 
                            if (ComNetOS.IsPostWin2K) {
                                error = (int)UnsafeNetInfoNativeMethods.IcmpParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket);
                            }
                            else{ 
                                error = (int)UnsafeIcmpNativeMethods.IcmpParseReplies (buffer.DangerousGetHandle (), (uint)MaxUdpPacket);
                            } 
                        } 

                        //looks like we get a lot of false failures here 
                        //if (error == 0){
                        //  error = Marshal.GetLastWin32Error();
                        //if (error != 0) {
                        //   throw new PingException(error);    looks like we get false failures here 
                        // if the status code isn't success.
                        //seems to be timing related 
                        // } 
                        //}
 
                        //marshals and constructs new reply
                        PingReply reply;

                        if (ping.ipv6) 
                        {
                            Icmp6EchoReply icmp6Reply = (Icmp6EchoReply)Marshal.PtrToStructure (buffer.DangerousGetHandle (), typeof(Icmp6EchoReply)); 
                            reply = new PingReply (icmp6Reply,buffer.DangerousGetHandle(),ping.sendSize); 
                        }
                        else { 
                            IcmpEchoReply icmpReply = (IcmpEchoReply)Marshal.PtrToStructure (buffer.DangerousGetHandle (), typeof(IcmpEchoReply));
                            reply = new PingReply (icmpReply);
                        }
 
                        eventArgs = new PingCompletedEventArgs (reply, null, false, asyncOp.UserSuppliedState);
                    } 
                } 
            }
            // in case of failure, create a failed event arg 
            catch (Exception e) {
                PingException pe = new PingException(SR.GetString(SR.net_ping), e);
                eventArgs = new PingCompletedEventArgs (null,pe, false, asyncOp.UserSuppliedState);
            } 
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                eventArgs = new PingCompletedEventArgs (null,pe, false, asyncOp.UserSuppliedState); 
            }
            finally { 
                ping.FreeUnmanagedStructures ();
                ping.inAsyncCall = false;
            }
 
            if (cancelled) {
                eventArgs = new PingCompletedEventArgs (null, null, true, asyncOp.UserSuppliedState); 
            } 
            asyncOp.PostOperationCompleted (onPingCompletedDelegate, eventArgs);
        } 


        //private callback invoked when downlevel send succeeds
        private static void PingSendCallback (IAsyncResult result) { 
            Ping ping = (Ping)(result.AsyncState);
            PingCompletedEventArgs eventArgs = null; 
 
            try {
                ping.pingSocket.EndSendTo (result); 
                PingReply reply = null;

                if (!ping.cancelled) {
                    // call blocking receive so we timeout normally. 
                    EndPoint endPoint = new IPEndPoint (0, 0);
 
                    int bytesReceived = 0; 

                    while (true) { 
                        bytesReceived = ping.pingSocket.ReceiveFrom (ping.downlevelReplyBuffer, ref endPoint);
                        if (CorrectPacket(ping.downlevelReplyBuffer,ping.packet)) {
                            break;
                        } 
                        if ((System.Environment.TickCount - ping.startTime) > ping.llTimeout) {
                            reply = new PingReply(IPStatus.TimedOut); 
                            break; 
                        }
                    } 
                    int rttTime = System.Environment.TickCount - ping.startTime; // stop timing
                    if (reply == null) {
                        reply = new PingReply (ping.downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, rttTime);
                    } 

                    //construct the reply 
                    eventArgs = new PingCompletedEventArgs (reply, null, false, ping.asyncOp.UserSuppliedState); 
                }
            } 

            // in case of failure, create a failed event arg
            catch (Exception e) {
                PingReply reply = null; 
                PingException pe = null;
                SocketException e2 = e as SocketException; 
 
                if (e2 != null) {
                    //timed out 
                    if (e2.ErrorCode == TimeoutErrorCode) {
                        reply = new PingReply(IPStatus.TimedOut);
                    }
                    //buffer is too big 
                    else if (e2.ErrorCode == PacketTooBigErrorCode) {
                        reply = new PingReply(IPStatus.PacketTooBig); 
                    } 
                }
                if (reply == null) { 
                    pe = new PingException(SR.GetString(SR.net_ping), e);
                }
                eventArgs = new PingCompletedEventArgs (reply, pe, false, ping.asyncOp.UserSuppliedState);
            } 
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                eventArgs = new PingCompletedEventArgs (null, pe, false, ping.asyncOp.UserSuppliedState); 
            }
 
            //otherwise, create real one
            try {
                if (ping.cancelled) {
                    eventArgs = new PingCompletedEventArgs (null, null, true, ping.asyncOp.UserSuppliedState); 
                }
                ping.asyncOp.PostOperationCompleted (ping.onPingCompletedDelegate, eventArgs); 
            } 
            finally {
                ping.inAsyncCall = false; 
            }
        }

        /*   private static void PingRecvCallback (IAsyncResult result) 
           {
               Ping ping = (Ping)result.AsyncState; 
               EndPoint endPoint = new IPEndPoint (0, 0); 
               int bytesReceived = ping.pingSocket.EndReceiveFrom (result, ref endPoint);
               PingReply reply = new PingReply (ping.downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, 0); 
               ping.inAsyncCall = false;
           }
   */
        public PingReply Send (string hostNameOrAddress) { 
            return Send (hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, null);
        } 
 

        public PingReply Send (string hostNameOrAddress, int timeout) { 
            return Send (hostNameOrAddress, timeout, DefaultSendBuffer, null);
        }

 
        public PingReply Send (IPAddress address) {
            return Send (address, DefaultTimeout, DefaultSendBuffer, null); 
        } 

        public PingReply Send (IPAddress address, int timeout) { 
            return Send (address, timeout, DefaultSendBuffer, null);
        }

        public PingReply Send (string hostNameOrAddress, int timeout, byte[] buffer) { 
            return Send (hostNameOrAddress, timeout, buffer, null);
        } 
 
        public PingReply Send (IPAddress address, int timeout, byte[] buffer) {
            return Send (address, timeout, buffer, null); 
        }

        public PingReply Send (string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) {
            if (ValidationHelper.IsBlankString(hostNameOrAddress)) { 
                throw new ArgumentNullException ("hostNameOrAddress");
            } 
 
            IPAddress address;
            try { 
                address = Dns.GetHostAddresses(hostNameOrAddress)[0];
            }
            catch (ArgumentException)
            { 
                throw;
            } 
            catch (Exception ex) { 
                throw new PingException(SR.GetString(SR.net_ping), ex);
            } 
            return Send(address, timeout, buffer, options);
        }

 
        public PingReply Send (IPAddress address, int timeout, byte[] buffer, PingOptions options) {
            if (buffer == null) { 
                throw new ArgumentNullException ("buffer"); 
            }
 
            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer");
            }
 
            if (timeout < 0) {
                throw new ArgumentOutOfRangeException ("timeout"); 
            } 

            if (address == null) { 
                throw new ArgumentNullException ("address");
            }

            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) 
            {
                throw new ArgumentException(SR.GetString(SR.net_invalid_ip_addr), "address"); 
            } 

            if (inAsyncCall == true) { 
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            }

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName);
            } 
 
            //
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission 
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that
            // always returns "localhost" or something.
            //
            IPAddress addressSnapshot; 
            if (address.AddressFamily == AddressFamily.InterNetwork)
            { 
                addressSnapshot = new IPAddress(address.GetAddressBytes()); 
            }
            else 
            {
                addressSnapshot = new IPAddress(address.GetAddressBytes(), address.ScopeId);
            }
 
            (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand();
 
            try { 
                return InternalSend (addressSnapshot, buffer, timeout, options, false);
            } 
            catch (Exception e) {
                throw new PingException(SR.GetString(SR.net_ping), e);
            }
            catch { 
                throw new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
            } 
        } 

 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, object userToken) {
            SendAsync (hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, userToken); 
        }
 
 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, object userToken) { 
            SendAsync (hostNameOrAddress, timeout, DefaultSendBuffer, userToken);
        }

 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, object userToken) { 
            SendAsync (address, DefaultTimeout, DefaultSendBuffer, userToken); 
        }
 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, int timeout, object userToken) {
            SendAsync (address, timeout, DefaultSendBuffer, userToken); 
        }
 
 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, byte[] buffer, object userToken) { 
            SendAsync (hostNameOrAddress, timeout, buffer, null, userToken);
        }

 
        [HostProtection(ExternalThreading=true)]
        public void SendAsync (IPAddress address, int timeout, byte[] buffer, object userToken) { 
            SendAsync (address, timeout, buffer, null, userToken); 
        }
 

        [HostProtection(ExternalThreading=true)]
        public void SendAsync (string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options, object userToken) {
            if (ValidationHelper.IsBlankString(hostNameOrAddress)) { 
                throw new ArgumentNullException ("hostNameOrAddress");
            } 
 
            if (buffer == null) {
                throw new ArgumentNullException ("buffer"); 
            }

            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer"); 
            }
 
            if (timeout < 0) { 
                throw new ArgumentOutOfRangeException ("timeout");
            } 

            if (inAsyncCall == true) {
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            } 

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName); 
            }
 
            IPAddress address;
            if (IPAddress.TryParse(hostNameOrAddress, out address))
            {
                SendAsync(address, timeout, buffer, options, userToken); 
                return;
            } 
 
            try {
                inAsyncCall = true; 
                asyncOp = AsyncOperationManager.CreateOperation (userToken);
                AsyncStateObject state = new AsyncStateObject(hostNameOrAddress,buffer,timeout,options,userToken);
                ThreadPool.QueueUserWorkItem(new WaitCallback(ContinueAsyncSend), state);
            } 
            catch (Exception e) {
                inAsyncCall = false; 
                throw new PingException(SR.GetString(SR.net_ping), e); 
            }
        } 



        [HostProtection(ExternalThreading=true)] 
        public void SendAsync (IPAddress address, int timeout, byte[] buffer, PingOptions options, object userToken) {
            if (buffer == null) { 
                throw new ArgumentNullException ("buffer"); 
            }
 
            if (buffer.Length > MaxBufferSize ) {
                throw new ArgumentException(SR.GetString(SR.net_invalidPingBufferSize), "buffer");
            }
 
            if (timeout < 0) {
                throw new ArgumentOutOfRangeException ("timeout"); 
            } 

            if (address == null) { 
                throw new ArgumentNullException ("address");
            }

            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) 
            {
                throw new ArgumentException(SR.GetString(SR.net_invalid_ip_addr), "address"); 
            } 

            if (inAsyncCall == true) { 
                throw new InvalidOperationException(SR.GetString(SR.net_inasync));
            }

            if (disposed) { 
                throw new ObjectDisposedException (this.GetType ().FullName);
            } 
 
            //
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission 
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that
            // always returns "localhost" or something.
            //
 
            IPAddress addressSnapshot;
            if (address.AddressFamily == AddressFamily.InterNetwork) 
            { 
                addressSnapshot = new IPAddress(address.GetAddressBytes());
            } 
            else
            {
                addressSnapshot = new IPAddress(address.GetAddressBytes(), address.ScopeId);
            } 

            (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand(); 
 
            try{
                inAsyncCall = true; 
                asyncOp = AsyncOperationManager.CreateOperation (userToken);
                InternalSend (addressSnapshot, buffer, timeout, options, true);
            }
 
            catch(Exception e){
                inAsyncCall = false; 
                throw new PingException(SR.GetString(SR.net_ping), e); 
            }
            catch { 
                inAsyncCall = false;
                throw new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
            }
        } 

 
        internal class AsyncStateObject{ 
            internal AsyncStateObject(string hostName, byte[] buffer, int timeout, PingOptions options, object userToken)
            { 
                this.hostName = hostName;
                this.buffer = buffer;
                this.timeout = timeout;
                this.options = options; 
                this.userToken = userToken;
            } 
 
            internal byte[] buffer;
            internal string hostName; 
            internal int timeout;
            internal PingOptions options;
            internal object userToken;
        } 

        private void ContinueAsyncSend(object state) { 
            // 
            // FxCop: need to snapshot the address here, so we're sure that it's not changed between the permission
            // and the operation, and to be sure that IPAddress.ToString() is called and not some override that 
            // always returns "localhost" or something.
            //

            Debug.Assert(asyncOp != null, "Null AsyncOp?"); 

            AsyncStateObject stateObject = (AsyncStateObject) state; 
 
            try {
                IPAddress addressSnapshot = Dns.GetHostAddresses(stateObject.hostName)[0]; 

                (new NetworkInformationPermission(NetworkInformationAccess.Ping)).Demand();
                InternalSend (addressSnapshot, stateObject.buffer, stateObject.timeout, stateObject.options, true);
            } 

            catch(Exception e){ 
                PingException pe = new PingException(SR.GetString(SR.net_ping), e); 
                PingCompletedEventArgs eventArgs = new PingCompletedEventArgs (null, pe, false, asyncOp.UserSuppliedState);
                inAsyncCall = false; 
                asyncOp.PostOperationCompleted(onPingCompletedDelegate, eventArgs);
            }
            catch {
                PingException pe = new PingException(SR.GetString(SR.net_ping), new Exception(SR.GetString(SR.net_nonClsCompliantException))); 
                PingCompletedEventArgs eventArgs = new PingCompletedEventArgs (null, pe, false, asyncOp.UserSuppliedState);
                inAsyncCall = false; 
                asyncOp.PostOperationCompleted(onPingCompletedDelegate, eventArgs); 
            }
        } 



        // internal method responsible for sending echo request on win2k and higher 

        private PingReply InternalSend (IPAddress address, byte[] buffer, int timeout, PingOptions options, bool async) { 
            inAsyncCall = async; 
            cancelled = false;
 
            //for  llTimeout) { 
                        return new PingReply(IPStatus.TimedOut);
                    }
                }
 
                //construct and return the reply
                rttTime = System.Environment.TickCount - startTime; // stop timing 
                return new PingReply (downlevelReplyBuffer, bytesReceived, ((IPEndPoint)endPoint).Address, rttTime); 
            }
 
            catch (SocketException e)
            {
                //timed out, [....] is implied
                if (e.ErrorCode == TimeoutErrorCode) { 
                    return new PingReply(IPStatus.TimedOut);
                } 
                //buffer too big 
                else if (e.ErrorCode == PacketTooBigErrorCode) {
                    PingReply reply = new PingReply(IPStatus.PacketTooBig); 
                    if (!async) {
                        return reply;
                    }
                    PingCompletedEventArgs eventArgs = new PingCompletedEventArgs(reply,null, false, asyncOp.UserSuppliedState); 
                    asyncOp.PostOperationCompleted (onPingCompletedDelegate, eventArgs);
                    return null; 
 
                }
                else 
                    throw e;
            }
        }
        // copies sendbuffer into unmanaged memory for async icmpsendecho apis 
        private unsafe void SetUnmanagedStructures (byte[] buffer) {
            requestBuffer = SafeLocalFree.LocalAlloc(buffer.Length); 
            byte* dst = (byte*)requestBuffer.DangerousGetHandle(); 
            for (int i = 0; i < buffer.Length; ++i)
            { 
                dst[i] = buffer[i];
            }
        }
 
        // release the unmanaged memory after ping completion
        void FreeUnmanagedStructures () { 
            if (requestBuffer != null) { 
                requestBuffer.Close();
                requestBuffer = null; 
            }
        }

 
        // creates a default send buffer if a buffer wasn't specified.  This follows the
        // ping.exe model 
        private byte[] DefaultSendBuffer { 
            get {
                if (defaultSendBuffer == null) { 
                    defaultSendBuffer = new byte[DefaultSendBufferSize];
                    for (int i=0;i> 16) + (total & 0xffff); 
            total += (total >> 16); 
            return(~total);
        } 

        //converts the structure into a byte array
        internal byte[] GetBytes() {
            byte[] bytes = new byte[buffer.Length + 8]; 

            byte[] b_cksum = BitConverter.GetBytes (checkSum); 
            byte[] b_id = BitConverter.GetBytes (Identifier); 
            byte[] b_seq = BitConverter.GetBytes (sequenceNumber);
            bytes[0] = type ; 
            bytes[1] = subCode ;
            Array.Copy ( b_cksum , 0 , bytes , 2 , 2 ) ;
            Array.Copy ( b_id , 0 , bytes , 4 , 2 ) ;
            Array.Copy (b_seq, 0, bytes, 6, 2); 
            Array.Copy ( buffer , 0 , bytes , 8 , buffer . Length ) ;
            return bytes; 
        } 
    } // class IcmpPacket
} 



// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK