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