UdpSocket.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 / cdf / src / NetFx40 / System.ServiceModel.Discovery / System / ServiceModel / Channels / UdpSocket.cs / 1305376 / UdpSocket.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System; 
    using System.Net; 
    using System.Net.Sockets;
    using System.Runtime; 
    using System.Threading;
#if DEBUG
    using System.Diagnostics;
#endif 
    using System.ServiceModel.Discovery;
 
    class UdpSocket 
    {
        int openCount; 
        int timeToLive;
        int pendingReceiveCount;
        Socket socket;
#if DEBUG 
        StackTrace disposeStack;
#endif 
 
        public UdpSocket(Socket socket, int interfaceIndex)
        { 
            Fx.Assert(socket != null, "Socket argument cannot be null");

            this.openCount = 0;
            this.pendingReceiveCount = 0; 

            this.ThisLock = new object(); 
 
            this.socket = socket;
            this.InterfaceIndex = interfaceIndex; 
            this.timeToLive = socket.Ttl;
        }

        enum TransferDirection : byte 
        {
            Send, 
            Receive, 
        }
 
        public AddressFamily AddressFamily
        {
            get
            { 
                return this.socket.AddressFamily;
            } 
        } 

        public int PendingReceiveCount 
        {
            get
            {
                return this.pendingReceiveCount; 
            }
        } 
 
        //value of UdpConstants.Defaults.InterfaceIndex (-1) if not a multicast socket
        internal int InterfaceIndex 
        {
            get;
            private set;
        } 

        internal bool IsDisposed 
        { get { return this.openCount < 0; } } 

        internal object ThisLock 
        {
            get;
            private set;
        } 

        //must be called under a lock in receive loop 
        public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, ref EndPoint remoteEndPoint, AsyncCallback callback, object state) 
        {
            UdpUtility.ValidateBufferBounds(buffer, offset, size); 

            ThrowIfNotOpen();

            bool success = false; 
            IAsyncResult asyncResult = null;
            try 
            { 
                this.pendingReceiveCount++;
 
                asyncResult = new ReceiveFromAsyncResult(
                    this.socket,
                    new ArraySegment(buffer, offset, size),
                    remoteEndPoint, 
                    size - offset,
                    this.timeToLive, 
                    callback, 
                    state);
                success = true; 

                return asyncResult;
            }
            finally 
            {
                if (!success) 
                { 
                    this.pendingReceiveCount--;
                } 
            }
        }

        public void Close() 
        {
            bool cleanup = false; 
            lock (this.ThisLock) 
            {
                if (this.IsDisposed) 
                {
                    return;
                }
 
                //UdpUtility.CreateListenSocketsOnUniquePort can create a socket and then close it without ever calling
                //UdpSocket.Open() if it fails to bind on both IPv4 and IPv6.  If this happens, then openCount will still be at zero. 
                if (this.openCount > 0) 
                {
                    this.openCount--; 
                }

                if (this.openCount == 0)
                { 
                    cleanup = true;
                    this.openCount = -1; 
                } 
            }
 
            if (cleanup)
            {
#if DEBUG
                if (!Fx.FastDebug) 
                {
                    disposeStack = new StackTrace(); 
                } 
#endif
                //non-zero sendTimeout causes the socket to block on a receive while looking for an EOF, which will never come 
                this.socket.Close(0);
            }
        }
 
        //must be called under a lock in receive loop
        public ArraySegment EndReceiveFrom(IAsyncResult result, ref EndPoint remoteEndPoint) 
        { 
            this.pendingReceiveCount--;
            return ReceiveFromAsyncResult.End(result, ref remoteEndPoint); 
        }

        internal EndPoint CreateIPAnyEndPoint()
        { 
            if (this.AddressFamily == AddressFamily.InterNetwork)
            { 
                return new IPEndPoint(IPAddress.Any, 0); 
            }
            else 
            {
                return new IPEndPoint(IPAddress.IPv6Any, 0);
            }
        } 

        public void Open() 
        { 
            lock (this.ThisLock)
            { 
                if (this.IsDisposed)
                {
                    throw FxTrace.Exception.AsError(new ObjectDisposedException("UdpSocket"));
                } 
                this.openCount++;
            } 
        } 

        public int SendTo(byte[] buffer, int offset, int size, EndPoint remoteEndPoint) 
        {
            ThrowIfNotOpen();
            UdpUtility.ValidateBufferBounds(buffer, offset, size);
 
            try
            { 
                int count = this.socket.SendTo(buffer, offset, size, SocketFlags.None, remoteEndPoint); 
                Fx.Assert(count == size, "Bytes sent on the wire should be the same as the bytes specified");
 
                return count;
            }
            catch (SocketException socketException)
            { 
                throw FxTrace.Exception.AsError(ConvertNetworkError(socketException, size - offset, TransferDirection.Send, this.timeToLive));
            } 
        } 

        public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, EndPoint remoteEndPoint, AsyncCallback callback, object state) 
        {
            ThrowIfNotOpen();
            UdpUtility.ValidateBufferBounds(buffer, offset, size);
 
            return new SendToAsyncResult(this.socket, buffer, offset, size, remoteEndPoint, this.timeToLive, callback, state);
        } 
 
        public int EndSendTo(IAsyncResult result)
        { 
            return SendToAsyncResult.End(result);
        }

        static Exception ConvertNetworkError(SocketException socketException, ReceiveFromAsyncResult result) 
        {
            return ConvertNetworkError(socketException, result.MessageSize, TransferDirection.Receive, result.TimeToLive); 
        } 

        //  size:   sending => the size of the data being sent 
        //          Receiving => the max message size we can receive
        //  remoteEndPoint: remote endpoint reported when error occured
        static Exception ConvertNetworkError(SocketException socketException, int size, TransferDirection direction, int timeToLive)
        { 
            Exception result = null;
 
            if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE) 
            {
                //This would likely indicate a bug in our ref-counting 
                //for instance, a channel is closing the socket multiple times...
                Fx.Assert("The socket appears to have been closed unexpectedly.  This probably indicates incorrect ref counting (i.e. a channel is closing the socket multiple times)");
                result = new CommunicationObjectAbortedException(socketException.Message, socketException);
            } 
            else
            { 
                string errorMessage; 
                switch (socketException.SocketErrorCode)
                { 
                    case SocketError.MessageSize: //10040
                        errorMessage = (direction == TransferDirection.Send ? SR.UdpMaxMessageSendSizeExceeded(size) : SR.MaxReceivedMessageSizeExceeded(size));
                        Exception inner = new QuotaExceededException(errorMessage, socketException);
                        result = new ProtocolException(errorMessage, inner); 
                        break;
                    case SocketError.NetworkReset: //10052 
                        //ICMP: Time Exceeded (TTL expired) 
                        //see http://tools.ietf.org/html/rfc792
                        result = new CommunicationException(SR.IcmpTimeExpired(timeToLive), socketException); 
                        break;
                    case SocketError.ConnectionReset: //10054
                        //ICMP: Destination Unreachable (target host/port/etc not reachable)
                        //see http://tools.ietf.org/html/rfc792 
                        result = new CommunicationException(SR.IcmpDestinationUnreachable, socketException);
                        break; 
                    default: 
                        errorMessage = (direction == TransferDirection.Send ? SR.UdpSendException : SR.UdpReceiveException);
                        result = new CommunicationException(errorMessage, socketException); 
                        break;
                }
            }
 
            Fx.Assert(result != null, "we should never return null");
            return result; 
        } 

        void ThrowIfDisposed() 
        {
            if (this.IsDisposed)
            {
                throw FxTrace.Exception.AsError(new ObjectDisposedException(this.GetType().ToString())); 
            }
        } 
 
        void ThrowIfNotOpen()
        { 
            ThrowIfDisposed();

            if (this.openCount == 0)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ObjectNotOpen));
            } 
        } 

        class SendToAsyncResult : TypedAsyncResult 
        {
            Socket socket;
            int offset;
            int size; 
            int timeToLive;
 
            static AsyncCallback onSendToComplete = Fx.ThunkCallback(OnSendToComplete); 

            public SendToAsyncResult(Socket socket, byte[] buffer, int offset, int size, EndPoint remoteEndPoint, int timeToLive, AsyncCallback callback, object state) 
                : base(callback, state)
            {
                this.socket = socket;
                this.offset = offset; 
                this.size = size;
                this.timeToLive = timeToLive; 
                int count = 0; 

                try 
                {
                    IAsyncResult socketAsyncResult = this.socket.BeginSendTo(buffer, offset, size, SocketFlags.None, remoteEndPoint, onSendToComplete, this);

                    if (!socketAsyncResult.CompletedSynchronously) 
                    {
                        return; 
                    } 

                    count = this.socket.EndSendTo(socketAsyncResult); 
                }
                catch (SocketException socketException)
                {
                    throw FxTrace.Exception.AsError(ConvertNetworkError(socketException, this.size - this.offset, TransferDirection.Send, this.timeToLive)); 
                }
 
                this.Complete(count, true); 
            }
 
            static void OnSendToComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                { 
                    return;
                } 
 
                SendToAsyncResult thisPtr = (SendToAsyncResult)result.AsyncState;
                Exception completionException = null; 
                int count = 0;

                try
                { 
                    count = thisPtr.socket.EndSendTo(result);
                } 
                catch (SocketException socketException) 
                {
                    completionException = ConvertNetworkError(socketException, thisPtr.size - thisPtr.offset, TransferDirection.Send, thisPtr.timeToLive); 
                }
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex)) 
                    {
                        throw; 
                    } 

                    completionException = ex; 
                }

                if (completionException != null)
                { 
                    thisPtr.Complete(false, completionException);
                } 
                else 
                {
                    thisPtr.Complete(count, false); 
                }
            }
        }
 
        class ReceiveFromAsyncResult : TypedAsyncResult>
        { 
            static AsyncCallback onReceiveMessageFromCallback = Fx.ThunkCallback(new AsyncCallback(OnReceiveMessageFrom)); 
            Socket socket;
 
            public ReceiveFromAsyncResult(Socket socket, ArraySegment buffer, EndPoint remoteEndPoint, int messageSize, int timeToLive, AsyncCallback userCallback, object userState) :
                base(userCallback, userState)
            {
                this.RemoteEndPoint = remoteEndPoint; 
                this.MessageSize = messageSize;
                this.socket = socket; 
                this.Buffer = buffer; 
                this.TimeToLive = timeToLive;
 
                ArraySegment data = default(ArraySegment);

                try
                { 
                    IAsyncResult socketAsyncResult = this.socket.BeginReceiveFrom(this.Buffer.Array,
                        this.Buffer.Offset, 
                        this.Buffer.Count, 
                        SocketFlags.None,
                        ref remoteEndPoint, 
                        onReceiveMessageFromCallback,
                        this);

                    if (!socketAsyncResult.CompletedSynchronously) 
                    {
                        return; 
                    } 

                    data = EndReceiveFrom(socketAsyncResult); 
                }
                catch (SocketException socketException)
                {
                    throw FxTrace.Exception.AsError(UdpSocket.ConvertNetworkError(socketException, this)); 
                }
 
                Complete(data, true); 
            }
 
            public EndPoint RemoteEndPoint
            {
                get;
                private set; 
            }
 
            public int TimeToLive 
            {
                get; 
                private set;
            }

            //used when generating error messages for the user... 
            internal int MessageSize
            { 
                get; 
                private set;
            } 

            ArraySegment Buffer
            {
                get; 
                set;
            } 
 
            public static ArraySegment End(IAsyncResult result, ref EndPoint remoteEndPoint)
            { 
                ArraySegment data = TypedAsyncResult>.End(result);
                ReceiveFromAsyncResult receiveFromResult = (ReceiveFromAsyncResult)result;
                remoteEndPoint = receiveFromResult.RemoteEndPoint;
                return data; 
            }
 
            static void OnReceiveMessageFrom(IAsyncResult result) 
            {
                if (result.CompletedSynchronously) 
                {
                    return;
                }
 
                ReceiveFromAsyncResult asyncResult = (ReceiveFromAsyncResult)result.AsyncState;
 
                Exception completionException = null; 
                ArraySegment data = default(ArraySegment);
 
                try
                {
                    data = asyncResult.EndReceiveFrom(result);
                } 
                catch (SocketException socketException)
                { 
                    completionException = UdpSocket.ConvertNetworkError(socketException, asyncResult); 
                }
                catch (Exception exception) 
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw; 
                    }
                    completionException = exception; 
                } 

                if (completionException != null) 
                {
                    asyncResult.Complete(false, completionException);
                }
                else 
                {
                    asyncResult.Complete(data, false); 
                } 
            }
 
            ArraySegment EndReceiveFrom(IAsyncResult result)
            {
                EndPoint remoteEndPoint = this.RemoteEndPoint;
                int count = this.socket.EndReceiveFrom(result, ref remoteEndPoint); 
                this.RemoteEndPoint = remoteEndPoint;
                return new ArraySegment(this.Buffer.Array, this.Buffer.Offset, count); 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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