public Task MultipleWriteAsync(IList <ArraySegment <byte> > sendBuffers,
                                           CancellationToken cancellationToken)
            {
                Contract.Assert(this.SupportsMultipleWrite, "This method MUST NOT be used for custom NetworkStream implementations.");

                if (!m_InOpaqueMode)
                {
                    // We can't use fast path over SSL
                    return(Task.Factory.FromAsync <IList <ArraySegment <byte> > >(s_BeginMultipleWrite, s_EndMultipleWrite,
                                                                                  sendBuffers, this));
                }

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Enter(Logging.WebSockets, this, Methods.MultipleWriteAsync, string.Empty);
                }

                bool completedAsynchronously = false;

                try
                {
                    cancellationToken.ThrowIfCancellationRequested();
#if DEBUG
                    // When using fast path only one outstanding read is permitted. By switching into opaque mode
                    // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
                    // caller takes responsibility for enforcing this constraint.
                    Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1,
                                    "Only one outstanding write allowed at any given time.");
#endif
                    WebSocketHelpers.ThrowIfConnectionAborted(m_InnerStream, false);
                    m_WriteTaskCompletionSource = new TaskCompletionSource <object>();
                    m_WriteEventArgs.SetBuffer(null, 0, 0);
                    m_WriteEventArgs.BufferList = sendBuffers;
                    completedAsynchronously     = InnerSocket.SendAsync(m_WriteEventArgs);
                    if (!completedAsynchronously)
                    {
                        if (m_WriteEventArgs.SocketError != SocketError.Success)
                        {
                            throw new SocketException(m_WriteEventArgs.SocketError);
                        }

                        return(Task.CompletedTask);
                    }

                    return(m_WriteTaskCompletionSource.Task);
                }
                finally
                {
                    if (WebSocketBase.LoggingEnabled)
                    {
                        Logging.Exit(Logging.WebSockets, this, Methods.MultipleWriteAsync, completedAsynchronously);
                    }
                }
            }
            private static void EndMultipleWrite(IAsyncResult asyncResult)
            {
                Contract.Assert(asyncResult != null, "'asyncResult' MUST NOT be NULL.");
                Contract.Assert(asyncResult.AsyncState != null, "'asyncResult.AsyncState' MUST NOT be NULL.");
                WebSocketConnection connection = asyncResult.AsyncState as WebSocketConnection;

                Contract.Assert(connection != null, "'connection' MUST NOT be NULL.");

                WebSocketHelpers.ThrowIfConnectionAborted(connection.m_InnerStream, false);
                connection.m_InnerStream.NetworkStream.EndMultipleWrite(asyncResult);
            }
            public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
            {
                WebSocketHelpers.ValidateBuffer(buffer, offset, count);

                if (!m_InOpaqueMode)
                {
                    return(base.WriteAsync(buffer, offset, count, cancellationToken));
                }

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Enter(Logging.WebSockets, this, Methods.WriteAsync,
                                  WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken));
                }

                bool completedAsynchronously = false;

                try
                {
                    cancellationToken.ThrowIfCancellationRequested();
#if DEBUG
                    // When using fast path only one outstanding read is permitted. By switching into opaque mode
                    // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
                    // caller takes responsibility for enforcing this constraint.
                    Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1,
                                    "Only one outstanding write allowed at any given time.");
#endif
                    WebSocketHelpers.ThrowIfConnectionAborted(m_InnerStream, false);
                    m_WriteTaskCompletionSource = new TaskCompletionSource <object>();
                    m_WriteEventArgs.BufferList = null;
                    m_WriteEventArgs.SetBuffer(buffer, offset, count);
                    completedAsynchronously = InnerSocket.SendAsync(m_WriteEventArgs);
                    if (!completedAsynchronously)
                    {
                        if (m_WriteEventArgs.SocketError != SocketError.Success)
                        {
                            throw new SocketException(m_WriteEventArgs.SocketError);
                        }

                        return(Task.CompletedTask);
                    }

                    return(m_WriteTaskCompletionSource.Task);
                }
                finally
                {
                    if (WebSocketBase.LoggingEnabled)
                    {
                        Logging.Exit(Logging.WebSockets, this, Methods.WriteAsync, completedAsynchronously);
                    }
                }
            }
        public async override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, this, Methods.ReadAsync,
                              WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken));
            }

            CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration();

            int bytesRead = 0;

            try
            {
                if (cancellationToken.CanBeCanceled)
                {
                    cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false);
                }

                WebSocketHelpers.ThrowIfConnectionAborted(m_ConnectStream.Connection, true);
                bytesRead = await base.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow <int>();

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Dump(Logging.WebSockets, this, Methods.ReadAsync, buffer, offset, bytesRead);
                }
            }
            catch (Exception error)
            {
                if (s_CanHandleException(error))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                throw;
            }
            finally
            {
                cancellationTokenRegistration.Dispose();

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Exit(Logging.WebSockets, this, Methods.ReadAsync, bytesRead);
                }
            }

            return(bytesRead);
        }
        public async Task MultipleWriteAsync(IList <ArraySegment <byte> > sendBuffers, CancellationToken cancellationToken)
        {
            Contract.Assert(this.SupportsMultipleWrite, "This method MUST NOT be used for custom NetworkStream implementations.");

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, this, Methods.MultipleWriteAsync, string.Empty);
            }
            CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration();

            try
            {
                if (cancellationToken.CanBeCanceled)
                {
                    cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false);
                }

                WebSocketHelpers.ThrowIfConnectionAborted(m_ConnectStream.Connection, false);
                await((WebSocketBase.IWebSocketStream)base.BaseStream).MultipleWriteAsync(sendBuffers, cancellationToken).SuppressContextFlow();

                if (WebSocketBase.LoggingEnabled)
                {
                    foreach (ArraySegment <byte> buffer in sendBuffers)
                    {
                        Logging.Dump(Logging.WebSockets, this, Methods.MultipleWriteAsync, buffer.Array, buffer.Offset, buffer.Count);
                    }
                }
            }
            catch (Exception error)
            {
                if (s_CanHandleException(error))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                throw;
            }
            finally
            {
                cancellationTokenRegistration.Dispose();

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Exit(Logging.WebSockets, this, Methods.MultipleWriteAsync, string.Empty);
                }
            }
        }
            private static IAsyncResult BeginMultipleWrite(IList <ArraySegment <byte> > sendBuffers, AsyncCallback callback, object asyncState)
            {
                Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL.");
                Contract.Assert(asyncState != null, "'asyncState' MUST NOT be NULL.");
                WebSocketConnection connection = asyncState as WebSocketConnection;

                Contract.Assert(connection != null, "'connection' MUST NOT be NULL.");

                BufferOffsetSize[] buffers = new BufferOffsetSize[sendBuffers.Count];

                for (int index = 0; index < sendBuffers.Count; index++)
                {
                    ArraySegment <byte> sendBuffer = sendBuffers[index];
                    buffers[index] = new BufferOffsetSize(sendBuffer.Array, sendBuffer.Offset, sendBuffer.Count, false);
                }

                WebSocketHelpers.ThrowIfConnectionAborted(connection.m_InnerStream, false);
                return(connection.m_InnerStream.NetworkStream.BeginMultipleWrite(buffers, callback, asyncState));
            }
        public async Task CloseNetworkConnectionAsync(CancellationToken cancellationToken)
        {
            // need to yield here to make sure that we don't get any exception synchronously
            await Task.Yield();

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, string.Empty);
            }

            CancellationTokenSource reasonableTimeoutCancellationTokenSource = null;
            CancellationTokenSource linkedCancellationTokenSource            = null;
            CancellationToken       linkedCancellationToken = CancellationToken.None;

            CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration();

            int bytesRead = 0;

            try
            {
                reasonableTimeoutCancellationTokenSource =
                    new CancellationTokenSource(WebSocketHelpers.ClientTcpCloseTimeout);
                linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
                    reasonableTimeoutCancellationTokenSource.Token,
                    cancellationToken);
                linkedCancellationToken       = linkedCancellationTokenSource.Token;
                cancellationTokenRegistration = linkedCancellationToken.Register(s_OnCancel, this, false);

                WebSocketHelpers.ThrowIfConnectionAborted(m_ConnectStream.Connection, true);
                byte[] buffer = new byte[1];
                if (m_WebSocketConnection != null && m_InOpaqueMode)
                {
                    bytesRead = await m_WebSocketConnection.ReadAsyncCore(buffer, 0, 1, linkedCancellationToken, true).SuppressContextFlow <int>();
                }
                else
                {
                    bytesRead = await base.ReadAsync(buffer, 0, 1, linkedCancellationToken).SuppressContextFlow <int>();
                }

                if (bytesRead != 0)
                {
                    Contract.Assert(false, "'bytesRead' MUST be '0' at this point. Instead more payload was received ('" + buffer[0].ToString() + "')");

                    if (WebSocketBase.LoggingEnabled)
                    {
                        Logging.Dump(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, buffer, 0, bytesRead);
                    }

                    throw new WebSocketException(WebSocketError.NotAWebSocket);
                }
            }
            catch (Exception error)
            {
                if (!s_CanHandleException(error))
                {
                    throw;
                }

                // throw OperationCancelledException when canceled by the caller
                // ignore cancellation due to the timeout
                cancellationToken.ThrowIfCancellationRequested();
            }
            finally
            {
                cancellationTokenRegistration.Dispose();
                if (linkedCancellationTokenSource != null)
                {
                    linkedCancellationTokenSource.Dispose();
                }

                if (reasonableTimeoutCancellationTokenSource != null)
                {
                    reasonableTimeoutCancellationTokenSource.Dispose();
                }

                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Exit(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, bytesRead);
                }
            }
        }
            internal Task <int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken,
                                              bool ignoreReadError)
            {
                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncCore,
                                  WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken));
                }

                bool completedAsynchronously = false;

                m_IgnoreReadError = ignoreReadError;
                try
                {
                    cancellationToken.ThrowIfCancellationRequested();
#if DEBUG
                    // When using fast path only one outstanding read is permitted. By switching into opaque mode
                    // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
                    // caller takes responsibility for enforcing this constraint.
                    Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Reads) == 1,
                                    "Only one outstanding read allowed at any given time.");
#endif
                    WebSocketHelpers.ThrowIfConnectionAborted(m_InnerStream, true);
                    m_ReadTaskCompletionSource = new TaskCompletionSource <int>();
                    Contract.Assert(m_ReadEventArgs != null, "'m_ReadEventArgs' MUST NOT be NULL.");
                    m_ReadEventArgs.SetBuffer(buffer, offset, count);
                    Socket innerSocket;
                    if (ignoreReadError)
                    {
                        // The State of the WebSocket instance is already Closed at this point
                        // Skipping call to WebSocketBase.ThrowIfClosedOrAborted
                        innerSocket = GetInnerSocket(true);
                    }
                    else
                    {
                        innerSocket = InnerSocket;
                    }
                    completedAsynchronously = innerSocket.ReceiveAsync(m_ReadEventArgs);
                    if (!completedAsynchronously)
                    {
                        if (m_ReadEventArgs.SocketError != SocketError.Success)
                        {
                            if (!m_IgnoreReadError)
                            {
                                throw new SocketException(m_ReadEventArgs.SocketError);
                            }
                            else
                            {
                                return(Task.FromResult <int>(0));
                            }
                        }

                        return(Task.FromResult <int>(m_ReadEventArgs.BytesTransferred));
                    }

                    return(m_ReadTaskCompletionSource.Task);
                }
                finally
                {
                    if (WebSocketBase.LoggingEnabled)
                    {
                        Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncCore, completedAsynchronously);
                    }
                }
            }