Example #1
0
        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);
        }
Example #5
0
        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);
                }
            }
        }