ping.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / NetworkInformation / ping.cs / 1305376 / 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 
    { 
        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 cancelled = false; 
        bool disposed = false; 
        object lockObject = new object();
 
        //used for icmpsendecho apis
        internal ManualResetEvent pingEvent = null;
        private RegisteredWaitHandle registeredWait = null;
        SafeLocalFree requestBuffer = null; 
        SafeLocalFree replyBuffer = null;
        int sendSize = 0;  //needed to determine what reply size is for ipv6 in callback 
 
        SafeCloseIcmpHandle handlePingV4 = null;
        SafeCloseIcmpHandle handlePingV6 = null; 

        //new async event support
        AsyncOperation asyncOp = null;
        SendOrPostCallback onPingCompletedDelegate; 
        public event PingCompletedEventHandler PingCompleted;
 
        // For blocking in SendAsyncCancel() 
        ManualResetEvent asyncFinished = null;
        bool InAsyncCall { 
            get {
                if (asyncFinished == null)
                    return false;
                // Never blocks, just checks if a thread would block. 
                return !asyncFinished.WaitOne(0);
            } 
            set { 
                if (asyncFinished == null)
                    asyncFinished = new ManualResetEvent(!value); 
                else if (value)
                    asyncFinished.Reset(); // Block
                else
                    asyncFinished.Set(); // Clear 
            }
        } 
 
        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 (handlePingV4 != null) {
                handlePingV4.Close (); 
                handlePingV4 = null;
            }

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

            UnregisterWaitHandle(); 

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

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

        private void UnregisterWaitHandle() 
        {
            lock (lockObject)
            {
                if (registeredWait != null) 
                {
                    registeredWait.Unregister(null); 
                    // If Unregister returns false, it is sufficient to nullify registeredWait 
                    // and let its own finilizer clean up later.
                    registeredWait = null; 
                }
            }
        }
 
        protected override void Dispose(Boolean disposing)
        { 
            if (disposing) { // Only on explicit dispose.  Otherwise, the GC can cleanup everything else. 
                InternalDispose();
            } 
            base.Dispose(disposing);
        }

        //cancels pending async calls 
        public void SendAsyncCancel() {
            lock (lockObject) { 
                if (!InAsyncCall) { 
                    return;
                } 

                cancelled = true;
            }
            // Because there is no actual native cancel, 
            // we just have to block until the current operation is completed.
            asyncFinished.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.lockObject) {
                    cancelled = ping.cancelled; 
                    asyncOp = ping.asyncOp;
                    onPingCompletedDelegate = ping.onPingCompletedDelegate; 
 
                    if (!cancelled) {
                        //parse reply buffer 
                        SafeLocalFree buffer = ping.replyBuffer;

                        Debug.Assert(ComNetOS.IsPostWin2K,"Requires XP or higher, Win2k IcmpParseReply code removed");
 
                        // IcmpParseReplies in XP does -required- post prosseing for IPv4 ping replies;
                        // No Icmp6ParseReplies calls are needed for post processing 
                        // because they would only set the Icmp6EchoReply.Status value into lastWin32Error, 
                        // which we will retrieve from marshalling anyways.
                        if (!ping.ipv6 && !ComNetOS.IsVista) { // XP IPv4 
                            UnsafeNetInfoNativeMethods.IcmpParseReplies(buffer.DangerousGetHandle(), (uint)MaxUdpPacket);
                        }

                        //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); 
                    } else { //cancelled
                        eventArgs = new PingCompletedEventArgs (null, null, true, 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); 
            }
            finally { 
                ping.FreeUnmanagedStructures ();
                ping.UnregisterWaitHandle();
                ping.InAsyncCall = false;
            } 

            asyncOp.PostOperationCompleted (onPingCompletedDelegate, eventArgs); 
        } 

        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; 
            if (!IPAddress.TryParse(hostNameOrAddress, out 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");
            } 

            TestIsIpSupported(address); // Address family is installed?

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

            if (InAsyncCall) { 
                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);
            }
        } 

 
 
        [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) {
                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; 
                cancelled = false; 
                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");
            } 

            TestIsIpSupported(address); // Address family is installed?

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

            if (InAsyncCall) { 
                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; 
                cancelled = false;
                asyncOp = AsyncOperationManager.CreateOperation (userToken);
                InternalSend (addressSnapshot, buffer, timeout, options, true);
            } 

            catch(Exception e){ 
                InAsyncCall = false; 
                throw new PingException(SR.GetString(SR.net_ping), e);
            } 
        }


        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); 
            }
        } 



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

        private PingReply InternalSend (IPAddress address, byte[] buffer, int timeout, PingOptions options, bool async) { 
 
            Debug.Assert(ComNetOS.IsPostWin2K, "Requires XP or higher");
 
            ipv6 =  (address.AddressFamily == AddressFamily.InterNetworkV6)?true:false;
            sendSize = buffer.Length;

            //get and cache correct handle 
            if (!ipv6 && handlePingV4 == null) {
                handlePingV4 = UnsafeNetInfoNativeMethods.IcmpCreateFile (); 
                if (handlePingV4.IsInvalid) { 
                    handlePingV4 = null;
                    throw new Win32Exception(); // Gets last error 
                }
            }
            else if (ipv6 && handlePingV6 == null) {
                handlePingV6 = UnsafeNetInfoNativeMethods.Icmp6CreateFile(); 
                if (handlePingV6.IsInvalid) {
                    handlePingV6 = null; 
                    throw new Win32Exception(); // Gets last error 
                }
            } 


            //setup the options
            IPOptions ipOptions = new IPOptions (options); 

            //setup the reply buffer 
            if (replyBuffer == null) { 
                replyBuffer = SafeLocalFree.LocalAlloc (MaxUdpPacket);
            } 

            //queue the event
            int error;
 
            try
            { 
                if (async) { 
                    if (pingEvent == null)
                        pingEvent = new ManualResetEvent (false); 
                    else
                        pingEvent.Reset();

                    registeredWait = ThreadPool.RegisterWaitForSingleObject (pingEvent, new WaitOrTimerCallback (PingCallback), this, -1, true); 
                }
 
                //Copy user dfata into the native world 
                SetUnmanagedStructures (buffer);
 
                if (!ipv6) {
                    if (async) {
                        error = (int)UnsafeNetInfoNativeMethods.IcmpSendEcho2 (handlePingV4, pingEvent.SafeWaitHandle, IntPtr.Zero, IntPtr.Zero, (uint)address.m_Address, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout);
                    } 
                    else{
                        error = (int)UnsafeNetInfoNativeMethods.IcmpSendEcho2 (handlePingV4, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, (uint)address.m_Address, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout); 
                    } 
                }
                else { 
                    IPEndPoint ep = new IPEndPoint (address, 0);
                    SocketAddress remoteAddr = ep.Serialize ();
                    byte[] sourceAddr = new byte[28];
                    if(async){ 
                        error = (int)UnsafeNetInfoNativeMethods.Icmp6SendEcho2 (handlePingV6, pingEvent.SafeWaitHandle, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.m_Buffer, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout);
                    } 
                    else{ 
                        error = (int)UnsafeNetInfoNativeMethods.Icmp6SendEcho2 (handlePingV6, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.m_Buffer, requestBuffer, (ushort)buffer.Length, ref ipOptions, replyBuffer, MaxUdpPacket, (uint)timeout);
                    } 
                }
            }
            catch
            { 
                UnregisterWaitHandle();
                throw; 
            } 

            //need this if something is bogus. 
            if (error == 0) {
                error = (int)Marshal.GetLastWin32Error();

                // Only skip Async IO Pending error value 
                if (async && error == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
                    return null; // Expected async return value 
 
                // Cleanup
                FreeUnmanagedStructures(); 
                UnregisterWaitHandle();

                if (async // No IPStatus async errors
                    || error < (int)IPStatus.DestinationNetworkUnreachable // Min 
                    || error > (int)IPStatus.DestinationScopeMismatch) // Max // Out of IPStatus range
                    throw new Win32Exception(error); 
 
                return new PingReply((IPStatus)error); // Synchronous IPStatus errors
            } 

            if (async) {
                return null;
            } 

            FreeUnmanagedStructures (); 
 
            //return the reply
            PingReply reply; 
            if (ipv6) {
                Icmp6EchoReply icmp6Reply = (Icmp6EchoReply)Marshal.PtrToStructure(replyBuffer.DangerousGetHandle(), typeof(Icmp6EchoReply));
                reply = new PingReply(icmp6Reply, replyBuffer.DangerousGetHandle(), sendSize);
            } 
            else {
                IcmpEchoReply icmpReply = (IcmpEchoReply)Marshal.PtrToStructure(replyBuffer.DangerousGetHandle(), typeof(IcmpEchoReply)); 
                reply = new PingReply(icmpReply); 
            }
 
            // IcmpEchoReply still has an unsafe IntPtr reference into replybuffer
            // and replybuffer was being freed prematurely by the GC, causing AccessViolationExceptions.
            GC.KeepAlive(replyBuffer);
 
            return reply;
        } 
 
        // Tests if the current machine supports the given ip protocol family
        private void TestIsIpSupported(IPAddress ip) { 
            // Catches if IPv4 has been uninstalled on Vista+
            if (ip.AddressFamily == AddressFamily.InterNetwork && !Socket.OSSupportsIPv4)
                throw new NotSupportedException(SR.GetString(SR.net_ipv4_not_installed));
            // Catches if IPv6 is not installed on XP 
            else if ((ip.AddressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6))
                throw new NotSupportedException(SR.GetString(SR.net_ipv6_not_installed)); 
        } 

        // 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

                        

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