private static void OnRequestError( WinHttpWebSocketState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult) { Debug.Assert(state != null, "OnRequestError: state is null"); var innerException = WinHttpException.CreateExceptionUsingError((int)asyncResult.dwError); switch ((uint)asyncResult.dwResult.ToInt32()) { case Interop.WinHttp.API_SEND_REQUEST: case Interop.WinHttp.API_RECEIVE_RESPONSE: { var exception = new WebSocketException(SR.net_webstatus_ConnectFailure, innerException); state.UpdateState(WebSocketState.Closed); state.TcsUpgrade.TrySetException(exception); } break; default: { Debug.Fail( "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.", "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")"); } break; } }
// Requires lock taken. private Interop.WinHttp.SafeWinHttpHandle InitializeWinHttp(ClientWebSocketOptions options) { Interop.WinHttp.SafeWinHttpHandle sessionHandle; sessionHandle = Interop.WinHttp.WinHttpOpen( IntPtr.Zero, Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, null, null, (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC); ThrowOnInvalidHandle(sessionHandle); uint optionAssuredNonBlockingTrue = 1; // TRUE if (!Interop.WinHttp.WinHttpSetOption( sessionHandle, Interop.WinHttp.WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS, ref optionAssuredNonBlockingTrue, (uint)Marshal.SizeOf <uint>())) { WinHttpException.ThrowExceptionUsingLastError(); } return(sessionHandle); }
private static void OnWebSocketError( WinHttpWebSocketState state, Interop.WinHttp.WINHTTP_WEB_SOCKET_ASYNC_RESULT asyncResult) { Debug.Assert(state != null, "OnWebSocketError: state is null"); var innerException = WinHttpException.CreateExceptionUsingError((int)(asyncResult.AsyncResult.dwError)); if (asyncResult.AsyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED) { var exception = new WebSocketException( WebSocketError.InvalidState, SR.Format( SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted"), innerException); state.UpdateState(WebSocketState.Aborted); if (state.TcsReceive != null) { state.TcsReceive.TrySetException(exception); } if (state.TcsSend != null) { state.TcsSend.TrySetException(exception); } return; } switch (asyncResult.Operation) { case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_SEND_OPERATION: state.PendingWriteOperation = false; state.TcsSend.TrySetException(innerException); break; case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_RECEIVE_OPERATION: state.PendingReadOperation = false; state.TcsReceive.TrySetException(innerException); break; case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_CLOSE_OPERATION: state.TcsClose.TrySetException(innerException); break; case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION: state.TcsCloseOutput.TrySetException(innerException); break; default: Debug.Fail( "OnWebSocketError: Operation (" + asyncResult.Operation + ") is not expected.", "Error code: " + asyncResult.AsyncResult.dwError + " (" + innerException.Message + ")"); break; } }
private void UpdateServerCloseStatus() { uint ret; ushort serverStatus; var closeDescription = new byte[WebSocketValidate.MaxControlFramePayloadLength]; uint closeDescriptionConsumed; lock (_operation.Lock) { ret = Interop.WinHttp.WinHttpWebSocketQueryCloseStatus( _operation.WebSocketHandle, out serverStatus, closeDescription, (uint)closeDescription.Length, out closeDescriptionConsumed); if (ret != Interop.WinHttp.ERROR_SUCCESS) { throw WinHttpException.CreateExceptionUsingError((int)ret); } _closeStatus = (WebSocketCloseStatus)serverStatus; _closeStatusDescription = Encoding.UTF8.GetString(closeDescription, 0, (int)closeDescriptionConsumed); } }
private void AddRequestHeaders(Uri uri, ClientWebSocketOptions options) { var requestHeadersBuffer = new StringBuilder(); // Manually add cookies. if (options.Cookies != null) { string cookieHeader = GetCookieHeader(uri, options.Cookies); if (!string.IsNullOrEmpty(cookieHeader)) { requestHeadersBuffer.AppendLine(cookieHeader); } } // Serialize general request headers. requestHeadersBuffer.AppendLine(options.RequestHeaders.ToString()); var subProtocols = options.RequestedSubProtocols; if (subProtocols.Count > 0) { requestHeadersBuffer.AppendLine(string.Format("{0}: {1}", HeaderNameWebSocketProtocol, string.Join(", ", subProtocols))); } // Add request headers to WinHTTP request handle. if (!Interop.WinHttp.WinHttpAddRequestHeaders( _operation.RequestHandle, requestHeadersBuffer, (uint)requestHeadersBuffer.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD)) { WinHttpException.ThrowExceptionUsingLastError(); } }
public override Task SendAsync( ArraySegment <byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { _operation.InterlockedCheckValidStates(s_validSendStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { var bufferType = WebSocketMessageTypeAdapter.GetWinHttpMessageType(messageType, endOfMessage); _operation.PinSendBuffer(buffer); bool sendOperationAlreadyPending = false; if (_operation.PendingWriteOperation == false) { lock (_operation.Lock) { _operation.CheckValidState(s_validSendStates); if (_operation.PendingWriteOperation == false) { _operation.PendingWriteOperation = true; _operation.TcsSend = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); uint ret = Interop.WinHttp.WinHttpWebSocketSend( _operation.WebSocketHandle, bufferType, buffer.Count > 0 ? Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset) : IntPtr.Zero, (uint)buffer.Count); if (Interop.WinHttp.ERROR_SUCCESS != ret) { throw WinHttpException.CreateExceptionUsingError((int)ret); } } else { sendOperationAlreadyPending = true; } } } else { sendOperationAlreadyPending = true; } if (sendOperationAlreadyPending) { var exception = new InvalidOperationException( SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "SendAsync")); _operation.TcsSend.TrySetException(exception); Abort(); } return(_operation.TcsSend.Task); } }
private void ThrowOnInvalidHandle(Interop.WinHttp.SafeWinHttpHandle value) { if (value.IsInvalid) { Abort(); throw new WebSocketException( SR.net_webstatus_ConnectFailure, WinHttpException.CreateExceptionUsingLastError()); } }
private Task <bool> InternalReceiveAsync(ArraySegment <byte> buffer) { bool receiveOperationAlreadyPending = false; if (_operation.PendingReadOperation == false) { lock (_operation.Lock) { if (_operation.PendingReadOperation == false) { _operation.CheckValidState(s_validReceiveStates); // Prevent continuations from running on the same thread as the callback to prevent re-entrance deadlocks _operation.TcsReceive = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); _operation.PendingReadOperation = true; uint bytesRead = 0; Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE winHttpBufferType = 0; uint status = Interop.WinHttp.WinHttpWebSocketReceive( _operation.WebSocketHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset), (uint)buffer.Count, out bytesRead, // Unused in async mode: ignore. out winHttpBufferType); // Unused in async mode: ignore. if (Interop.WinHttp.ERROR_SUCCESS != status) { throw WinHttpException.CreateExceptionUsingError((int)status); } } else { receiveOperationAlreadyPending = true; } } } else { receiveOperationAlreadyPending = true; } if (receiveOperationAlreadyPending) { var exception = new InvalidOperationException( SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "ReceiveAsync")); _operation.TcsReceive.TrySetException(exception); Abort(); } return(_operation.TcsReceive.Task); }
private static void OnWebSocketSecureFailure(WinHttpWebSocketState state, uint flags) { Debug.Assert(state != null, "OnWebSocketSecureFailure: state is null"); var innerException = WinHttpException.CreateExceptionUsingError((int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE); var exception = new WebSocketException(WebSocketError.ConnectionClosedPrematurely, innerException); // TODO (Issue 2509): handle SSL related exceptions. state.UpdateState(WebSocketState.Aborted); // TODO (Issue 2509): Create exception from WINHTTP_CALLBACK_STATUS_SECURE_FAILURE flags. state.TcsUpgrade.TrySetException(exception); }
private static void OnRequestSecureFailure(WinHttpWebSocketState state, uint flags) { Debug.Assert(state != null, "OnRequestSecureFailure: state is null"); var innerException = WinHttpException.CreateExceptionUsingError((int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE); var exception = new WebSocketException( WebSocketError.Success, SR.net_webstatus_ConnectFailure, innerException); // TODO: handle SSL related exceptions. state.UpdateState(WebSocketState.Closed); // TODO: Create exception from WINHTTP_CALLBACK_STATUS_SECURE_FAILURE flags. state.TcsUpgrade.TrySetException(exception); }
private Task <bool> InternalReceiveWsUpgradeResponse() { // TODO (Issue 2507): Potential optimization: move this in WinHttpWebSocketCallback. lock (_operation.Lock) { ThrowOnInvalidConnectState(); _operation.TcsUpgrade = new TaskCompletionSource <bool>(); if (!Interop.WinHttp.WinHttpReceiveResponse(_operation.RequestHandle, IntPtr.Zero)) { WinHttpException.ThrowExceptionUsingLastError(); } } return(_operation.TcsUpgrade.Task); }
private unsafe string GetResponseHeader(string headerName, char[] buffer = null) { const int StackLimit = 128; Debug.Assert(buffer == null || (buffer != null && buffer.Length > StackLimit)); int bufferLength; if (buffer == null) { bufferLength = StackLimit; char *pBuffer = stackalloc char[bufferLength]; if (QueryHeaders(headerName, pBuffer, ref bufferLength)) { return(new string(pBuffer, 0, bufferLength)); } } else { bufferLength = buffer.Length; fixed(char *pBuffer = buffer) { if (QueryHeaders(headerName, pBuffer, ref bufferLength)) { return(new string(pBuffer, 0, bufferLength)); } } } int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { return(null); } if (lastError == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { buffer = new char[bufferLength]; return(GetResponseHeader(headerName, buffer)); } throw WinHttpException.CreateExceptionUsingError(lastError); }
private string GetResponseHeaderStringInfo(string headerName) { uint bytesNeeded = 0; bool results = false; // Call WinHttpQueryHeaders once to obtain the size of the buffer needed. The size is returned in // bytes but the API actually returns Unicode characters. if (!Interop.WinHttp.WinHttpQueryHeaders( _operation.RequestHandle, Interop.WinHttp.WINHTTP_QUERY_CUSTOM, headerName, null, ref bytesNeeded, IntPtr.Zero)) { int lastError = Marshal.GetLastWin32Error(); if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND) { return(null); } if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER) { throw WinHttpException.CreateExceptionUsingError(lastError); } } int charsNeeded = (int)bytesNeeded / sizeof(char); var buffer = new StringBuilder(charsNeeded, charsNeeded); results = Interop.WinHttp.WinHttpQueryHeaders( _operation.RequestHandle, Interop.WinHttp.WINHTTP_QUERY_CUSTOM, headerName, buffer, ref bytesNeeded, IntPtr.Zero); if (!results) { WinHttpException.ThrowExceptionUsingLastError(); } return(buffer.ToString()); }
public override Task CloseOutputAsync( WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) { _operation.InterlockedCheckAndUpdateState(WebSocketState.CloseSent, s_validCloseOutputStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { lock (_operation.Lock) { _operation.CheckValidState(s_validCloseOutputStatesAfterUpdate); uint ret; _operation.TcsCloseOutput = new TaskCompletionSource <bool>(); if (!string.IsNullOrEmpty(statusDescription)) { byte[] statusDescriptionBuffer = Encoding.UTF8.GetBytes(statusDescription); ret = Interop.WinHttp.WinHttpWebSocketShutdown( _operation.WebSocketHandle, (ushort)closeStatus, statusDescriptionBuffer, (uint)statusDescriptionBuffer.Length); } else { ret = Interop.WinHttp.WinHttpWebSocketShutdown( _operation.WebSocketHandle, (ushort)closeStatus, IntPtr.Zero, 0); } if (ret != Interop.WinHttp.ERROR_SUCCESS) { throw WinHttpException.CreateExceptionUsingError((int)ret); } } return(_operation.TcsCloseOutput.Task); } }
private HttpStatusCode GetHttpStatusCode() { uint infoLevel = Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE | Interop.WinHttp.WINHTTP_QUERY_FLAG_NUMBER; uint result = 0; uint resultSize = sizeof(uint); if (!Interop.WinHttp.WinHttpQueryHeaders( _operation.RequestHandle, infoLevel, Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX, ref result, ref resultSize, IntPtr.Zero)) { WinHttpException.ThrowExceptionUsingLastError(); } return((HttpStatusCode)result); }
private Task <bool> InternalSendWsUpgradeRequestAsync() { lock (_operation.Lock) { ThrowOnInvalidConnectState(); if (!Interop.WinHttp.WinHttpSendRequest( _operation.RequestHandle, Interop.WinHttp.WINHTTP_NO_ADDITIONAL_HEADERS, 0, IntPtr.Zero, 0, 0, _operation.ToIntPtr())) { WinHttpException.ThrowExceptionUsingLastError(); } } return(_operation.TcsUpgrade.Task); }
private void AddRequestHeaders(Uri uri, ClientWebSocketOptions options) { var requestHeadersBuffer = new StringBuilder(); // Manually add cookies. if (options.Cookies != null) { AppendCookieHeaderLine(uri, options.Cookies, requestHeadersBuffer); } // Serialize general request headers. requestHeadersBuffer.AppendLine(options.RequestHeaders.ToString()); using (List <string> .Enumerator e = options.RequestedSubProtocols.GetEnumerator()) { if (e.MoveNext()) { requestHeadersBuffer.Append(HeaderNameWebSocketProtocol + ": "); requestHeadersBuffer.Append(e.Current); while (e.MoveNext()) { requestHeadersBuffer.Append(", "); requestHeadersBuffer.Append(e.Current); } requestHeadersBuffer.AppendLine(); } } // Add request headers to WinHTTP request handle. if (!Interop.WinHttp.WinHttpAddRequestHeaders( _operation.RequestHandle, requestHeadersBuffer, (uint)requestHeadersBuffer.Length, Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD)) { WinHttpException.ThrowExceptionUsingLastError(); } }
private Task <bool> InternalCloseAsync(WebSocketCloseStatus closeStatus, string statusDescription) { uint ret; _operation.TcsClose = new TaskCompletionSource <bool>(); lock (_operation.Lock) { _operation.CheckValidState(s_validCloseStates); if (!string.IsNullOrEmpty(statusDescription)) { byte[] statusDescriptionBuffer = Encoding.UTF8.GetBytes(statusDescription); ret = Interop.WinHttp.WinHttpWebSocketClose( _operation.WebSocketHandle, (ushort)closeStatus, statusDescriptionBuffer, (uint)statusDescriptionBuffer.Length); } else { ret = Interop.WinHttp.WinHttpWebSocketClose( _operation.WebSocketHandle, (ushort)closeStatus, IntPtr.Zero, 0); } if (ret != Interop.WinHttp.ERROR_SUCCESS) { throw WinHttpException.CreateExceptionUsingError((int)ret); } } return(_operation.TcsClose.Task); }
private Task <bool> InternalReceiveAsync(Memory <byte> pinnedBuffer) { bool receiveOperationAlreadyPending = false; if (_operation.PendingReadOperation == false) { lock (_operation.Lock) { if (_operation.PendingReadOperation == false) { _operation.CheckValidState(s_validReceiveStates); // Prevent continuations from running on the same thread as the callback to prevent re-entrance deadlocks _operation.TcsReceive = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); _operation.PendingReadOperation = true; uint bytesRead = 0; Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE winHttpBufferType = 0; IntPtr pinnedBufferPtr; unsafe { fixed(byte *p = &pinnedBuffer.Span.DangerousGetPinnableReference()) { pinnedBufferPtr = (IntPtr)p; } } uint status = Interop.WinHttp.WinHttpWebSocketReceive( _operation.WebSocketHandle, pinnedBufferPtr, (uint)pinnedBuffer.Length, out bytesRead, // Unused in async mode: ignore. out winHttpBufferType); // Unused in async mode: ignore. if (Interop.WinHttp.ERROR_SUCCESS != status) { throw WinHttpException.CreateExceptionUsingError((int)status); } } else { receiveOperationAlreadyPending = true; } } } else { receiveOperationAlreadyPending = true; } if (receiveOperationAlreadyPending) { var exception = new InvalidOperationException( SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "ReceiveAsync")); _operation.TcsReceive.TrySetException(exception); Abort(); } return(_operation.TcsReceive.Task); }
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { lock (_operation.Lock) { _operation.CheckValidState(s_validConnectingStates); // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort. // // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the // state is still valid to continue operation. _operation.SessionHandle = InitializeWinHttp(options); _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback( _operation.SessionHandle, uri.IdnHost, (ushort)uri.Port, 0); ThrowOnInvalidHandle(_operation.ConnectionHandle); bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss; _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback( _operation.ConnectionHandle, "GET", uri.PathAndQuery, null, Interop.WinHttp.WINHTTP_NO_REFERER, null, secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0); ThrowOnInvalidHandle(_operation.RequestHandle); _operation.IncrementHandlesOpenWithCallback(); if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, IntPtr.Zero, 0)) { WinHttpException.ThrowExceptionUsingLastError(); } // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } const uint notificationFlags = Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | Interop.WinHttp.WINHTTP_CALLBACK_FLAG_HANDLES | Interop.WinHttp.WINHTTP_CALLBACK_FLAG_SECURE_FAILURE; if (Interop.WinHttp.WinHttpSetStatusCallback( _operation.RequestHandle, WinHttpWebSocketCallback.s_StaticCallbackDelegate, notificationFlags, IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.RequestHandle.AttachCallback(); // We need to pin the operation object at this point in time since the WinHTTP callback // has been fully wired to the request handle and the operation object has been set as // the context value of the callback. Any notifications from activity on the handle will // result in the callback being called with the context value. _operation.Pin(); AddRequestHeaders(uri, options); _operation.TcsUpgrade = new TaskCompletionSource <bool>(); } await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false); await InternalReceiveWsUpgradeResponse().ConfigureAwait(false); lock (_operation.Lock) { VerifyUpgradeResponse(); ThrowOnInvalidConnectState(); _operation.WebSocketHandle = Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero); ThrowOnInvalidHandle(_operation.WebSocketHandle); _operation.IncrementHandlesOpenWithCallback(); // We need the address of the IntPtr to the GCHandle. IntPtr context = _operation.ToIntPtr(); IntPtr contextAddress; unsafe { contextAddress = (IntPtr)(void *)&context; } if (!Interop.WinHttp.WinHttpSetOption( _operation.WebSocketHandle, Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE, contextAddress, (uint)IntPtr.Size)) { WinHttpException.ThrowExceptionUsingLastError(); } _operation.WebSocketHandle.AttachCallback(); _operation.UpdateState(WebSocketState.Open); if (_operation.RequestHandle != null) { _operation.RequestHandle.Dispose(); // RequestHandle will be set to null in the callback. } _operation.TcsUpgrade = null; ctr.Dispose(); } } }
public override Task SendAsync( ArraySegment <byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { _operation.InterlockedCheckValidStates(s_validSendStates); using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken)) { var bufferType = WebSocketMessageTypeAdapter.GetWinHttpMessageType(messageType, endOfMessage); // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer.Array) { if (_cachedSendPinnedBuffer.IsAllocated) { _cachedSendPinnedBuffer.Free(); } _cachedSendPinnedBuffer = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); } bool sendOperationAlreadyPending = false; if (_operation.PendingWriteOperation == false) { lock (_operation.Lock) { _operation.CheckValidState(s_validSendStates); if (_operation.PendingWriteOperation == false) { _operation.PendingWriteOperation = true; _operation.TcsSend = new TaskCompletionSource <bool>(); uint ret = Interop.WinHttp.WinHttpWebSocketSend( _operation.WebSocketHandle, bufferType, buffer.Count > 0 ? Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset) : IntPtr.Zero, (uint)buffer.Count); if (Interop.WinHttp.ERROR_SUCCESS != ret) { throw WinHttpException.CreateExceptionUsingError((int)ret); } } else { sendOperationAlreadyPending = true; } } } else { sendOperationAlreadyPending = true; } if (sendOperationAlreadyPending) { var exception = new InvalidOperationException( SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "SendAsync")); _operation.TcsSend.TrySetException(exception); Abort(); } return(_operation.TcsSend.Task); } }