private async Task CleanupAsync(CancellationToken cancellationToken)
            {
                if (_isForRead)
                {
                    if (Interlocked.CompareExchange(ref _messageSourceCleanState, WebSocketHelper.OperationFinished, WebSocketHelper.OperationNotStarted) == WebSocketHelper.OperationNotStarted)
                    {
                        Exception pendingException = null;
                        try
                        {
                            if (!_endofMessageReceived && (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseSent))
                            {
                                // Drain the reading stream
                                do
                                {
                                    try
                                    {
                                        WebSocketReceiveResult receiveResult = await _webSocket.ReceiveAsync(new ArraySegment <byte>(_initialReadBuffer.Array), cancellationToken);

                                        _endofMessageReceived = receiveResult.EndOfMessage;
                                    }
                                    catch (Exception ex)
                                    {
                                        if (Fx.IsFatal(ex))
                                        {
                                            throw;
                                        }

                                        WebSocketHelper.ThrowCorrectException(ex, TimeoutHelper.GetOriginalTimeout(cancellationToken), WebSocketHelper.ReceiveOperation);
                                    }
                                }while (!_endofMessageReceived && (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseSent));
                            }
                        }
                        catch (Exception ex)
                        {
                            if (Fx.IsFatal(ex))
                            {
                                throw;
                            }

                            // Not throwing out this exception during stream cleanup. The exception
                            // will be thrown out when we are trying to receive the next message using the same
                            // WebSocket object.
                            pendingException = WebSocketHelper.ConvertAndTraceException(ex, TimeoutHelper.GetOriginalTimeout(cancellationToken), WebSocketHelper.CloseOperation);
                        }

                        _bufferManager.ReturnBuffer(_initialReadBuffer.Array);
                        Fx.Assert(_messageSource != null, "messageSource should not be null.");
                        _messageSource.FinishUsingMessageStream(pendingException);
                    }
                }
                else
                {
                    if (Interlocked.CompareExchange(ref _endOfMessageWritten, WebSocketHelper.OperationFinished, WebSocketHelper.OperationNotStarted) == WebSocketHelper.OperationNotStarted)
                    {
                        await WriteEndOfMessageAsync(cancellationToken);
                    }
                }
            }
        private Task CloseOutputImplAsync(CancellationToken cancellationToken)
        {
            try
            {
                return(WebSocket.CloseOutputAsync(_webSocketCloseDetails.OutputCloseStatus, _webSocketCloseDetails.OutputCloseStatusDescription, cancellationToken));
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                throw WebSocketHelper.ConvertAndTraceException(e);
            }
        }
            private async void StartNextReceiveAsync()
            {
                Fx.Assert(_receiveTask == null || _receiveTask.Task.IsCompleted, "this.receiveTask is not completed.");
                _receiveTask = new TaskCompletionSource <object>();
                int currentState = Interlocked.CompareExchange(ref _asyncReceiveState, AsyncReceiveState.Started, AsyncReceiveState.Finished);

                Fx.Assert(currentState == AsyncReceiveState.Finished, "currentState is not AsyncReceiveState.Finished: " + currentState);
                if (currentState != AsyncReceiveState.Finished)
                {
                    throw Fx.Exception.AsError(new InvalidOperationException());
                }

                try
                {
                    if (_useStreaming)
                    {
                        if (_streamWaitTask != null)
                        {
                            //// Wait until the previous stream message finished.

                            await _streamWaitTask.Task.ConfigureAwait(false);
                        }

                        _streamWaitTask = new TaskCompletionSource <object>();
                    }

                    if (_pendingException == null)
                    {
                        if (!_useStreaming)
                        {
                            await ReadBufferedMessageAsync().ConfigureAwait(false);
                        }
                        else
                        {
                            byte[] buffer  = _bufferManager.TakeBuffer(_receiveBufferSize);
                            bool   success = false;
                            try
                            {
                                //if (TD.WebSocketAsyncReadStartIsEnabled())
                                //{
                                //    TD.WebSocketAsyncReadStart(this.webSocket.GetHashCode());
                                //}

                                try
                                {
                                    Task <WebSocketReceiveResult> receiveTask = _webSocket.ReceiveAsync(
                                        new ArraySegment <byte>(buffer, 0, _receiveBufferSize),
                                        CancellationToken.None);

                                    await receiveTask.ConfigureAwait(false);

                                    WebSocketReceiveResult result = receiveTask.Result;
                                    CheckCloseStatus(result);
                                    _pendingMessage = await PrepareMessageAsync(result, buffer, result.Count);

                                    //if (TD.WebSocketAsyncReadStopIsEnabled())
                                    //{
                                    //    TD.WebSocketAsyncReadStop(
                                    //        this.webSocket.GetHashCode(),
                                    //        result.Count,
                                    //        TraceUtility.GetRemoteEndpointAddressPort(this.remoteEndpointMessageProperty));
                                    //}
                                }
                                catch (AggregateException ex)
                                {
                                    WebSocketHelper.ThrowCorrectException(ex, _asyncReceiveTimeout, WebSocketHelper.ReceiveOperation);
                                }
                                success = true;
                            }
                            catch (Exception ex)
                            {
                                if (Fx.IsFatal(ex))
                                {
                                    throw;
                                }

                                _pendingException = WebSocketHelper.ConvertAndTraceException(ex, _asyncReceiveTimeout, WebSocketHelper.ReceiveOperation);
                            }
                            finally
                            {
                                if (!success)
                                {
                                    _bufferManager.ReturnBuffer(buffer);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    if (Interlocked.CompareExchange(ref _asyncReceiveState, AsyncReceiveState.Finished, AsyncReceiveState.Started) == AsyncReceiveState.Started)
                    {
                        _receiveTask.SetResult(null);
                    }
                }
            }
            private async Task ReadBufferedMessageAsync()
            {
                byte[] internalBuffer = null;
                try
                {
                    internalBuffer = _bufferManager.TakeBuffer(_receiveBufferSize);

                    int  receivedByteCount        = 0;
                    bool endOfMessage             = false;
                    WebSocketReceiveResult result = null;
                    do
                    {
                        try
                        {
                            //if (TD.WebSocketAsyncReadStartIsEnabled())
                            //{
                            //    TD.WebSocketAsyncReadStart(this.webSocket.GetHashCode());
                            //}

                            Task <WebSocketReceiveResult> receiveTask = _webSocket.ReceiveAsync(
                                new ArraySegment <byte>(internalBuffer, receivedByteCount, internalBuffer.Length - receivedByteCount),
                                CancellationToken.None);

                            await receiveTask.ConfigureAwait(false);

                            result = receiveTask.Result;
                            CheckCloseStatus(result);
                            endOfMessage = result.EndOfMessage;

                            receivedByteCount += result.Count;
                            if (receivedByteCount >= internalBuffer.Length && !result.EndOfMessage)
                            {
                                if (internalBuffer.Length >= _maxBufferSize)
                                {
                                    _pendingException = Fx.Exception.AsError(new QuotaExceededException(SR.Format(SR.MaxReceivedMessageSizeExceeded, _maxBufferSize)));
                                    return;
                                }

                                int newSize = (int)Math.Min(((double)internalBuffer.Length) * 2, _maxBufferSize);
                                Fx.Assert(newSize > 0, "buffer size should be larger than zero.");
                                byte[] newBuffer = _bufferManager.TakeBuffer(newSize);
                                Buffer.BlockCopy(internalBuffer, 0, newBuffer, 0, receivedByteCount);
                                _bufferManager.ReturnBuffer(internalBuffer);
                                internalBuffer = newBuffer;
                            }

                            //if (TD.WebSocketAsyncReadStopIsEnabled())
                            //{
                            //    TD.WebSocketAsyncReadStop(
                            //        this.webSocket.GetHashCode(),
                            //        receivedByteCount,
                            //        TraceUtility.GetRemoteEndpointAddressPort(this.RemoteEndpointMessageProperty));
                            //}
                        }
                        catch (AggregateException ex)
                        {
                            WebSocketHelper.ThrowCorrectException(ex, TimeSpan.MaxValue, WebSocketHelper.ReceiveOperation);
                        }
                    }while (!endOfMessage && !_closureReceived);

                    byte[] buffer  = null;
                    bool   success = false;
                    try
                    {
                        buffer = _bufferManager.TakeBuffer(receivedByteCount);
                        Buffer.BlockCopy(internalBuffer, 0, buffer, 0, receivedByteCount);
                        Fx.Assert(result != null, "Result should not be null");
                        _pendingMessage = await PrepareMessageAsync(result, buffer, receivedByteCount);

                        success = true;
                    }
                    finally
                    {
                        if (buffer != null && (!success || _pendingMessage == null))
                        {
                            _bufferManager.ReturnBuffer(buffer);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex))
                    {
                        throw;
                    }

                    _pendingException = WebSocketHelper.ConvertAndTraceException(ex, TimeSpan.MaxValue, WebSocketHelper.ReceiveOperation);
                }
                finally
                {
                    if (internalBuffer != null)
                    {
                        _bufferManager.ReturnBuffer(internalBuffer);
                    }
                }
            }