private void Reset(uint size) { if (size == _size) { return; } if (_size != 0) { _overlapped.Dispose(); } _size = size; if (size == 0) { _overlapped = null; _memoryBlob = null; _backingBuffer = null; return; } _backingBuffer = new byte[checked ((int)size)]; var boundHandle = RequestContext.Server.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); }
private void OnReleasePins() { if (_nativeOverlapped != null) { SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; nativeOverlapped.Dispose(); } }
internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration) : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; var boundHandle = requestStream.RequestContext.Server.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); _cancellationRegistration = cancellationRegistration; }
private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST *Allocate(uint size) { uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; // We can't reuse overlapped objects if (_nativeOverlapped != null) { SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; nativeOverlapped.Dispose(); } if (_nativeOverlapped == null) { SetBuffer(checked ((int)newSize)); var boundHandle = _acceptResult.Server.BoundHandle; _nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); return((UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST *)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0)); } return(RequestBlob); }
private unsafe CancellationToken CreateDisconnectToken(ulong connectionId) { // Debug.WriteLine("Server: Registering connection for disconnect for connection ID: " + connectionId); // Create a nativeOverlapped callback so we can register for disconnect callback var cts = new CancellationTokenSource(); SafeNativeOverlapped nativeOverlapped = null; nativeOverlapped = new SafeNativeOverlapped(_boundHandle, _boundHandle.AllocateNativeOverlapped( (errorCode, numBytes, overlappedPtr) => { // Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); // Free the overlapped nativeOverlapped.Dispose(); // Pull the token out of the list and Cancel it. ConnectionCancellation token; _connectionCancellationTokens.TryRemove(connectionId, out token); try { cts.Cancel(); } catch (AggregateException exception) { LogHelper.LogException(_logger, "CreateDisconnectToken::Disconnected", exception); } cts.Dispose(); }, null, null)); uint statusCode; try { statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueueHandle, connectionId: connectionId, reserved: 0, overlapped: nativeOverlapped); } catch (Win32Exception exception) { statusCode = (uint)exception.NativeErrorCode; LogHelper.LogException(_logger, "CreateDisconnectToken", exception); } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // We got an unknown result so return a None // TODO: return a canceled token? return(CancellationToken.None); } if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. // TODO: return a canceled token? return(CancellationToken.None); } return(cts.Token); }
internal ResponseStreamAsyncResult(ResponseStream responseStream, BufferBuilder buffer, bool chunked, CancellationTokenRegistration cancellationRegistration) : this(responseStream, cancellationRegistration) { var boundHandle = _responseStream.RequestContext.Server.BoundHandle; object[] objectsToPin; if (buffer.TotalBytes == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); return; } _dataChunks = new HttpApi.HTTP_DATA_CHUNK[buffer.BufferCount + (chunked ? 2 : 0)]; objectsToPin = new object[_dataChunks.Length + 1]; objectsToPin[0] = _dataChunks; var currentChunk = 0; var currentPin = 1; var chunkHeaderBuffer = new ArraySegment <byte>(); if (chunked) { chunkHeaderBuffer = Helpers.GetChunkHeader(buffer.TotalBytes); SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, chunkHeaderBuffer); } foreach (var segment in buffer.Buffers) { SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, segment); } if (chunked) { SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, new ArraySegment <byte>(Helpers.CRLF)); } // This call will pin needed memory _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); currentChunk = 0; if (chunked) { _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset); currentChunk++; } foreach (var segment in buffer.Buffers) { _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset); currentChunk++; } if (chunked) { _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); currentChunk++; } // We've captured a reference to all the buffers, clear the buffer so that it can be used to queue overlapped writes. buffer.Clear(); }
internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset, long?count, bool chunked, CancellationTokenRegistration cancellationRegistration) : this(responseStream, cancellationRegistration) { var boundHandle = responseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. #if NETSTANDARD1_3 _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #else // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. #endif long length = _fileStream.Length; // Expensive if (offset < 0 || offset > length) { _fileStream.Dispose(); throw new ArgumentOutOfRangeException("offset", offset, string.Empty); } if (count.HasValue && (count < 0 || count > length - offset)) { _fileStream.Dispose(); throw new ArgumentOutOfRangeException("count", count, string.Empty); } if (count == 0 || (!count.HasValue && _fileStream.Length == 0)) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { _dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; object[] objectsToPin = new object[_dataChunks.Length]; objectsToPin[_dataChunks.Length - 1] = _dataChunks; var chunkHeaderBuffer = new ArraySegment <byte>(); if (chunked) { chunkHeaderBuffer = Helpers.GetChunkHeader((int)(count ?? _fileStream.Length - offset)); _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count; objectsToPin[0] = chunkHeaderBuffer.Array; _dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[1].fromFile.offset = (ulong)offset; _dataChunks[1].fromFile.count = (ulong)(count ?? -1); _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); // Nothing to pin for the file handle. _dataChunks[2].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length; objectsToPin[1] = Helpers.CRLF; } else { _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[0].fromFile.offset = (ulong)offset; _dataChunks[0].fromFile.count = (ulong)(count ?? -1); _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); } // This call will pin needed memory _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); if (chunked) { // These must be set after pinning with Overlapped. _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset); _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); } } }