internal OverlappedCache(System.Threading.Overlapped overlapped, object pinnedObjects, IOCompletionCallback callback, bool alreadyTriedCast) { this.m_Overlapped = overlapped; this.m_PinnedObjects = pinnedObjects; this.m_PinnedObjectsArray = alreadyTriedCast ? null : NclConstants.EmptyObjectArray; this.m_NativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack(callback, pinnedObjects)); }
// SetUnmanagedStructures // // This needs to be called for overlapped IO to function properly. // // Fills in overlapped Structures used in an async overlapped Winsock call. // These calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the overlapped calls may complete asynchronously. internal void SetUnmanagedStructures(object objectsToPin) { Socket s = (Socket)AsyncObject; // Bind the Win32 Socket Handle to the ThreadPool Debug.Assert(s != null, "m_CurrentSocket is null"); Debug.Assert(s.SafeHandle != null, "m_CurrentSocket.SafeHandle is null"); if (s.SafeHandle.IsInvalid) { throw new ObjectDisposedException(s.GetType().FullName); } ThreadPoolBoundHandle boundHandle = s.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); unsafe { NativeOverlapped* overlapped = boundHandle.AllocateNativeOverlapped(s_ioCallback, this, objectsToPin); _nativeOverlapped = new SafeNativeOverlapped(s.SafeHandle, overlapped); if (GlobalLog.IsEnabled) { GlobalLog.Print( "BaseOverlappedAsyncResult#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped. Return=" + _nativeOverlapped.DangerousGetHandle().ToString("x")); } } }
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.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); _memoryBlob = (HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO *)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); }
internal OverlappedCache(System.Threading.Overlapped overlapped, object[] pinnedObjectsArray, IOCompletionCallback callback) { this.m_Overlapped = overlapped; this.m_PinnedObjects = pinnedObjectsArray; this.m_PinnedObjectsArray = pinnedObjectsArray; this.m_NativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack(callback, pinnedObjectsArray)); }
internal void AllocateNativeRequest(uint?size = null, ulong requestId = 0) { _nativeRequestContext?.ReleasePins(); _nativeRequestContext?.Dispose(); //Debug.Assert(size != 0, "unexpected size"); // We can't reuse overlapped objects uint newSize = size.HasValue ? size.Value : DefaultBufferSize; var backingBuffer = new byte[newSize + AlignmentPadding]; var boundHandle = Server.RequestQueue.BoundHandle; var nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, backingBuffer)); var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(backingBuffer, 0); // TODO: // Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors // are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on // virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In // these cases the buffer alignment may cause reading values at invalid offset. Setting buffer // alignment to 0 for now. // // _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); var bufferAlignment = 0; var nativeRequest = (HttpApiTypes.HTTP_REQUEST *)(requestAddress + bufferAlignment); // nativeRequest _nativeRequestContext = new NativeRequestContext(nativeOverlapped, bufferAlignment, nativeRequest, backingBuffer, requestId); }
internal ResponseStreamAsyncResult(ResponseBody responseStream, FileStream fileStream, long offset, long count, bool chunked, CancellationToken cancellationToken) : this(responseStream, cancellationToken) { var boundHandle = responseStream.RequestContext.Server.RequestQueue.BoundHandle; _fileStream = fileStream; if (count == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { _dataChunks = new HttpApiTypes.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(count); _dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count; objectsToPin[0] = chunkHeaderBuffer.Array; _dataChunks[1].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[1].fromFile.offset = (ulong)offset; _dataChunks[1].fromFile.count = (ulong)count; _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); // Nothing to pin for the file handle. _dataChunks[2].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length; objectsToPin[1] = Helpers.CRLF; } else { _dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[0].fromFile.offset = (ulong)offset; _dataChunks[0].fromFile.count = (ulong)count; _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); } } }
internal static unsafe extern SocketError WSARecv( IntPtr socketHandle, WSABuffer *buffer, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, SafeNativeOverlapped overlapped, IntPtr completionRoutine);
internal static extern unsafe SocketError WSASend( IntPtr socketHandle, WSABuffer *buffers, int bufferCount, out int bytesTransferred, SocketFlags socketFlags, SafeNativeOverlapped overlapped, IntPtr completionRoutine);
internal ResponseStreamAsyncResult(ResponseBody responseStream, ArraySegment <byte> data, bool chunked, CancellationToken cancellationToken) : this(responseStream, cancellationToken) { var boundHandle = _responseStream.RequestContext.Server.RequestQueue.BoundHandle; object[] objectsToPin; if (data.Count == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); return; } _dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[1 + (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(data.Count); SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, chunkHeaderBuffer); } SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, data); 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++; } _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(data.Array, data.Offset); currentChunk++; if (chunked) { _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); currentChunk++; } }
internal static extern SocketError WSARecvFrom( [In] SafeCloseSocket socketHandle, [In, Out] WSABuffer[] buffers, [In] int bufferCount, [Out] out int bytesTransferred, [In, Out] ref SocketFlags socketFlags, [In] IntPtr socketAddressPointer, [In] IntPtr socketAddressSizePointer, [In] SafeNativeOverlapped overlapped, [In] IntPtr completionRoutine);
internal static extern SocketError WSASendTo( [In] SafeCloseSocket socketHandle, [In] WSABuffer[] buffersArray, [In] int bufferCount, [Out] out int bytesTransferred, [In] SocketFlags socketFlags, [In] IntPtr socketAddress, [In] int socketAddressSize, [In] SafeNativeOverlapped overlapped, [In] IntPtr completionRoutine);
internal static unsafe extern SocketError WSARecvFrom( SafeCloseSocket socketHandle, WSABuffer *buffers, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, IntPtr socketAddressPointer, IntPtr socketAddressSizePointer, SafeNativeOverlapped overlapped, IntPtr completionRoutine);
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.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); _cancellationRegistration = cancellationRegistration; }
internal void AllocateNativeRequest(uint?size = null, ulong requestId = 0) { _nativeRequestContext?.ReleasePins(); _nativeRequestContext?.Dispose(); // We can't reuse overlapped objects var boundHandle = Server.RequestQueue.BoundHandle; var nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, pinData: null)); // nativeRequest _nativeRequestContext = new NativeRequestContext(nativeOverlapped, Server.MemoryPool, size, requestId); }
private void InternalFree() { this.m_Overlapped = null; this.m_PinnedObjects = null; if (this.m_NativeOverlapped != null) { if (!this.m_NativeOverlapped.IsInvalid) { this.m_NativeOverlapped.Dispose(); } this.m_NativeOverlapped = null; } }
internal static unsafe SocketError WSASend( IntPtr socketHandle, WSABuffer[] buffers, int bufferCount, out int bytesTransferred, SocketFlags socketFlags, SafeNativeOverlapped overlapped, IntPtr completionRoutine) { Debug.Assert(buffers != null); fixed(WSABuffer *buffersPtr = &buffers[0]) { return(WSASend(socketHandle, buffersPtr, bufferCount, out bytesTransferred, socketFlags, overlapped, completionRoutine)); } }
internal static unsafe SocketError WSASend( SafeCloseSocket socketHandle, ref WSABuffer buffer, int bufferCount, out int bytesTransferred, SocketFlags socketFlags, SafeNativeOverlapped overlapped, IntPtr completionRoutine) { // We intentionally do NOT copy this back after the function completes: // We don't want to cause a race in async scenarios. // The WSABuffer struct should be unchanged anyway. WSABuffer localBuffer = buffer; return(WSASend(socketHandle, &localBuffer, bufferCount, out bytesTransferred, socketFlags, overlapped, completionRoutine)); }
internal static unsafe SocketError WSARecvFrom( SafeCloseSocket socketHandle, WSABuffer[] buffers, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, IntPtr socketAddressPointer, IntPtr socketAddressSizePointer, SafeNativeOverlapped overlapped, IntPtr completionRoutine) { Debug.Assert(buffers != null); fixed(WSABuffer *buffersPtr = &buffers[0]) { return(WSARecvFrom(socketHandle, buffersPtr, bufferCount, out bytesTransferred, ref socketFlags, socketAddressPointer, socketAddressSizePointer, overlapped, completionRoutine)); } }
// SetUnmanagedStructures // // This needs to be called for overlapped IO to function properly. // // Fills in overlapped Structures used in an async overlapped Winsock call. // These calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the overlapped calls may complete asynchronously. internal void SetUnmanagedStructures(object objectsToPin) { Socket s = (Socket)AsyncObject; // Bind the Win32 Socket Handle to the ThreadPool Debug.Assert(s != null, "m_CurrentSocket is null"); Debug.Assert(s.SafeHandle != null, "m_CurrentSocket.SafeHandle is null"); if (s.SafeHandle.IsInvalid) { throw new ObjectDisposedException(s.GetType().FullName); } ThreadPoolBoundHandle boundHandle = s.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); unsafe { NativeOverlapped* overlapped = boundHandle.AllocateNativeOverlapped(s_ioCallback, this, objectsToPin); _nativeOverlapped = new SafeNativeOverlapped(s.SafeHandle, overlapped); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"{boundHandle}::AllocateNativeOverlapped. return={_nativeOverlapped}"); } }
// Utility cleanup routine. Frees the overlapped structure. // This should be overridden to free pinned and unmanaged memory in the subclass. // It needs to also be invoked from the subclass. protected virtual void ForceReleaseUnmanagedStructures() { // Free the unmanaged memory if allocated. if (NetEventSource.IsEnabled) NetEventSource.Enter(this); _nativeOverlapped.Dispose(); _nativeOverlapped = null; GC.SuppressFinalize(this); }
private unsafe void PrepareIOCPOperation() { Debug.Assert(_currentSocket != null, "_currentSocket is null"); Debug.Assert(_currentSocket.SafeHandle != null, "_currentSocket.SafeHandle is null"); Debug.Assert(!_currentSocket.SafeHandle.IsInvalid, "_currentSocket.SafeHandle is invalid"); ThreadPoolBoundHandle boundHandle = _currentSocket.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); NativeOverlapped* overlapped = null; if (_preAllocatedOverlapped != null) { overlapped = boundHandle.AllocateNativeOverlapped(_preAllocatedOverlapped); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped(m_PreAllocatedOverlapped=" + LoggingHash.HashString(_preAllocatedOverlapped) + "). Returned = " + ((IntPtr)overlapped).ToString("x")); } } else { overlapped = boundHandle.AllocateNativeOverlapped(CompletionPortCallback, this, null); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped(pinData=null)" + "). Returned = " + ((IntPtr)overlapped).ToString("x")); } } Debug.Assert(overlapped != null, "NativeOverlapped is null."); // If we already have a SafeNativeOverlapped SafeHandle and it's associated with the same // socket (due to the last operation that used this SocketAsyncEventArgs using the same socket), // then we can reuse the same SafeHandle object. Otherwise, this is either the first operation // or the last operation was with a different socket, so create a new SafeHandle. if (_ptrNativeOverlapped?.SocketHandle == _currentSocket.SafeHandle) { _ptrNativeOverlapped.ReplaceHandle(overlapped); } else { _ptrNativeOverlapped?.Dispose(); _ptrNativeOverlapped = new SafeNativeOverlapped(_currentSocket.SafeHandle, overlapped); } }
internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK *pEntityChunks, uint *pBytesSent, IntPtr pReserved1, uint Reserved2, SafeNativeOverlapped pOverlapped, IntPtr pLogData);
internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST *pRequestBuffer, uint requestBufferLength, uint *pBytesReturned, SafeNativeOverlapped pOverlapped);
internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped);
internal OverlappedCache(Overlapped overlapped, object[] pinnedObjectsArray, IOCompletionCallback callback) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjectsArray; m_PinnedObjectsArray = pinnedObjectsArray; unsafe { m_NativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack(callback, pinnedObjectsArray)); } }
// Cleans up any existing Overlapped object and related state variables. private void FreeOverlapped(bool checkForShutdown) { if (!checkForShutdown || !Environment.HasShutdownStarted) { // Free the overlapped object. if (_ptrNativeOverlapped != null && !_ptrNativeOverlapped.IsInvalid) { _ptrNativeOverlapped.Dispose(); _ptrNativeOverlapped = null; } // Free the preallocated overlapped object. This in turn will unpin // any pinned buffers. if (_preAllocatedOverlapped != null) { _preAllocatedOverlapped.Dispose(); _preAllocatedOverlapped = null; _pinState = PinState.None; _pinnedAcceptBuffer = null; _pinnedSingleBuffer = null; _pinnedSingleBufferOffset = 0; _pinnedSingleBufferCount = 0; } // Free any allocated GCHandles. if (_socketAddressGCHandle.IsAllocated) { _socketAddressGCHandle.Free(); _pinnedSocketAddress = null; } if (_wsaMessageBufferGCHandle.IsAllocated) { _wsaMessageBufferGCHandle.Free(); _ptrWSAMessageBuffer = IntPtr.Zero; } if (_wsaRecvMsgWSABufferArrayGCHandle.IsAllocated) { _wsaRecvMsgWSABufferArrayGCHandle.Free(); _ptrWSARecvMsgWSABufferArray = IntPtr.Zero; } if (_controlBufferGCHandle.IsAllocated) { _controlBufferGCHandle.Free(); _ptrControlBuffer = IntPtr.Zero; } } }
private unsafe void PrepareIOCPOperation() { Debug.Assert(_currentSocket != null, "_currentSocket is null"); Debug.Assert(_currentSocket.SafeHandle != null, "_currentSocket.SafeHandle is null"); Debug.Assert(!_currentSocket.SafeHandle.IsInvalid, "_currentSocket.SafeHandle is invalid"); ThreadPoolBoundHandle boundHandle = _currentSocket.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); NativeOverlapped* overlapped = null; if (_preAllocatedOverlapped != null) { overlapped = boundHandle.AllocateNativeOverlapped(_preAllocatedOverlapped); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped(m_PreAllocatedOverlapped=" + LoggingHash.HashString(_preAllocatedOverlapped) + "). Returned = " + ((IntPtr)overlapped).ToString("x")); } } else { overlapped = boundHandle.AllocateNativeOverlapped(CompletionPortCallback, this, null); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped(pinData=null)" + "). Returned = " + ((IntPtr)overlapped).ToString("x")); } } Debug.Assert(overlapped != null, "NativeOverlapped is null."); _ptrNativeOverlapped = new SafeNativeOverlapped(_currentSocket.SafeHandle, overlapped); }
// Method to setup an Overlapped object with with multiple buffers pinned. unsafe private void SetupOverlappedMultiple() { ArraySegment<byte>[] tempList = new ArraySegment<byte>[m_BufferList.Count]; m_BufferList.CopyTo(tempList, 0); // Alloc new Overlapped. m_Overlapped = new Overlapped(); // Number of things to pin is number of buffers. // Ensure we have properly sized object array. if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != tempList.Length)) { m_ObjectsToPin = new object[tempList.Length]; } // Fill in object array. for(int i = 0; i < (tempList.Length); i++) { m_ObjectsToPin[i] = tempList[i].Array; } if(m_WSABufferArray == null || m_WSABufferArray.Length != tempList.Length) { m_WSABufferArray = new WSABuffer[tempList.Length]; } // Pin buffers and fill in WSABuffer descriptor pointers and lengths #if SOCKETTHREADPOOL m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin)); #else m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin)); #endif for(int i = 0; i < tempList.Length; i++) { ArraySegment<byte> localCopy = tempList[i]; ValidationHelper.ValidateSegment(localCopy); m_WSABufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array, localCopy.Offset); m_WSABufferArray[i].Length = localCopy.Count; } m_PinState = PinState.MultipleBuffer; }
// Method to clean up any existing Overlapped object and related state variables. private void FreeOverlapped(bool checkForShutdown) { if (!checkForShutdown || !NclUtilities.HasShutdownStarted) { // Free the overlapped object if(m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) { m_PtrNativeOverlapped.Dispose(); m_PtrNativeOverlapped = null; m_Overlapped = null; m_PinState = PinState.None; m_PinnedAcceptBuffer = null; m_PinnedSingleBuffer = null; m_PinnedSingleBufferOffset = 0; m_PinnedSingleBufferCount = 0; } // Free any alloc'd GCHandles if(m_SocketAddressGCHandle.IsAllocated) { m_SocketAddressGCHandle.Free(); } if(m_WSAMessageBufferGCHandle.IsAllocated) { m_WSAMessageBufferGCHandle.Free(); } if(m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated) { m_WSARecvMsgWSABufferArrayGCHandle.Free(); } if(m_ControlBufferGCHandle.IsAllocated) { m_ControlBufferGCHandle.Free(); } } }
private unsafe void PrepareIOCPOperation() { Debug.Assert(_currentSocket != null, "_currentSocket is null"); Debug.Assert(_currentSocket.SafeHandle != null, "_currentSocket.SafeHandle is null"); Debug.Assert(!_currentSocket.SafeHandle.IsInvalid, "_currentSocket.SafeHandle is invalid"); ThreadPoolBoundHandle boundHandle = _currentSocket.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); NativeOverlapped* overlapped = null; if (_preAllocatedOverlapped != null) { overlapped = boundHandle.AllocateNativeOverlapped(_preAllocatedOverlapped); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"boundHandle:{boundHandle}, PreAllocatedOverlapped:{_preAllocatedOverlapped}, Returned:{(IntPtr)overlapped}"); } else { overlapped = boundHandle.AllocateNativeOverlapped(CompletionPortCallback, this, null); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"boundHandle:{boundHandle}, AllocateNativeOverlapped(pinData=null), Returned:{(IntPtr)overlapped}"); } Debug.Assert(overlapped != null, "NativeOverlapped is null."); // If we already have a SafeNativeOverlapped SafeHandle and it's associated with the same // socket (due to the last operation that used this SocketAsyncEventArgs using the same socket), // then we can reuse the same SafeHandle object. Otherwise, this is either the first operation // or the last operation was with a different socket, so create a new SafeHandle. if (_ptrNativeOverlapped?.SocketHandle == _currentSocket.SafeHandle) { _ptrNativeOverlapped.ReplaceHandle(overlapped); } else { _ptrNativeOverlapped?.Dispose(); _ptrNativeOverlapped = new SafeNativeOverlapped(_currentSocket.SafeHandle, overlapped); } }
internal static extern unsafe uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped);
internal static unsafe partial uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped);
// Method to setup an Overlapped object with either m_Buffer or m_AcceptBuffer pinned. unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) { // Alloc new Overlapped. m_Overlapped = new Overlapped(); // Pin buffer, get native pointers, and fill in WSABuffer descriptor. if(pinSingleBuffer) { if(m_Buffer != null) { #if SOCKETTHREADPOOL m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_Buffer)); #else m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_Buffer)); #endif m_PinnedSingleBuffer = m_Buffer; m_PinnedSingleBufferOffset = m_Offset; m_PinnedSingleBufferCount = m_Count; m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_Buffer, m_Offset); m_PtrAcceptBuffer = IntPtr.Zero; m_WSABuffer.Pointer = m_PtrSingleBuffer; m_WSABuffer.Length = m_Count; m_PinState = PinState.SingleBuffer; } else { #if SOCKETTHREADPOOL m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, null)); #else m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null)); #endif m_PinnedSingleBuffer = null; m_PinnedSingleBufferOffset = 0; m_PinnedSingleBufferCount = 0; m_PtrSingleBuffer = IntPtr.Zero; m_PtrAcceptBuffer = IntPtr.Zero; m_WSABuffer.Pointer = m_PtrSingleBuffer; m_WSABuffer.Length = m_Count; m_PinState = PinState.NoBuffer; } } else { #if SOCKETTHREADPOOL m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_AcceptBuffer)); #else m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_AcceptBuffer)); #endif m_PinnedAcceptBuffer = m_AcceptBuffer; m_PtrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(m_AcceptBuffer, 0); m_PtrSingleBuffer = IntPtr.Zero; m_PinState = PinState.SingleAcceptBuffer; } }
private void InternalFree() { m_Overlapped = null; m_PinnedObjects = null; if (m_NativeOverlapped != null) { if (!m_NativeOverlapped.IsInvalid) { m_NativeOverlapped.Dispose(); } m_NativeOverlapped = null; } }
// Method to setup an Overlapped object for SendPacketsAsync. unsafe private void SetupOverlappedSendPackets() { int index; // Alloc new Overlapped. m_Overlapped = new Overlapped(); // Alloc native descriptor. m_SendPacketsDescriptor = new UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[m_SendPacketsElementsFileCount + m_SendPacketsElementsBufferCount]; // Number of things to pin is number of buffers + 1 (native descriptor). // Ensure we have properly sized object array. if(m_ObjectsToPin == null || (m_ObjectsToPin.Length != m_SendPacketsElementsBufferCount + 1)) { m_ObjectsToPin = new object[m_SendPacketsElementsBufferCount + 1]; } // Fill in objects to pin array. Native descriptor buffer first and then user specified buffers. m_ObjectsToPin[0] = m_SendPacketsDescriptor; index = 1; foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) { if(spe != null && spe.m_Buffer != null && spe.m_Count > 0) { m_ObjectsToPin[index] = spe.m_Buffer; index++; } } // Pin buffers #if SOCKETTHREADPOOL m_Overlapped.AsyncResult = new DummyAsyncResult(CompletionPortCallback); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(null, m_ObjectsToPin)); #else m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, m_ObjectsToPin)); #endif // Get pointer to native descriptor. m_PtrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(m_SendPacketsDescriptor, 0); // Fill in native descriptor. int descriptorIndex = 0; int fileIndex = 0; foreach(SendPacketsElement spe in m_SendPacketsElementsInternal) { if (spe != null) { if(spe.m_Buffer != null && spe.m_Count > 0) { // a buffer m_SendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.m_Buffer, spe.m_Offset); m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count; m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags; descriptorIndex++; } else if (spe.m_FilePath != null) { // a file m_SendPacketsDescriptor[descriptorIndex].fileHandle = m_SendPacketsFileHandles[fileIndex].DangerousGetHandle(); m_SendPacketsDescriptor[descriptorIndex].fileOffset = spe.m_Offset; m_SendPacketsDescriptor[descriptorIndex].length = (uint)spe.m_Count; m_SendPacketsDescriptor[descriptorIndex].flags = spe.m_Flags; fileIndex++; descriptorIndex++; } } } m_PinState = PinState.SendPackets; }
// // This method is called after an asynchronous call is made for the user, // it checks and acts accordingly if the IO: // 1) completed synchronously. // 2) was pended. // 3) failed. // internal unsafe SocketError CheckAsyncCallOverlappedResult(SocketError errorCode) { #if DEBUG m_SavedErrorCode = errorCode; #endif // // Check if the Async IO call: // 1) was pended. // 2) completed synchronously. // 3) failed. // if (m_UseOverlappedIO) { // // we're using overlapped IO under Win9x (or NT with registry setting overriding // completion port usage) // switch (errorCode) { case 0: case SocketError.IOPending: // // the Async IO call was pended: // Queue our event to the thread pool. // GlobalLog.Assert(m_UnmanagedBlob != null, "BaseOverlappedAsyncResult#{0}::CheckAsyncCallOverlappedResult()|Unmanaged blob isn't allocated.", ValidationHelper.HashString(this)); ThreadPool.UnsafeRegisterWaitForSingleObject( m_OverlappedEvent, new WaitOrTimerCallback(OverlappedCallback), this, -1, true ); // // we're done, completion will be asynchronous // in the callback. return // return SocketError.Success; default: // // the Async IO call failed: // set the number of bytes transferred to -1 (error) // ErrorCode = (int)errorCode; Result = -1; ReleaseUnmanagedStructures(); break; } } else { #if DEBUG OverlappedCache cache = m_Cache; if (cache != null) { SafeNativeOverlapped nativeOverlappedPtr = cache.NativeOverlapped; if (nativeOverlappedPtr != null) m_IntermediateNativeOverlapped = nativeOverlappedPtr; } #endif // // We're using completion ports under WinNT. Release one reference on the structures for // the main thread. // ReleaseUnmanagedStructures(); switch (errorCode) { // // ignore cases in which a completion packet will be queued: // we'll deal with this IO in the callback // case 0: case SocketError.IOPending: // // ignore, do nothing // return SocketError.Success; // // in the remaining cases a completion packet will NOT be queued: // we'll have to call the callback explicitly signaling an error // default: // // call the callback with error code // ErrorCode = (int)errorCode; Result = -1; // The AsyncResult must be cleared since the callback isn't going to be called. // Not doing so leads to a leak where the pinned cached OverlappedData continues to point to the async result object, // which points to the Socket (as well as user data) and to the OverlappedCache, preventing the OverlappedCache // finalizer from freeing the pinned OverlappedData. if (m_Cache != null) { // Could be null only if SetUnmanagedStructures weren't called. m_Cache.Overlapped.AsyncResult = null; } ReleaseUnmanagedStructures(); // Additional release for the completion that won't happen. break; } } return errorCode; }
private void CompleteIOCPOperation() { // TODO #4900: Optimization to remove callbacks if the operations are completed synchronously: // Use SetFileCompletionNotificationModes(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS). // If SetFileCompletionNotificationModes(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) is not set on this handle // it is guaranteed that the IOCP operation will be completed in the callback even if Socket.Success was // returned by the Win32 API. // Required to allow another IOCP operation for the same handle. if (_ptrNativeOverlapped != null) { _ptrNativeOverlapped.Dispose(); _ptrNativeOverlapped = null; } }
private void FreeOverlapped(bool checkForShutdown) { if (!checkForShutdown || !NclUtilities.HasShutdownStarted) { if ((this.m_PtrNativeOverlapped != null) && !this.m_PtrNativeOverlapped.IsInvalid) { this.m_PtrNativeOverlapped.Dispose(); this.m_PtrNativeOverlapped = null; this.m_Overlapped = null; this.m_PinState = PinState.None; this.m_PinnedAcceptBuffer = null; this.m_PinnedSingleBuffer = null; this.m_PinnedSingleBufferOffset = 0; this.m_PinnedSingleBufferCount = 0; } if (this.m_SocketAddressGCHandle.IsAllocated) { this.m_SocketAddressGCHandle.Free(); } if (this.m_WSAMessageBufferGCHandle.IsAllocated) { this.m_WSAMessageBufferGCHandle.Free(); } if (this.m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated) { this.m_WSARecvMsgWSABufferArrayGCHandle.Free(); } if (this.m_ControlBufferGCHandle.IsAllocated) { this.m_ControlBufferGCHandle.Free(); } } }
// Utility cleanup routine. Frees the overlapped structure. // This should be overriden to free pinned and unmanaged memory in the subclass. // It needs to also be invoked from the subclass. protected virtual void ForceReleaseUnmanagedStructures() { // Free the unmanaged memory if allocated. if (GlobalLog.IsEnabled) { GlobalLog.Print( "BaseOverlappedAsyncResult#" + LoggingHash.HashString(this) + "::ForceReleaseUnmanagedStructures"); } _nativeOverlapped.Dispose(); _nativeOverlapped = null; GC.SuppressFinalize(this); }
private void SetupOverlappedMultiple() { this.m_Overlapped = new Overlapped(); ArraySegment<byte>[] array = new ArraySegment<byte>[this.m_BufferList.Count]; this.m_BufferList.CopyTo(array, 0); if ((this.m_ObjectsToPin == null) || (this.m_ObjectsToPin.Length != array.Length)) { this.m_ObjectsToPin = new object[array.Length]; } for (int i = 0; i < array.Length; i++) { this.m_ObjectsToPin[i] = array[i].Array; } if ((this.m_WSABufferArray == null) || (this.m_WSABufferArray.Length != array.Length)) { this.m_WSABufferArray = new WSABuffer[array.Length]; } this.m_PtrNativeOverlapped = new SafeNativeOverlapped(this.m_Overlapped.UnsafePack(new IOCompletionCallback(this.CompletionPortCallback), this.m_ObjectsToPin)); for (int j = 0; j < array.Length; j++) { ArraySegment<byte> segment = array[j]; ValidationHelper.ValidateSegment(segment); this.m_WSABufferArray[j].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset); this.m_WSABufferArray[j].Length = segment.Count; } this.m_PinState = PinState.MultipleBuffer; }
internal bool TransmitPackets(SafeCloseSocket socketHandle, IntPtr packetArray, int elementCount, int sendSize, SafeNativeOverlapped overlapped) { EnsureDynamicWinsockMethods(); TransmitPacketsDelegate transmitPackets = _dynamicWinsockMethods.GetDelegate<TransmitPacketsDelegate>(socketHandle); // UseDefaultWorkerThread = 0. return transmitPackets(socketHandle, packetArray, elementCount, sendSize, overlapped, 0); }
private void SetupOverlappedSendPackets() { this.m_Overlapped = new Overlapped(); this.m_SendPacketsDescriptor = new UnsafeNclNativeMethods.OSSOCK.TransmitPacketsElement[this.m_SendPacketsElementsFileCount + this.m_SendPacketsElementsBufferCount]; if ((this.m_ObjectsToPin == null) || (this.m_ObjectsToPin.Length != (this.m_SendPacketsElementsBufferCount + 1))) { this.m_ObjectsToPin = new object[this.m_SendPacketsElementsBufferCount + 1]; } this.m_ObjectsToPin[0] = this.m_SendPacketsDescriptor; int index = 1; foreach (SendPacketsElement element in this.m_SendPacketsElementsInternal) { if ((element.m_Buffer != null) && (element.m_Count > 0)) { this.m_ObjectsToPin[index] = element.m_Buffer; index++; } } this.m_PtrNativeOverlapped = new SafeNativeOverlapped(this.m_Overlapped.UnsafePack(new IOCompletionCallback(this.CompletionPortCallback), this.m_ObjectsToPin)); this.m_PtrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(this.m_SendPacketsDescriptor, 0); int num2 = 0; int num3 = 0; foreach (SendPacketsElement element2 in this.m_SendPacketsElementsInternal) { if (element2 != null) { if ((element2.m_Buffer != null) && (element2.m_Count > 0)) { this.m_SendPacketsDescriptor[num2].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(element2.m_Buffer, element2.m_Offset); this.m_SendPacketsDescriptor[num2].length = (uint) element2.m_Count; this.m_SendPacketsDescriptor[num2].flags = element2.m_Flags; num2++; } else if ((element2.m_FilePath != null) && (element2.m_FilePath.Length != 0)) { this.m_SendPacketsDescriptor[num2].fileHandle = this.m_SendPacketsFileHandles[num3].DangerousGetHandle(); this.m_SendPacketsDescriptor[num2].fileOffset = element2.m_Offset; this.m_SendPacketsDescriptor[num2].length = (uint) element2.m_Count; this.m_SendPacketsDescriptor[num2].flags = element2.m_Flags; num3++; num2++; } } } this.m_PinState = PinState.SendPackets; }
internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, byte *pSslClientCertInfo, uint sslClientCertInfoSize, uint *pBytesReceived, SafeNativeOverlapped pOverlapped);
private void SetupOverlappedSingle(bool pinSingleBuffer) { this.m_Overlapped = new Overlapped(); if (pinSingleBuffer) { if (this.m_Buffer != null) { this.m_PtrNativeOverlapped = new SafeNativeOverlapped(this.m_Overlapped.UnsafePack(new IOCompletionCallback(this.CompletionPortCallback), this.m_Buffer)); this.m_PinnedSingleBuffer = this.m_Buffer; this.m_PinnedSingleBufferOffset = this.m_Offset; this.m_PinnedSingleBufferCount = this.m_Count; this.m_PtrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.m_Buffer, this.m_Offset); this.m_PtrAcceptBuffer = IntPtr.Zero; this.m_WSABuffer.Pointer = this.m_PtrSingleBuffer; this.m_WSABuffer.Length = this.m_Count; this.m_PinState = PinState.SingleBuffer; } else { this.m_PtrNativeOverlapped = new SafeNativeOverlapped(this.m_Overlapped.UnsafePack(new IOCompletionCallback(this.CompletionPortCallback), null)); this.m_PinnedSingleBuffer = null; this.m_PinnedSingleBufferOffset = 0; this.m_PinnedSingleBufferCount = 0; this.m_PtrSingleBuffer = IntPtr.Zero; this.m_PtrAcceptBuffer = IntPtr.Zero; this.m_WSABuffer.Pointer = this.m_PtrSingleBuffer; this.m_WSABuffer.Length = this.m_Count; this.m_PinState = PinState.NoBuffer; } } else { this.m_PtrNativeOverlapped = new SafeNativeOverlapped(this.m_Overlapped.UnsafePack(new IOCompletionCallback(this.CompletionPortCallback), this.m_AcceptBuffer)); this.m_PinnedAcceptBuffer = this.m_AcceptBuffer; this.m_PtrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.m_AcceptBuffer, 0); this.m_PtrSingleBuffer = IntPtr.Zero; this.m_PinState = PinState.SingleAcceptBuffer; } }
internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2 *pHttpResponse, HTTP_CACHE_POLICY *pCachePolicy, uint *pBytesSent, IntPtr pReserved1, uint Reserved2, SafeNativeOverlapped pOverlapped, IntPtr pLogData);
private unsafe CancellationToken CreateDisconnectToken(ulong connectionId) { LogHelper.LogDebug(_logger, "CreateDisconnectToken", "Registering connection for disconnect for connection ID: " + connectionId); // Create a nativeOverlapped callback so we can register for disconnect callback var cts = new CancellationTokenSource(); var returnToken = cts.Token; SafeNativeOverlapped nativeOverlapped = null; var boundHandle = _requestQueue.BoundHandle; nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped( (errorCode, numBytes, overlappedPtr) => { LogHelper.LogDebug(_logger, "CreateDisconnectToken", "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 Callback", exception); } }, null, null)); uint statusCode; try { statusCode = HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueue.Handle, 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, assume the connection has been closed. nativeOverlapped.Dispose(); ConnectionCancellation ignored; _connectionCancellationTokens.TryRemove(connectionId, out ignored); LogHelper.LogDebug(_logger, "HttpWaitForDisconnectEx", new Win32Exception((int)statusCode)); cts.Cancel(); } if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion nativeOverlapped.Dispose(); ConnectionCancellation ignored; _connectionCancellationTokens.TryRemove(connectionId, out ignored); cts.Cancel(); } return(returnToken); }
internal static extern uint HttpWaitForDisconnectEx(SafeHandle requestQueueHandle, ulong connectionId, uint reserved, SafeNativeOverlapped overlapped);
private bool TransmitPackets(SafeCloseSocket socketHandle, IntPtr packetArray, int elementCount, int sendSize, SafeNativeOverlapped overlapped, TransmitFileOptions flags) { EnsureDynamicWinsockMethods(); TransmitPacketsDelegate transmitPackets = m_DynamicWinsockMethods.GetDelegate<TransmitPacketsDelegate>(socketHandle); return transmitPackets(socketHandle, packetArray, elementCount, sendSize, overlapped, flags); }
internal static partial uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO *pSslClientCertInfo, uint sslClientCertInfoSize, uint *pBytesReceived, SafeNativeOverlapped pOverlapped);
private unsafe void InitializeOverlapped() { m_Overlapped = new Overlapped(); m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null)); }