SocketConnection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / SocketConnection.cs / 3 / SocketConnection.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
#define WSARECV
namespace System.ServiceModel.Channels 
{
    using System.Collections.Generic; 
    using System.ServiceModel; 
    using System.Diagnostics;
    using System.Net; 
    using System.Net.Sockets;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.ServiceModel.Diagnostics; 
    using System.Text;
 
 
    class SocketConnection : IConnection
#if WSARECV 
, IDisposable
#endif
    {
        // common state 
        Socket socket;
        TimeSpan sendTimeout; 
        TimeSpan receiveTimeout; 
        CloseState closeState;
        bool isShutdown; 
        bool noDelay = false;
        bool aborted;
        TraceEventType exceptionEventType;
 
        // read state
        int asyncReadSize; 
#if WSARECV 
        static int bytesTransferred;
        OverlappedContext asyncReadOverlapped; 
        static int socketFlags;
        OverlappedIOCompleteCallback readCallback;
#endif
        byte[] readBuffer; 
        int asyncReadBufferSize;
        object asyncReadState; 
        WaitCallback asyncReadCallback; 
        Exception asyncReadException;
        AsyncCallback onReceive; 
        bool asyncReadPending;
        bool asyncWritePending;
        IOThreadTimer receiveTimer;
        static WaitCallback onReceiveTimeout; 
        IOThreadTimer sendTimer;
        static WaitCallback onSendTimeout; 
        string timeoutErrorString; 
        TransferOperation timeoutErrorTransferOperation;
        IPEndPoint remoteEndpoint; 

        public SocketConnection(Socket socket, int asyncReadBufferSize, bool autoBindToCompletionPort)
        {
            if (socket == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("socket"); 
            } 

            this.closeState = CloseState.Open; 
            this.exceptionEventType = TraceEventType.Error;
            this.socket = socket;
            this.socket.SendBufferSize = this.socket.ReceiveBufferSize = asyncReadBufferSize;
            this.sendTimeout = this.receiveTimeout = TimeSpan.MaxValue; 
            this.asyncReadBufferSize = asyncReadBufferSize;
            this.onReceive = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnReceive)); 
 
            if (autoBindToCompletionPort)
            { 
                this.socket.UseOnlyOverlappedIO = false;
            }
            this.TraceSocketInfo(socket, TraceCode.SocketConnectionCreate, null);
        } 

        public int AsyncReadBufferSize 
        { 
            get { return asyncReadBufferSize; }
        } 

        public byte[] AsyncReadBuffer
        {
            get 
            {
                if (readBuffer == null) 
                { 
                    lock (ThisLock)
                    { 
                        ThrowIfClosed();
                        if (readBuffer == null)
                        {
#if WSARECV 
                            asyncReadOverlapped = new OverlappedContext();
#endif 
                            readBuffer = DiagnosticUtility.Utility.AllocateByteArray(asyncReadBufferSize); 
                        }
                    } 
                }
                return readBuffer;
            }
        } 

        object ThisLock 
        { 
            get { return this; }
        } 

        public TraceEventType ExceptionEventType
        {
            get { return this.exceptionEventType; } 
            set { this.exceptionEventType = value; }
        } 
 
        public IPEndPoint RemoteIPEndPoint
        { 
            get
            {
                // this property should only be called on the receive path
                if (remoteEndpoint == null && this.closeState == CloseState.Open) 
                {
                    try 
                    { 
                        remoteEndpoint = (IPEndPoint)socket.RemoteEndPoint;
                    } 
                    catch (SocketException socketException)
                    {
                        // will never be a timeout error, so TimeSpan.Zero is ok
#pragma warning suppress 56503 // Called from Receive path, SocketConnection cannot allow a SocketException to escape. 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                            ConvertReceiveException(socketException, TimeSpan.Zero), ExceptionEventType); 
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
                        if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
                        {
#pragma warning suppress 56503 // rethrow 
                            throw;
                        } 
                        else 
                        {
#pragma warning suppress 56503 // Called from Receive path, SocketConnection must convert ObjectDisposedException properly. 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                        }
                    }
                } 

                return remoteEndpoint; 
            } 
        }
 
        IOThreadTimer SendTimer
        {
            get
            { 
                if (this.sendTimer == null)
                { 
                    if (onSendTimeout == null) 
                    {
                        onSendTimeout = new WaitCallback(OnSendTimeout); 
                    }

                    this.sendTimer = new IOThreadTimer(onSendTimeout, this, false);
                } 

                return this.sendTimer; 
            } 
        }
 
        IOThreadTimer ReceiveTimer
        {
            get
            { 
                if (this.receiveTimer == null)
                { 
                    if (onReceiveTimeout == null) 
                    {
                        onReceiveTimeout = new WaitCallback(OnReceiveTimeout); 
                    }

                    this.receiveTimer = new IOThreadTimer(onReceiveTimeout, this, false);
                } 

                return this.receiveTimer; 
            } 
        }
 
        static void OnReceiveTimeout(object state)
        {
            SocketConnection thisPtr = (SocketConnection)state;
            thisPtr.Abort(SR.GetString(SR.SocketAbortedReceiveTimedOut, thisPtr.receiveTimeout), TransferOperation.Read); 
        }
 
        static void OnSendTimeout(object state) 
        {
            SocketConnection thisPtr = (SocketConnection)state; 
            thisPtr.Abort(TraceEventType.Warning,
                SR.GetString(SR.SocketAbortedSendTimedOut, thisPtr.sendTimeout), TransferOperation.Write);
        }
 
        public void Abort()
        { 
            Abort(null, TransferOperation.Undefined); 
        }
 
        void Abort(string timeoutErrorString, TransferOperation transferOperation)
        {
            TraceEventType traceEventType = TraceEventType.Warning;
 
            // we could be timing out a cached connection
            if (this.ExceptionEventType == TraceEventType.Information) 
            { 
                traceEventType = this.ExceptionEventType;
            } 

            Abort(traceEventType, timeoutErrorString, transferOperation);
        }
 
        void Abort(TraceEventType traceEventType)
        { 
            Abort(traceEventType, null, TransferOperation.Undefined); 
        }
 
        void Abort(TraceEventType traceEventType, string timeoutErrorString, TransferOperation transferOperation)
        {
            lock (ThisLock)
            { 
                if (closeState == CloseState.Closed)
                { 
                    return; 
                }
 
                this.timeoutErrorString = timeoutErrorString;
                this.timeoutErrorTransferOperation = transferOperation;
                aborted = true;
                closeState = CloseState.Closed; 

#if WSARECV 
                if (!this.asyncReadPending && this.asyncReadOverlapped != null) 
                {
                    this.asyncReadOverlapped.FreeOrDefer(); 
                }
#endif

                if (this.asyncReadPending) 
                {
                    CancelReceiveTimer(); 
                } 

                if (this.asyncWritePending) 
                {
                    CancelSendTimer();
                }
            } 

            if (DiagnosticUtility.ShouldTrace(traceEventType)) 
            { 
                TraceUtility.TraceEvent(traceEventType, TraceCode.SocketConnectionAbort, this);
            } 

            socket.Close(0);
        }
 
        void AbortRead()
        { 
            lock (ThisLock) 
            {
                if (this.asyncReadPending) 
                {
                    if (closeState != CloseState.Closed)
                    {
                        this.asyncReadPending = false; 
                        CancelReceiveTimer();
                    } 
                } 
            }
        } 

        void CancelReceiveTimer()
        {
            // CSDMain 34539: Snapshot the timer so that we don't null ref if there is a race 
            // between calls to CancelReceiveTimer (e.g., Abort, AsyncReadCallback)
 
            IOThreadTimer receiveTimerSnapshot = this.receiveTimer; 
            this.receiveTimer = null;
 
            if (receiveTimerSnapshot != null)
            {
                receiveTimerSnapshot.Cancel();
            } 
        }
 
        void CancelSendTimer() 
        {
            if (this.sendTimer != null) 
            {
                this.sendTimer.Cancel();
                this.sendTimer = null;
            } 
        }
 
        public void Close(TimeSpan timeout) 
        {
            lock (ThisLock) 
            {
                if (closeState == CloseState.Closing || closeState == CloseState.Closed)
                {
                    // already closing or closed, so just return 
                    return;
                } 
                this.TraceSocketInfo(this.socket, TraceCode.SocketConnectionClose, timeout.ToString()); 
                closeState = CloseState.Closing;
            } 

            // first we shutdown our send-side
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            Shutdown(timeoutHelper.RemainingTime()); 
            byte[] dummy = new byte[1];
 
            // then we check for a FIN from the other side (i.e. read zero) 
            int bytesRead;
            TimeSpan readFinTimeout = timeoutHelper.RemainingTime(); 
            try
            {
                bytesRead = ReadCore(dummy, 0, 1, readFinTimeout, true);
 
                if (bytesRead > 0)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                        new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, socket.RemoteEndPoint)), ExceptionEventType);
                } 
            }
            catch (TimeoutException timeoutException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException( 
                    SR.GetString(SR.SocketCloseReadTimeout, socket.RemoteEndPoint, readFinTimeout), timeoutException), ExceptionEventType);
            } 
 
            // finally we call Close with whatever time is remaining
            TimeSpan socketCloseTimeout = timeoutHelper.RemainingTime(); 

            // trace if we're effectively aborting
            if (socketCloseTimeout <= TimeSpan.Zero && DiagnosticUtility.ShouldTraceWarning)
            { 
                TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.SocketConnectionAbortClose, this);
            } 
 
            socket.Close(TimeoutHelper.ToMilliseconds(socketCloseTimeout));
 
            lock (ThisLock)
            {
#if WSARECV
                // Abort could have been called on a separate thread and cleaned up 
                // our buffers/completion here
                if (!this.asyncReadPending && closeState != CloseState.Closed && this.asyncReadOverlapped != null) 
                { 
                    this.asyncReadOverlapped.FreeOrDefer();
                } 
#endif
                closeState = CloseState.Closed;
            }
        } 

#if WSARECV 
        public void Dispose() 
        {
            this.Abort(); 
        }
#endif

        public void Shutdown(TimeSpan timeout) 
        {
            lock (ThisLock) 
            { 
                if (isShutdown)
                { 
                    return;
                }

                isShutdown = true; 
            }
 
            try 
            {
                socket.Shutdown(SocketShutdown.Send); 
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertSendException(socketException, TimeoutHelper.Infinite), ExceptionEventType);
            } 
            catch (ObjectDisposedException objectDisposedException) 
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined); 
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw;
                } 
                else
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType); 
                }
            } 
        }

        void ThrowIfClosed()
        { 
            if (closeState == CloseState.Closing || closeState == CloseState.Closed)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertObjectDisposedException(new ObjectDisposedException(
                    this.GetType().ToString(), SR.GetString(SR.SocketConnectionDisposed)), TransferOperation.Undefined), ExceptionEventType); 
            }
        }

        void TraceSocketInfo(Socket socket, TraceCode traceCode, string timeoutString) 
        {
            if (DiagnosticUtility.ShouldTraceInformation) 
            { 
                Dictionary values = new Dictionary(4);
                values["State"] = this.closeState.ToString(); 

                if (timeoutString != null)
                {
                    values["Timeout"] = timeoutString; 
                }
 
                if (socket != null && this.closeState != CloseState.Closing) 
                {
                    if (socket.LocalEndPoint != null) 
                    {
                        values["LocalEndpoint"] = socket.LocalEndPoint.ToString();
                    }
                    if (socket.RemoteEndPoint != null) 
                    {
                        values["RemoteEndPoint"] = socket.RemoteEndPoint.ToString(); 
                    } 
                }
                TraceUtility.TraceEvent(TraceEventType.Information, traceCode, 
                    new DictionaryTraceRecord(values), this, null);
            }
        }
 
        public object DuplicateAndClose(int targetProcessId)
        { 
            object result = socket.DuplicateAndClose(targetProcessId); 
            this.Abort(TraceEventType.Information);
            return result; 
        }

        public object GetCoreTransport()
        { 
            return socket;
        } 
 
        public bool Validate(Uri uri)
        { 
            return true;
        }

        Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime) 
        {
            return ConvertTransferException(socketException, this.sendTimeout, socketException, 
                TransferOperation.Write, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, remainingTime); 
        }
 
        Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime)
        {
            return ConvertTransferException(socketException, this.receiveTimeout, socketException,
                TransferOperation.Read, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, remainingTime); 
        }
 
        internal static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException) 
        {
            return ConvertTransferException(socketException, timeout, originalException, 
                TransferOperation.Undefined, false, null, TransferOperation.Undefined, TimeoutHelper.Infinite);
        }

        Exception ConvertObjectDisposedException(ObjectDisposedException originalException, TransferOperation transferOperation) 
        {
            if (this.timeoutErrorString != null) 
            { 
                return ConvertTimeoutErrorException(originalException, transferOperation, this.timeoutErrorString, this.timeoutErrorTransferOperation);
            } 
            else if (this.aborted)
            {
                return new CommunicationObjectAbortedException(SR.GetString(SR.SocketConnectionDisposed), originalException);
            } 
            else
            { 
                return originalException; 
            }
        } 

        static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException,
            TransferOperation transferOperation, bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation, TimeSpan remainingTime)
        { 
            if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
            { 
                return new CommunicationObjectAbortedException(socketException.Message, socketException); 
            }
 
            if (timeoutErrorString != null)
            {
                return ConvertTimeoutErrorException(originalException, transferOperation, timeoutErrorString, timeoutErrorTransferOperation);
            } 

            // 10053 can occur due to our timeout sockopt firing, so map to TimeoutException in that case 
            if (socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED && 
                remainingTime <= TimeSpan.Zero)
            { 
                return new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
            }

            if (socketException.ErrorCode == UnsafeNativeMethods.WSAENETRESET || 
                socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED ||
                socketException.ErrorCode == UnsafeNativeMethods.WSAECONNRESET) 
            { 
                if (aborted)
                { 
                    return new CommunicationObjectAbortedException(SR.GetString(SR.TcpLocalConnectionAborted), originalException);
                }
                else
                { 
                    return new CommunicationException(SR.GetString(SR.TcpConnectionResetError, timeout), originalException);
                } 
            } 
            else if (socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
            { 
                return new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
            }
            else
            { 
                if (aborted)
                { 
                    return new CommunicationObjectAbortedException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException); 
                }
                else 
                {
                    return new CommunicationException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException);
                }
            } 
        }
 
        static Exception ConvertTimeoutErrorException(Exception originalException, 
            TransferOperation transferOperation, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation)
        { 
            if (timeoutErrorString == null)
            {
                DiagnosticUtility.DebugAssert("Argument timeoutErrorString must not be null.");
            } 

            if (transferOperation == timeoutErrorTransferOperation) 
            { 
                return new TimeoutException(timeoutErrorString, originalException);
            } 
            else
            {
                return new CommunicationException(timeoutErrorString, originalException);
            } 
        }
 
        public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, 
            AsyncCallback callback, object state)
        { 
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);

            try
            { 
                lock (ThisLock)
                { 
                    SetImmediate(immediate); 
                    SetWriteTimeout(timeout, false);
                    this.asyncWritePending = true; 
                }
                IAsyncResult result = socket.BeginSend(buffer, offset, size, SocketFlags.None, callback, state);
                return result;
            } 
            catch (SocketException socketException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertSendException(socketException, TimeoutHelper.Infinite), ExceptionEventType);
            } 
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException)) 
                {
                    throw; 
                } 
                else
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                }
            }
        } 

        public void EndWrite(IAsyncResult result) 
        { 
            try
            { 
                bool callEnd;
                CancelSendTimer();
                lock (ThisLock)
                { 
                    this.asyncWritePending = false;
                    callEnd = (this.closeState != CloseState.Closed); 
                } 

                // System.Net will throw if EndSend() is called on a disposed socket. Note that we can 
                // still get aborted prior to calling EndSend, so we still need to catch ODE below
                if (callEnd)
                {
                    socket.EndSend(result); 
                }
            } 
            catch (SocketException socketException) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertSendException(socketException, TimeoutHelper.Infinite), ExceptionEventType);
            }
            catch (ObjectDisposedException objectDisposedException)
            { 
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException)) 
                { 
                    throw;
                } 
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                } 
            }
        } 
 
        public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
        { 
            // as per http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b201213
            // we shouldn't write more than 64K synchronously to a socket
            const int maxSocketWrite = 64 * 1024;
 
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            try
            { 
                SetImmediate(immediate);
                int bytesToWrite = size;

                while (bytesToWrite > 0) 
                {
                    SetWriteTimeout(timeoutHelper.RemainingTime(), true); 
                    size = Math.Min(bytesToWrite, maxSocketWrite); 
                    socket.Send(buffer, offset, size, SocketFlags.None);
                    bytesToWrite -= size; 
                    offset += size;
                    timeout = timeoutHelper.RemainingTime();
                }
            } 
            catch (SocketException socketException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertSendException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
            } 
            catch (ObjectDisposedException objectDisposedException)
            {
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException)) 
                {
                    throw; 
                } 
                else
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                }
            }
        } 

        public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager) 
        { 
            try
            { 
                Write(buffer, offset, size, immediate, timeout);
            }
            finally
            { 
                bufferManager.ReturnBuffer(buffer);
            } 
        } 

        public int Read(byte[] buffer, int offset, int size, TimeSpan timeout) 
        {
            ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
            ThrowIfClosed();
            return ReadCore(buffer, offset, size, timeout, false); 
        }
 
        int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool closing) 
        {
            int bytesRead = 0; 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            try
            {
                SetReadTimeout(timeoutHelper.RemainingTime(), true, closing); 
                bytesRead = socket.Receive(buffer, offset, size, SocketFlags.None);
            } 
            catch (SocketException socketException) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                    ConvertReceiveException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
            }
            catch (ObjectDisposedException objectDisposedException)
            { 
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException)) 
                { 
                    throw;
                } 
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                } 
            }
 
            return bytesRead; 
        }
 
        protected void SetAsyncBytesRead(int bytesRead)
        {
            this.asyncReadSize = bytesRead;
        } 

#if !WSARECV 
        public virtual AsyncReadResult BeginRead(int offset, int size, WaitCallback callback, object state) 
        {
            ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size); 

            lock (ThisLock)
            {
                ThrowIfClosed(); 

                asyncReadState = state; 
                asyncReadCallback = callback; 
                asyncReadPending = true;
            } 

            try
            {
                IAsyncResult result = socket.BeginReceive(AsyncReadBuffer, offset, size, SocketFlags.None, onReceive, null); 

                if (!result.CompletedSynchronously) 
                    return AsyncReadResult.Queued; 

                asyncReadSize = socket.EndReceive(result); 
                return AsyncReadResult.Completed;
            }
            catch (SocketException socketException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertReceiveException(socketException, TimeoutHelper.Infinite), ExceptionEventType);
            } 
        } 
#else
        unsafe public virtual AsyncReadResult BeginRead(int offset, int size, TimeSpan timeout, 
            WaitCallback callback, object state)
        {
            ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size);
 
            lock (ThisLock)
            { 
                ThrowIfClosed(); 

                asyncReadState = state; 
                asyncReadCallback = callback;
                this.asyncReadPending = true;
                SetReadTimeout(timeout, false, false);
            } 

            bool abortRead = true; 
            try 
            {
                if (socket.UseOnlyOverlappedIO) 
                {
                    try
                    {
                        IAsyncResult result = socket.BeginReceive(AsyncReadBuffer, offset, size, SocketFlags.None, onReceive, null); 

                        if (!result.CompletedSynchronously) 
                        { 
                            abortRead = false;
                            return AsyncReadResult.Queued; 
                        }

                        asyncReadSize = socket.EndReceive(result);
                        abortRead = false; 
                        return AsyncReadResult.Completed;
                    } 
                    catch (SocketException exception) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper( 
                            ConvertReceiveException(exception, TimeoutHelper.Infinite), ExceptionEventType);
                    }
                }
 
                if (readCallback == null)
                { 
                    // Do this just to get the socket bound to the completion port 
                    try
                    { 
                        socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, null, null);
                    }
                    catch (SocketException exception)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                            ConvertReceiveException(exception, TimeoutHelper.Infinite), ExceptionEventType); 
                    } 

                    readCallback = new OverlappedIOCompleteCallback(AsyncReadCallback); 
                }

                // Error on the side of leaking (rather than  premature free) by only calling Cancel if we know it's safe.
                bool success = true; 
                try
                { 
                    int wsaRecvError = 0; 

                    int error = UnsafeNativeMethods.ERROR_SUCCESS; 
                    lock (ThisLock)
                    {
                        ThrowIfClosed();
 
                        // This must be done before StartSyncOperation because it causes asyncReadOverlapped to be created.
                        UnsafeNativeMethods.WSABuffer wsaBuffer; 
                        wsaBuffer.length = Math.Min(AsyncReadBuffer.Length - offset, size); 

                        // Among other things, this pins the buffer. 
                        this.asyncReadOverlapped.StartAsyncOperation(AsyncReadBuffer, readCallback, true);

                        wsaBuffer.buffer = (IntPtr) (this.asyncReadOverlapped.BufferPtr + offset);
 
                        wsaRecvError = UnsafeNativeMethods.WSARecv(socket.Handle, &wsaBuffer, 1, out bytesTransferred,
                                ref socketFlags, this.asyncReadOverlapped.NativeOverlapped, IntPtr.Zero); 
                        if (wsaRecvError == -1) 
                        {
                            // Get the Win32 error code before doing anything else (including Monitor.Exit()). 
                            error = Marshal.GetLastWin32Error();
                        }
                    }
 
                    if (wsaRecvError == -1)
                    { 
                        if (error != UnsafeNativeMethods.ERROR_IO_PENDING && 
                            error != UnsafeNativeMethods.ERROR_MORE_DATA)
                        { 
                            success = false;
                            SocketException socketException = new SocketException(error);
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                                ConvertReceiveException(socketException, TimeoutHelper.Infinite), ExceptionEventType); 
                        }
                    } 
                } 
                finally
                { 
                    if (!success)
                    {
                        this.asyncReadOverlapped.CancelAsyncOperation();
                    } 
                }
                abortRead = false; 
            } 
            catch (ObjectDisposedException objectDisposedException)
            { 
                Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
                if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
                {
                    throw; 
                }
                else 
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
                } 
            }
            finally
            {
                if (abortRead) 
                {
                    AbortRead(); 
                } 
            }
 
            return AsyncReadResult.Queued;
        }

        unsafe void AsyncReadCallback(bool haveResult, int error, int bytesRead) 
        {
            if (!haveResult) 
            { 
                DiagnosticUtility.DebugAssert("Socket OverlappedContext should always be bound.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }

            CancelReceiveTimer();
 
            if (error != 0)
            { 
                // From System.Net:_BaseOverlappedAsyncResult.cs 
                // There are cases where passed errorCode does not reflect the details of the underlined socket error.
                if (error != UnsafeNativeMethods.ERROR_OPERATION_ABORTED) 
                {
                    // Here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
                    // and we need to do a manual lock since socket.SafeHandle isn't exposed publicly
                    lock (ThisLock) 
                    {
                        if (closeState == CloseState.Closing || closeState == CloseState.Closed) 
                        { 
                            error = UnsafeNativeMethods.ERROR_OPERATION_ABORTED;
                        } 
                        else
                        {
                            uint dummyFlags;
                            bool dummy = UnsafeNativeMethods.WSAGetOverlappedResult( 
                                    socket.Handle,
                                    this.asyncReadOverlapped.NativeOverlapped, 
                                    out bytesRead, 
                                    false,
                                    out dummyFlags); 
                            error = Marshal.GetLastWin32Error();
                        }
                    }
                } 

                asyncReadException = ConvertReceiveException(new SocketException(error), TimeoutHelper.Infinite); 
            } 

            asyncReadSize = bytesRead; 
            this.asyncReadOverlapped.FreeIfDeferred();
            FinishRead();
        }
#endif 

        void OnReceive(IAsyncResult result) 
        { 
            CancelReceiveTimer();
            if (result.CompletedSynchronously) 
            {
                return;
            }
 
            try
            { 
                asyncReadSize = socket.EndReceive(result); 
            }
            catch (SocketException socketException) 
            {
                asyncReadException = ConvertReceiveException(socketException, TimeoutHelper.Infinite);
            }
            catch (ObjectDisposedException objectDisposedException) 
            {
                asyncReadException = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read); 
            } 
#pragma warning suppress 56500 // [....], transferring exception to caller
            catch (Exception exception) 
            {
                if (DiagnosticUtility.IsFatal(exception))
                {
                    throw; 
                }
                asyncReadException = exception; 
            } 

            FinishRead(); 
        }

        void FinishRead()
        { 
            WaitCallback asyncReadCallback = this.asyncReadCallback;
            object asyncReadState = this.asyncReadState; 
 
            this.asyncReadState = null;
            this.asyncReadCallback = null; 

            asyncReadCallback(asyncReadState);
        }
 
        public int EndRead()
        { 
            if (asyncReadException != null) 
            {
                AbortRead(); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelper(asyncReadException, ExceptionEventType);
            }

            lock (ThisLock) 
            {
                if (!this.asyncReadPending) 
                { 
                    DiagnosticUtility.DebugAssert("SocketConnection.EndRead called with no read pending.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
                }

                this.asyncReadPending = false;
 
#if WSARECV
                if (closeState == CloseState.Closed && this.asyncReadOverlapped != null) 
                { 
                    this.asyncReadOverlapped.FreeOrDefer();
                } 
#endif
            }
            return asyncReadSize;
        } 

        void SetImmediate(bool immediate) 
        { 
            if (immediate != this.noDelay)
            { 
                lock (ThisLock)
                {
                    ThrowIfClosed();
                    socket.NoDelay = immediate; 
                }
                this.noDelay = immediate; 
            } 
        }
 
        void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing)
        {
            if (synchronous)
            { 
                CancelReceiveTimer();
 
                // 0 == infinite for winsock timeouts, so we should preempt and throw 
                if (timeout <= TimeSpan.Zero)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                        new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType);
                }
 
                if (UpdateTimeout(this.receiveTimeout, timeout))
                { 
                    lock (ThisLock) 
                    {
                        if (!closing || this.closeState != CloseState.Closing) 
                        {
                            ThrowIfClosed();
                        }
                        this.socket.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout); 
                    }
                    this.receiveTimeout = timeout; 
                } 
            }
            else 
            {
                this.receiveTimeout = timeout;
                if (timeout == TimeSpan.MaxValue)
                { 
                    CancelReceiveTimer();
                } 
                else 
                {
                    ReceiveTimer.Set(timeout); 
                }
            }
        }
 
        void SetWriteTimeout(TimeSpan timeout, bool synchronous)
        { 
            if (synchronous) 
            {
                CancelSendTimer(); 

                // 0 == infinite for winsock timeouts, so we should preempt and throw
                if (timeout <= TimeSpan.Zero)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
                        new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType); 
                } 

                if (UpdateTimeout(this.sendTimeout, timeout)) 
                {
                    lock (ThisLock)
                    {
                        ThrowIfClosed(); 
                        this.socket.SendTimeout = TimeoutHelper.ToMilliseconds(timeout);
                    } 
                    this.sendTimeout = timeout; 
                }
            } 
            else
            {
                this.sendTimeout = timeout;
                if (timeout == TimeSpan.MaxValue) 
                {
                    CancelSendTimer(); 
                } 
                else
                { 
                    SendTimer.Set(timeout);
                }
            }
        } 

        bool UpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout) 
        { 
            if (oldTimeout == newTimeout)
            { 
                return false;
            }

            long threshold = oldTimeout.Ticks / 10; 
            long delta = Math.Max(oldTimeout.Ticks, newTimeout.Ticks) - Math.Min(oldTimeout.Ticks, newTimeout.Ticks);
 
            return delta > threshold; 
        }
 
        enum CloseState
        {
            Open,
            Closing, 
            Closed,
        } 
 
        enum TransferOperation
        { 
            Write,
            Read,
            Undefined,
        } 
    }
 
    class SocketConnectionInitiator : IConnectionInitiator 
    {
        int bufferSize; 

        public SocketConnectionInitiator(int bufferSize)
        {
            this.bufferSize = bufferSize; 
        }
 
        IConnection CreateConnection(Socket socket) 
        {
            return new SocketConnection(socket, bufferSize, false); 
        }

        public static Exception ConvertConnectException(SocketException socketException, Uri remoteUri, TimeSpan timeSpent, Exception innerException)
        { 
            if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
            { 
                return new CommunicationObjectAbortedException(socketException.Message, socketException); 
            }
 
            if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRNOTAVAIL ||
                socketException.ErrorCode == UnsafeNativeMethods.WSAECONNREFUSED ||
                socketException.ErrorCode == UnsafeNativeMethods.WSAENETDOWN ||
                socketException.ErrorCode == UnsafeNativeMethods.WSAENETUNREACH || 
                socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTDOWN ||
                socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTUNREACH || 
                socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT) 
            {
                if (timeSpent == TimeSpan.MaxValue) 
                {
                    return new EndpointNotFoundException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
                }
                else 
                {
                    return new EndpointNotFoundException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException); 
                } 
            }
            else if (socketException.ErrorCode == UnsafeNativeMethods.WSAENOBUFS) 
            {
                return new InsufficientMemoryException(SR.GetString(SR.TcpConnectNoBufs), innerException);
            }
            else if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY || 
                socketException.ErrorCode == UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES ||
                socketException.ErrorCode == UnsafeNativeMethods.ERROR_OUTOFMEMORY) 
            { 
                return new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), socketException);
            } 
            else
            {
                if (timeSpent == TimeSpan.MaxValue)
                { 
                    return new CommunicationException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
                } 
                else 
                {
                    return new CommunicationException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException); 
                }
            }
        }
 
        static IPAddress[] GetIPAddresses(Uri uri)
        { 
            if (uri.HostNameType == UriHostNameType.IPv4 || 
                uri.HostNameType == UriHostNameType.IPv6)
            { 
                IPAddress ipAddress = IPAddress.Parse(uri.DnsSafeHost);
                return new IPAddress[] { ipAddress };
            }
 
            IPHostEntry hostEntry = null;
 
            try 
            {
                hostEntry = DnsCache.Resolve(uri.Host); 
            }
            catch (SocketException socketException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host), socketException));
            } 
 
            if (hostEntry.AddressList.Length == 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host)));
            }
 
            return hostEntry.AddressList;
        } 
 
        static TimeoutException CreateTimeoutException(Uri uri, TimeSpan timeout, IPAddress[] addresses, int invalidAddressCount,
            SocketException innerException) 
        {
            StringBuilder addressStringBuilder = new StringBuilder();
            for (int i = 0; i < invalidAddressCount; i++)
            { 
                if (addresses[i] == null)
                { 
                    continue; 
                }
 
                if (addressStringBuilder.Length > 0)
                {
                    addressStringBuilder.Append(", ");
                } 
                addressStringBuilder.Append(addresses[i].ToString());
            } 
 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
                SR.GetString(SR.TcpConnectingToViaTimedOut, uri.AbsoluteUri, timeout.ToString(), 
                invalidAddressCount, addresses.Length, addressStringBuilder.ToString()), innerException));
        }

        public IConnection Connect(Uri uri, TimeSpan timeout) 
        {
            if (DiagnosticUtility.ShouldTraceInformation) 
            { 
                TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingTcpConnection,
                    new StringTraceRecord("Uri", uri.ToString()), this, null); 
            }
            int port = uri.Port;
            IPAddress[] addresses = SocketConnectionInitiator.GetIPAddresses(uri);
            Socket socket = null; 
            SocketException lastException = null;
 
            if (port == -1) 
            {
                port = TcpUri.DefaultPort; 
            }

            int invalidAddressCount = 0;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            for (int i = 0; i < addresses.Length; i++)
            { 
                if (timeoutHelper.RemainingTime() == TimeSpan.Zero) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
                }

                AddressFamily addressFamily = addresses[i].AddressFamily; 

                if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6) 
                { 
                    addresses[i] = null; // disregard for exception attempt purposes
                    continue; 
                }

                DateTime connectStartTime = DateTime.UtcNow;
                try 
                {
                    socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); 
                    socket.Connect(new IPEndPoint(addresses[i], port)); 
                    lastException = null;
                    break; 
                }
                catch (SocketException socketException)
                {
                    invalidAddressCount++; 
                    SocketConnectionInitiator.TraceConnectFailure(socket, socketException, uri, DateTime.UtcNow - connectStartTime);
                    lastException = socketException; 
                    socket.Close(); 
                }
            } 

            if (socket == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
            } 
 
            if (lastException != null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    SocketConnectionInitiator.ConvertConnectException(lastException, uri,
                    timeoutHelper.ElapsedTime(), lastException));
            } 

            return CreateConnection(socket); 
        } 

        public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state) 
        {
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingTcpConnection, 
                    new StringTraceRecord("Uri", uri.ToString()), this, null);
            } 
            return new ConnectAsyncResult(uri, timeout, callback, state); 
        }
 
        public IConnection EndConnect(IAsyncResult result)
        {
            Socket socket = ConnectAsyncResult.End(result);
            return CreateConnection(socket); 
        }
 
        public static void TraceConnectFailure(Socket socket, SocketException socketException, Uri remoteUri, 
            TimeSpan timeSpentInConnect)
        { 
            if (DiagnosticUtility.ShouldTraceWarning)
            {
                Exception traceException = ConvertConnectException(socketException, remoteUri, timeSpentInConnect, socketException);
                TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.TcpConnectError, socket, traceException); 
            }
        } 
 
        class ConnectAsyncResult : AsyncResult
        { 
            IPAddress[] addresses;
            int currentIndex;
            int port;
            SocketException lastException; 
            TimeSpan timeout;
            TimeoutHelper timeoutHelper; 
            int invalidAddressCount; 
            DateTime connectStartTime;
            Socket socket; 
            Uri uri;
            static WaitCallback startConnectCallback;
            static AsyncCallback onConnect = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnConnect));
 
            public ConnectAsyncResult(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state) 
            { 
                this.uri = uri;
                addresses = SocketConnectionInitiator.GetIPAddresses(uri); 
                port = uri.Port;
                if (port == -1)
                {
                    port = TcpUri.DefaultPort; 
                }
 
                currentIndex = 0; 
                this.timeout = timeout;
                this.timeoutHelper = new TimeoutHelper(timeout); 

                if (Thread.CurrentThread.IsThreadPoolThread)
                {
                    if(StartConnect()) 
                    {
                        base.Complete(true); 
                    } 
                }
                else 
                {
                    // If we're not on a threadpool thread, then we need to post a callback to start our accepting loop
                    // Otherwise if the calling thread aborts then the async I/O will get inadvertantly cancelled
                    if (startConnectCallback == null) 
                    {
                        startConnectCallback = StartConnectCallback; 
                    } 

                    IOThreadScheduler.ScheduleCallback(startConnectCallback, this); 
                }
            }

            static void StartConnectCallback(object state) 
            {
                ConnectAsyncResult connectAsyncResult = (ConnectAsyncResult)state; 
                bool completeSelf = false; 
                Exception completionException = null;
                try 
                {
                    completeSelf = connectAsyncResult.StartConnect();
                }
#pragma warning suppress 56500 // covered by FxCOP 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    }
                    completeSelf = true;
                    completionException = e;
                } 

                if (completeSelf) 
                { 
                    connectAsyncResult.Complete(false, completionException);
                } 
            }

            bool StartConnect()
            { 
                while (currentIndex < addresses.Length)
                { 
                    if (timeoutHelper.RemainingTime() == TimeSpan.Zero) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
                    }

                    AddressFamily addressFamily = addresses[currentIndex].AddressFamily; 

                    if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6) 
                    { 
                        addresses[currentIndex++] = null; // disregard for exception attempt purposes
                        continue; 
                    }

                    this.connectStartTime = DateTime.UtcNow;
                    try 
                    {
                        IPEndPoint ipEndPoint = new IPEndPoint(addresses[currentIndex], port); 
                        this.socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); 
                        IAsyncResult result = socket.BeginConnect(ipEndPoint, onConnect, this);
                        if (!result.CompletedSynchronously) 
                        {
                            return false;
                        }
 
                        socket.EndConnect(result);
                        return true; 
                    } 
                    catch (SocketException socketException)
                    { 
                        invalidAddressCount++;
                        this.TraceConnectFailure(socketException);
                        lastException = socketException;
                        currentIndex++; 
                    }
                } 
 
                if (socket == null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
                }
 
                DiagnosticUtility.DebugAssert(lastException != null, "StartConnect: Can't get here without an exception.");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    SocketConnectionInitiator.ConvertConnectException(lastException, uri, 
                    timeoutHelper.ElapsedTime(), lastException));
            } 

            void TraceConnectFailure(SocketException exception)
            {
                SocketConnectionInitiator.TraceConnectFailure(this.socket, exception, uri, DateTime.UtcNow - connectStartTime); 
                this.socket.Close();
            } 
 
            static void OnConnect(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                {
                    return;
                } 

                bool completeSelf = false; 
                Exception completionException = null; 
                ConnectAsyncResult thisPtr = (ConnectAsyncResult)result.AsyncState;
                try 
                {
                    thisPtr.socket.EndConnect(result);
                    completeSelf = true;
                } 
                catch (SocketException socketException)
                { 
                    thisPtr.TraceConnectFailure(socketException); 
                    thisPtr.lastException = socketException;
                    thisPtr.currentIndex++; 
                    try
                    {
                        completeSelf = thisPtr.StartConnect();
                    } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                    catch (Exception e) 
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        { 
                            throw;
                        }
                        completeSelf = true;
                        completionException = e; 
                    }
                } 
 
                if (completeSelf)
                { 
                    thisPtr.Complete(false, completionException);
                }
            }
 
            public static Socket End(IAsyncResult result)
            { 
                ConnectAsyncResult thisPtr = AsyncResult.End(result); 
                return thisPtr.socket;
            } 
        }
    }

    internal interface ISocketListenerSettings 
    {
        int BufferSize { get; } 
        bool TeredoEnabled { get; } 
        int ListenBacklog { get; }
    } 

    class SocketConnectionListener : IConnectionListener
    {
        IPEndPoint localEndpoint; 
        bool isDisposed;
        bool isListening; 
        Socket listenSocket; 
        ISocketListenerSettings settings;
        bool useOnlyOverlappedIO; 

        public SocketConnectionListener(Socket listenSocket, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
            : this(settings, useOnlyOverlappedIO)
        { 
            this.listenSocket = listenSocket;
        } 
 
        public SocketConnectionListener(IPEndPoint localEndpoint, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
            : this(settings, useOnlyOverlappedIO) 
        {
            this.localEndpoint = localEndpoint;
        }
 
        SocketConnectionListener(ISocketListenerSettings settings, bool useOnlyOverlappedIO)
        { 
            this.settings = settings; 
            this.useOnlyOverlappedIO = useOnlyOverlappedIO;
        } 

        object ThisLock
        {
            get { return this; } 
        }
 
        public IAsyncResult BeginAccept(AsyncCallback callback, object state) 
        {
            return new AcceptAsyncResult(this, callback, state); 
        }

        IAsyncResult InternalBeginAccept(AsyncCallback callback, object state)
        { 
            lock (ThisLock)
            { 
                if (isDisposed) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(this.GetType().ToString(), SR.GetString(SR.SocketListenerDisposed))); 
                }

                if (!isListening)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SocketListenerNotListening)));
                } 
 
                return listenSocket.BeginAccept(callback, state);
            } 
        }

        Socket InternalEndAccept(IAsyncResult result)
        { 
            Socket socket = null;
            lock (ThisLock) 
            { 
                // unfortunately, a bad design decision in System.Net v1.0 causes
                // EndAccept on a disposed socket to throw ObjectDisposedException 
                // rather than returning null. So we have this check.
                if (!isDisposed)
                {
                    socket = listenSocket.EndAccept(result); 
                }
            } 
 
            return socket;
        } 

        public IConnection EndAccept(IAsyncResult result)
        {
            Socket socket = AcceptAsyncResult.End(result); 

            if (socket == null) 
                return null; 

            if (useOnlyOverlappedIO) 
            {
                socket.UseOnlyOverlappedIO = true;
            }
            return new SocketConnection(socket, settings.BufferSize, false); 
        }
 
        public void Dispose() 
        {
            lock (ThisLock) 
            {
                if (!isDisposed)
                {
                    if (listenSocket != null) 
                    {
                        listenSocket.Close(); 
                    } 

                    isDisposed = true; 
                }
            }
        }
 

        public void Listen() 
        { 
            // If you call listen() on a port, then kill the process, then immediately start a new process and
            // try to listen() on the same port, you sometimes get WSAEADDRINUSE.  Even if nothing was accepted. 
            // Ports don't immediately free themselves on process shutdown.  We call listen() in a loop on a delay
            // for a few iterations for this reason.
            //
            TimeSpan listenTimeout = TimeSpan.FromSeconds(1); 
            BackoffTimeoutHelper backoffHelper = new BackoffTimeoutHelper(listenTimeout);
 
            lock (ThisLock) 
            {
                if (this.listenSocket != null) 
                {
                    this.listenSocket.Listen(settings.ListenBacklog);
                    isListening = true;
                } 

                while (!isListening) 
                { 
                    try
                    { 
                        this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                        if (localEndpoint.AddressFamily == AddressFamily.InterNetworkV6 && settings.TeredoEnabled)
                        { 
                            this.listenSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)23, 10);
                        } 
 
                        this.listenSocket.Bind(localEndpoint);
                        this.listenSocket.Listen(settings.ListenBacklog); 
                        isListening = true;
                    }
                    catch (SocketException socketException)
                    { 
                        bool retry = false;
 
                        if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE) 
                        {
                            if (!backoffHelper.IsExpired()) 
                            {
                                backoffHelper.WaitAndBackoff();
                                retry = true;
                            } 
                        }
 
                        if (!retry) 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                SocketConnectionListener.ConvertListenException(socketException, this.localEndpoint));
                        }
                    }
                } 
            }
        } 
 
        public static Exception ConvertListenException(SocketException socketException, IPEndPoint localEndpoint)
        { 
            if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
            {
                return new CommunicationObjectAbortedException(socketException.Message, socketException);
            } 
            if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE)
            { 
                return new AddressAlreadyInUseException(SR.GetString(SR.TcpAddressInUse, localEndpoint.ToString()), socketException); 
            }
            else 
            {
                return new CommunicationException(
                    SR.GetString(SR.TcpListenError, socketException.ErrorCode, socketException.Message, localEndpoint.ToString()),
                    socketException); 
            }
        } 
 
        class AcceptAsyncResult : AsyncResult
        { 
            SocketConnectionListener listener;
            Socket socket;
            static WaitCallback startAccept;
            static AsyncCallback onAccept = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnAccept)); 

            public AcceptAsyncResult(SocketConnectionListener listener, AsyncCallback callback, object state) 
                : base(callback, state) 
            {
                this.listener = listener; 

                // If we're going to start up the thread pool eventually anyway, avoid using RegisterWaitForSingleObject
                if (!Thread.CurrentThread.IsThreadPoolThread)
                { 
                    if (startAccept == null)
                    { 
                        startAccept = new WaitCallback(StartAccept); 
                    }
 
                    IOThreadScheduler.ScheduleCallback(startAccept, this);
                }
                else
                { 
                    if (StartAccept())
                    { 
                        base.Complete(true); 
                    }
                } 
            }

            static void StartAccept(object state)
            { 
                AcceptAsyncResult thisPtr = (AcceptAsyncResult)state;
 
                Exception completionException = null; 
                bool completeSelf;
                try 
                {
                    completeSelf = thisPtr.StartAccept();
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    }
                    completeSelf = true;
                    completionException = e;
                } 
                if (completeSelf)
                { 
                    thisPtr.Complete(false, completionException); 
                }
            } 

            bool StartAccept()
            {
                while (true) 
                {
                    try 
                    { 
                        IAsyncResult result = listener.InternalBeginAccept(onAccept, this);
 
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        } 

                        this.socket = listener.InternalEndAccept(result); 
                        return true; 
                    }
                    catch (SocketException socketException) 
                    {
                        if (ShouldAcceptRecover(socketException))
                        {
                            continue; 
                        }
                        else 
                        { 
                            throw;
                        } 
                    }
                }
            }
 
            static bool ShouldAcceptRecover(SocketException exception)
            { 
                return ( 
                    (exception.ErrorCode == UnsafeNativeMethods.WSAECONNRESET) ||
                    (exception.ErrorCode == UnsafeNativeMethods.WSAEMFILE) || 
                    (exception.ErrorCode == UnsafeNativeMethods.WSAENOBUFS) ||
                    (exception.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
                );
            } 

            static void OnAccept(IAsyncResult result) 
            { 
                if (result.CompletedSynchronously)
                { 
                    return;
                }

                AcceptAsyncResult thisPtr = (AcceptAsyncResult)result.AsyncState; 

                Exception completionException = null; 
                bool completeSelf = true; 
                try
                { 
                    bool retryAcceptLoop = false;
                    try
                    {
                        thisPtr.socket = thisPtr.listener.InternalEndAccept(result); 
                        completeSelf = true;
                    } 
                    catch (SocketException socketException) 
                    {
                        if (ShouldAcceptRecover(socketException)) 
                        {
                            if (DiagnosticUtility.ShouldTraceWarning)
                            {
                                DiagnosticUtility.ExceptionUtility.TraceHandledException(socketException, TraceEventType.Warning); 
                            }
                            retryAcceptLoop = true; 
                        } 
                        else
                        { 
                            completeSelf = true;
                            completionException = socketException;
                        }
                    } 

                    if (retryAcceptLoop) 
                    { 
                        completeSelf = thisPtr.StartAccept();
                    } 
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw; 
                    }
                    completeSelf = true; 
                    completionException = e;
                }
                if (completeSelf)
                { 
                    thisPtr.Complete(false, completionException);
                } 
            } 

            public static Socket End(IAsyncResult result) 
            {
                AcceptAsyncResult thisPtr = AsyncResult.End(result);
                return thisPtr.socket;
            } 
        }
    } 
} 

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