public Task WriteFragmentAsync(ArraySegment <byte> buffer, bool isUtf8Encoded, bool isFinalFragment) { TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(); // The buffer will be read from asynchronously by unmanaged code, so we require that it remain pinned PinnedArraySegment <byte> pinnedBuffer = new PinnedArraySegment <byte>(buffer); // Callback will always be called (since it is responsible for cleanup), even if completed synchronously CompletionCallback callback = (hrError, cbIO, fUtf8Encoded, fFinalFragment, fClose) => { try { ThrowExceptionForHR(hrError); tcs.TrySetResult(null); // regular completion } catch (Exception ex) { tcs.TrySetException(ex); // exceptional completion } finally { // Always free the buffer to prevent a memory leak pinnedBuffer.Dispose(); } }; IntPtr completionContext = GCUtil.RootObject(callback); // update perf counter with count of data written to wire _perfCounters.IncrementCounter(AppPerfCounter.REQUEST_BYTES_OUT_WEBSOCKETS, pinnedBuffer.Count); // Call the underlying implementation; WriteFragment should never throw an exception int bytesSent = pinnedBuffer.Count; bool completionExpected; int hr = _context.WriteFragment( pData: pinnedBuffer.Pointer, pcbSent: ref bytesSent, fAsync: true, fUtf8Encoded: isUtf8Encoded, fFinalFragment: isFinalFragment, pfnCompletion: _asyncThunkAddress, pvCompletionContext: completionContext, pfCompletionExpected: out completionExpected); if (!completionExpected) { // Completed synchronously or error; the thunk and callback together handle cleanup AsyncCallbackThunk(hr, completionContext, bytesSent, isUtf8Encoded, isFinalFragment, fClose: false); } return(tcs.Task); }
public Task WriteFragmentAsync(ArraySegment<byte> buffer, bool isUtf8Encoded, bool isFinalFragment) { TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); // The buffer will be read from asynchronously by unmanaged code, so we require that it remain pinned PinnedArraySegment<byte> pinnedBuffer = new PinnedArraySegment<byte>(buffer); // Callback will always be called (since it is responsible for cleanup), even if completed synchronously CompletionCallback callback = (hrError, cbIO, fUtf8Encoded, fFinalFragment, fClose) => { try { ThrowExceptionForHR(hrError); tcs.TrySetResult(null); // regular completion } catch (Exception ex) { tcs.TrySetException(ex); // exceptional completion } finally { // Always free the buffer to prevent a memory leak pinnedBuffer.Dispose(); } }; IntPtr completionContext = GCUtil.RootObject(callback); // update perf counter with count of data written to wire _perfCounters.IncrementCounter(AppPerfCounter.REQUEST_BYTES_OUT_WEBSOCKETS, pinnedBuffer.Count); // Call the underlying implementation; WriteFragment should never throw an exception int bytesSent = pinnedBuffer.Count; bool completionExpected; int hr = _context.WriteFragment( pData: pinnedBuffer.Pointer, pcbSent: ref bytesSent, fAsync: true, fUtf8Encoded: isUtf8Encoded, fFinalFragment: isFinalFragment, pfnCompletion: _asyncThunkAddress, pvCompletionContext: completionContext, pfCompletionExpected: out completionExpected); if (!completionExpected) { // Completed synchronously or error; the thunk and callback together handle cleanup AsyncCallbackThunk(hr, completionContext, bytesSent, isUtf8Encoded, isFinalFragment, fClose: false); } return tcs.Task; }
public Task <WebSocketReceiveResult> ReadFragmentAsync(ArraySegment <byte> buffer) { TaskCompletionSource <WebSocketReceiveResult> tcs = new TaskCompletionSource <WebSocketReceiveResult>(); // The buffer will be written to asynchronously by unmanaged code, so we require that it remain pinned PinnedArraySegment <byte> pinnedBuffer = new PinnedArraySegment <byte>(buffer); // Callback will always be called (since it is responsible for cleanup), even if completed synchronously CompletionCallback callback = (hrError, cbIO, fUtf8Encoded, fFinalFragment, fClose) => { try { ThrowExceptionForHR(hrError); WebSocketCloseStatus?closeStatus = null; string closeStatusDescription = null; WebSocketMessageType messageType = (fUtf8Encoded) ? WebSocketMessageType.Text : WebSocketMessageType.Binary; if (fClose) { // this is a CLOSE frame messageType = WebSocketMessageType.Close; WebSocketCloseStatus statusCode; GetCloseStatus(out statusCode, out closeStatusDescription); closeStatus = statusCode; } else { // this is a data frame, so update perf counter with count of data read from wire _perfCounters.IncrementCounter(AppPerfCounter.REQUEST_BYTES_IN_WEBSOCKETS, cbIO); } tcs.TrySetResult(new WebSocketReceiveResult( count: cbIO, messageType: messageType, endOfMessage: fFinalFragment, closeStatus: closeStatus, closeStatusDescription: closeStatusDescription)); } catch (Exception ex) { tcs.TrySetException(ex); // exceptional completion } finally { // Always free the buffer to prevent a memory leak pinnedBuffer.Dispose(); } }; IntPtr completionContext = GCUtil.RootObject(callback); // Call the underlying implementation; ReadFragment should never throw an exception int bytesRead = pinnedBuffer.Count; bool isUtf8Encoded; bool isFinalFragment; bool isConnectionClose; bool completionExpected; int hr = _context.ReadFragment( pData: pinnedBuffer.Pointer, pcbData: ref bytesRead, fAsync: true, pfUtf8Encoded: out isUtf8Encoded, pfFinalFragment: out isFinalFragment, pfConnectionClose: out isConnectionClose, pfnCompletion: _asyncThunkAddress, pvCompletionContext: completionContext, pfCompletionExpected: out completionExpected); if (!completionExpected) { // Completed synchronously or error; the thunk and callback together handle cleanup AsyncCallbackThunk(hr, completionContext, bytesRead, isUtf8Encoded, isFinalFragment, isConnectionClose); } return(tcs.Task); }
public Task<WebSocketReceiveResult> ReadFragmentAsync(ArraySegment<byte> buffer) { TaskCompletionSource<WebSocketReceiveResult> tcs = new TaskCompletionSource<WebSocketReceiveResult>(); // The buffer will be written to asynchronously by unmanaged code, so we require that it remain pinned PinnedArraySegment<byte> pinnedBuffer = new PinnedArraySegment<byte>(buffer); // Callback will always be called (since it is responsible for cleanup), even if completed synchronously CompletionCallback callback = (hrError, cbIO, fUtf8Encoded, fFinalFragment, fClose) => { try { ThrowExceptionForHR(hrError); WebSocketCloseStatus? closeStatus = null; string closeStatusDescription = null; WebSocketMessageType messageType = (fUtf8Encoded) ? WebSocketMessageType.Text : WebSocketMessageType.Binary; if (fClose) { // this is a CLOSE frame messageType = WebSocketMessageType.Close; WebSocketCloseStatus statusCode; GetCloseStatus(out statusCode, out closeStatusDescription); closeStatus = statusCode; } else { // this is a data frame, so update perf counter with count of data read from wire _perfCounters.IncrementCounter(AppPerfCounter.REQUEST_BYTES_IN_WEBSOCKETS, cbIO); } tcs.TrySetResult(new WebSocketReceiveResult( count: cbIO, messageType: messageType, endOfMessage: fFinalFragment, closeStatus: closeStatus, closeStatusDescription: closeStatusDescription)); } catch (Exception ex) { tcs.TrySetException(ex); // exceptional completion } finally { // Always free the buffer to prevent a memory leak pinnedBuffer.Dispose(); } }; IntPtr completionContext = GCUtil.RootObject(callback); // Call the underlying implementation; ReadFragment should never throw an exception int bytesRead = pinnedBuffer.Count; bool isUtf8Encoded; bool isFinalFragment; bool isConnectionClose; bool completionExpected; int hr = _context.ReadFragment( pData: pinnedBuffer.Pointer, pcbData: ref bytesRead, fAsync: true, pfUtf8Encoded: out isUtf8Encoded, pfFinalFragment: out isFinalFragment, pfConnectionClose: out isConnectionClose, pfnCompletion: _asyncThunkAddress, pvCompletionContext: completionContext, pfCompletionExpected: out completionExpected); if (!completionExpected) { // Completed synchronously or error; the thunk and callback together handle cleanup AsyncCallbackThunk(hr, completionContext, bytesRead, isUtf8Encoded, isFinalFragment, isConnectionClose); } return tcs.Task; }