From 4710a54d5b07fedfc9d8a60110b6557075ce8d3b Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 11 Apr 2021 15:39:13 +0100 Subject: [PATCH 1/2] Drop unnessary WSABuffer[]? from SocketAsyncEventArgs --- .../Windows/WinSock/Interop.WSARecvFrom.cs | 4 +- .../Windows/WinSock/Interop.WSASendTo.cs | 4 +- .../NetworkInterfaceBasicTest.cs | 4 +- .../src/System.Net.Sockets.csproj | 2 +- .../Net/Sockets/DynamicWinsockMethods.cs | 2 +- .../src/System/Net/Sockets/Socket.Windows.cs | 4 +- .../Sockets/SocketAsyncEventArgs.Windows.cs | 246 +++++++++++------- .../System/Net/Sockets/SocketPal.Windows.cs | 12 +- 8 files changed, 167 insertions(+), 111 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSARecvFrom.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSARecvFrom.cs index da2667e0bbe667..441568ee920b41 100644 --- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSARecvFrom.cs +++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSARecvFrom.cs @@ -43,7 +43,7 @@ internal static unsafe SocketError WSARecvFrom( internal static unsafe SocketError WSARecvFrom( SafeHandle socketHandle, - WSABuffer[] buffers, + ReadOnlySpan buffers, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, @@ -53,7 +53,7 @@ internal static unsafe SocketError WSARecvFrom( IntPtr completionRoutine) { Debug.Assert(buffers != null && buffers.Length > 0); - fixed (WSABuffer* buffersPtr = &buffers[0]) + fixed (WSABuffer* buffersPtr = &MemoryMarshal.GetReference(buffers)) { return WSARecvFrom(socketHandle, buffersPtr, bufferCount, out bytesTransferred, ref socketFlags, socketAddressPointer, socketAddressSizePointer, overlapped, completionRoutine); } diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSASendTo.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSASendTo.cs index b98509b1ca27dc..ea000ad8e6ef8e 100644 --- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSASendTo.cs +++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSASendTo.cs @@ -43,7 +43,7 @@ internal static unsafe SocketError WSASendTo( internal static unsafe SocketError WSASendTo( SafeHandle socketHandle, - WSABuffer[] buffers, + ReadOnlySpan buffers, int bufferCount, [Out] out int bytesTransferred, SocketFlags socketFlags, @@ -53,7 +53,7 @@ internal static unsafe SocketError WSASendTo( IntPtr completionRoutine) { Debug.Assert(buffers != null && buffers.Length > 0); - fixed (WSABuffer* buffersPtr = &buffers[0]) + fixed (WSABuffer* buffersPtr = &MemoryMarshal.GetReference(buffers)) { return WSASendTo(socketHandle, buffersPtr, bufferCount, out bytesTransferred, socketFlags, socketAddress, socketAddressSize, overlapped, completionRoutine); } diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs index 2ce80187032907..f8506d4f6d0a95 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs @@ -303,8 +303,8 @@ public async Task NetworkInterface_LoopbackInterfaceIndex_MatchesReceivedPackets } Assert.Equal( - (await receivedTask).PacketInformation.Interface, - ipv6 ? NetworkInterface.IPv6LoopbackInterfaceIndex : NetworkInterface.LoopbackInterfaceIndex); + ipv6 ? NetworkInterface.IPv6LoopbackInterfaceIndex : NetworkInterface.LoopbackInterfaceIndex, + (await receivedTask).PacketInformation.Interface); } } } diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index e33132df5f2ee0..5241a9abb51c05 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -287,9 +287,9 @@ + - diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DynamicWinsockMethods.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DynamicWinsockMethods.cs index 789a1782172bf5..f42d7ab2968f8f 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DynamicWinsockMethods.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DynamicWinsockMethods.cs @@ -146,7 +146,7 @@ internal unsafe delegate bool DisconnectExDelegate( [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] internal unsafe delegate SocketError WSARecvMsgDelegate( SafeSocketHandle socketHandle, - IntPtr msg, + Interop.Winsock.WSAMsg* msg, out int bytesTransferred, NativeOverlapped* overlapped, IntPtr completionRoutine); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs index 6f4e2ed63e77be..ba1b0c75265ee5 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs @@ -251,14 +251,14 @@ internal unsafe bool ConnectEx(SafeSocketHandle socketHandle, return connectEx(socketHandle, socketAddress, socketAddressSize, buffer, dataLength, out bytesSent, overlapped); } - internal unsafe SocketError WSARecvMsg(SafeSocketHandle socketHandle, IntPtr msg, out int bytesTransferred, NativeOverlapped* overlapped, IntPtr completionRoutine) + internal unsafe SocketError WSARecvMsg(SafeSocketHandle socketHandle, Interop.Winsock.WSAMsg* msg, out int bytesTransferred, NativeOverlapped* overlapped, IntPtr completionRoutine) { WSARecvMsgDelegate recvMsg = GetDynamicWinsockMethods().GetWSARecvMsgDelegate(socketHandle); return recvMsg(socketHandle, msg, out bytesTransferred, overlapped, completionRoutine); } - internal unsafe SocketError WSARecvMsgBlocking(SafeSocketHandle socketHandle, IntPtr msg, out int bytesTransferred) + internal unsafe SocketError WSARecvMsgBlocking(SafeSocketHandle socketHandle, Interop.Winsock.WSAMsg* msg, out int bytesTransferred) { WSARecvMsgDelegate recvMsg = GetDynamicWinsockMethods().GetWSARecvMsgDelegate(_handle); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs index 7bca8498ebca1a..3c172d0f3abf2a 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs @@ -13,6 +13,8 @@ namespace System.Net.Sockets { public partial class SocketAsyncEventArgs : EventArgs, IDisposable { + private const int MaxStackWSABuffers = 16; + // Single buffer private MemoryHandle _singleBufferHandle; @@ -54,13 +56,10 @@ private enum SingleBufferHandleState : byte // BufferList property variables. // Note that these arrays are allocated and then grown as necessary, but never shrunk. // Thus the actual in-use length is defined by _bufferListInternal.Count, not the length of these arrays. - private WSABuffer[]? _wsaBufferArrayPinned; private MemoryHandle[]? _multipleBufferMemoryHandles; - // Internal buffers for WSARecvMsg - private byte[]? _wsaMessageBufferPinned; + // Internal buffer for WSARecvMsg private byte[]? _controlBufferPinned; - private WSABuffer[]? _wsaRecvMsgWSABufferArrayPinned; // Internal SocketAddress buffer private GCHandle _socketAddressGCHandle; @@ -428,16 +427,30 @@ internal unsafe SocketError DoOperationReceiveMultiBuffer(SafeSocketHandle handl NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { + int count = _bufferListInternal!.Count; + WSABuffer[]? array = null; + + Span wsaBuffers = count <= MaxStackWSABuffers + ? stackalloc WSABuffer[count] + : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); + + SetupWsaBuffers(wsaBuffers); + SocketFlags flags = _socketFlags; SocketError socketError = Interop.Winsock.WSARecv( handle, - _wsaBufferArrayPinned, - _bufferListInternal!.Count, + wsaBuffers, + count, out int bytesTransferred, ref flags, overlapped, IntPtr.Zero); + if (array is not null) + { + ArrayPool.Shared.Return(array); + } + return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); } catch @@ -500,11 +513,20 @@ internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeSocketHandle h NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { + int count = _bufferListInternal!.Count; + WSABuffer[]? array = null; + + Span wsaBuffers = count <= MaxStackWSABuffers + ? stackalloc WSABuffer[count] + : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); + + SetupWsaBuffers(wsaBuffers); + SocketFlags flags = _socketFlags; SocketError socketError = Interop.Winsock.WSARecvFrom( handle, - _wsaBufferArrayPinned!, - _bufferListInternal!.Count, + wsaBuffers, + count, out int bytesTransferred, ref flags, PtrSocketAddressBuffer, @@ -512,6 +534,11 @@ internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeSocketHandle h overlapped, IntPtr.Zero); + if (array is not null) + { + ArrayPool.Shared.Return(array); + } + return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); } catch @@ -524,103 +551,103 @@ internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeSocketHandle h internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSocketHandle handle, CancellationToken cancellationToken) { // WSARecvMsg uses a WSAMsg descriptor. - // The WSAMsg buffer is a pinned array to avoid complicating the use of Overlapped. // WSAMsg contains a pointer to a sockaddr. // The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped. // WSAMsg contains a pointer to a WSABuffer array describing data buffers. // WSAMsg also contains a single WSABuffer describing a control buffer. PinSocketAddressBuffer(); - // Create a WSAMessageBuffer if none exists yet. - if (_wsaMessageBufferPinned == null) - { - _wsaMessageBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.WSAMsg), pinned: true); - } - - // Create and pin an appropriately sized control buffer if none already - IPAddress? ipAddress = (_socketAddress!.Family == AddressFamily.InterNetworkV6 ? _socketAddress.GetIPAddress() : null); - bool ipv4 = (_currentSocket!.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode - bool ipv6 = _currentSocket.AddressFamily == AddressFamily.InterNetworkV6; - - if (ipv6 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlDataIPv6))) - { - _controlBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.ControlDataIPv6), pinned: true); - } - else if (ipv4 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlData))) - { - _controlBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.ControlData), pinned: true); - } - - // If single buffer we need a single element WSABuffer. - WSABuffer[] wsaRecvMsgWSABufferArray; - uint wsaRecvMsgWSABufferCount; if (_bufferList == null) { - if (_wsaRecvMsgWSABufferArrayPinned == null) - { - _wsaRecvMsgWSABufferArrayPinned = GC.AllocateUninitializedArray(1, pinned: true); - } - fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span)) { Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None); _singleBufferHandleState = SingleBufferHandleState.InProcess; - _wsaRecvMsgWSABufferArrayPinned[0].Pointer = (IntPtr)bufferPtr + _offset; - _wsaRecvMsgWSABufferArrayPinned[0].Length = _count; - wsaRecvMsgWSABufferArray = _wsaRecvMsgWSABufferArrayPinned; - wsaRecvMsgWSABufferCount = 1; + WSABuffer fixedBuffers = default; + + fixedBuffers.Pointer = (IntPtr)bufferPtr + _offset; + fixedBuffers.Length = _count; - return Core(); + return Core(&fixedBuffers, 1); } } else { // Use the multi-buffer WSABuffer. - wsaRecvMsgWSABufferArray = _wsaBufferArrayPinned!; - wsaRecvMsgWSABufferCount = (uint)_bufferListInternal!.Count; + int count = _bufferListInternal!.Count; + WSABuffer[]? array = null; + + Span wsaBuffers = count <= MaxStackWSABuffers + ? stackalloc WSABuffer[count] + : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); + + SetupWsaBuffers(wsaBuffers); + + SocketError socketError; + fixed (WSABuffer* buffersPtr = wsaBuffers) + { + socketError = Core(buffersPtr, (uint)count); + } - return Core(); + if (array is not null) + { + ArrayPool.Shared.Return(array); + } + + return socketError; } // Fill in WSAMessageBuffer, run WSARecvMsg and process the IOCP result. // Logic is in a separate method so we can share code between the (pinned) single buffer and the multi-buffer case - SocketError Core() + SocketError Core(WSABuffer* fixedBuffers, uint count) { - // Fill in WSAMessageBuffer. - Interop.Winsock.WSAMsg* pMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned, 0); - pMessage->socketAddress = PtrSocketAddressBuffer; - pMessage->addressLength = (uint)_socketAddress.Size; - fixed (void* ptrWSARecvMsgWSABufferArray = &wsaRecvMsgWSABufferArray[0]) + IPAddress? ipAddress = (_socketAddress!.Family == AddressFamily.InterNetworkV6 ? _socketAddress.GetIPAddress() : null); + bool ipv4 = (_currentSocket!.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode + bool ipv6 = _currentSocket.AddressFamily == AddressFamily.InterNetworkV6; + + byte[]? controlBuffer = null; + if (ipv4 || ipv6) { - pMessage->buffers = (IntPtr)ptrWSARecvMsgWSABufferArray; + // Allocate a controlBuffer if we haven't yet. + controlBuffer = (_controlBufferPinned ??= GC.AllocateUninitializedArray(sizeof(Interop.Winsock.ControlDataIPv6), pinned: true)); + } + else + { + // Is neither ipv4 or ipv6, release the controlBuffer if we have one allocated. + _controlBufferPinned = null; } - pMessage->count = wsaRecvMsgWSABufferCount; - if (_controlBufferPinned != null) + // Fill in WSAMessageBuffer. + Interop.Winsock.WSAMsg message = new Interop.Winsock.WSAMsg() { - Debug.Assert(_controlBufferPinned.Length > 0); - fixed (void* ptrControlBuffer = &_controlBufferPinned[0]) + socketAddress = PtrSocketAddressBuffer, + addressLength = (uint)_socketAddress.Size, + buffers = (IntPtr)fixedBuffers, + count = count, + flags = _socketFlags, + controlBuffer = new WSABuffer { - pMessage->controlBuffer.Pointer = (IntPtr)ptrControlBuffer; + Length = ipv6 ? sizeof(Interop.Winsock.ControlDataIPv6) : ipv4 ? sizeof(Interop.Winsock.ControlData) : 0, + Pointer = controlBuffer is not null ? Marshal.UnsafeAddrOfPinnedArrayElement(controlBuffer!, 0) : IntPtr.Zero } - pMessage->controlBuffer.Length = _controlBufferPinned.Length; - } - pMessage->flags = _socketFlags; + }; NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { SocketError socketError = socket.WSARecvMsg( handle, - Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned, 0), + &message, out int bytesTransferred, overlapped, IntPtr.Zero); - return _bufferList == null ? + socketError = _bufferList == null ? ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped, cancellationToken) : ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); + + return socketError; } catch { @@ -671,15 +698,29 @@ internal unsafe SocketError DoOperationSendMultiBuffer(SafeSocketHandle handle) NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { + int count = _bufferListInternal!.Count; + WSABuffer[]? array = null; + + Span wsaBuffers = count <= MaxStackWSABuffers + ? stackalloc WSABuffer[count] + : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); + + SetupWsaBuffers(wsaBuffers); + SocketError socketError = Interop.Winsock.WSASend( handle, - _wsaBufferArrayPinned, - _bufferListInternal!.Count, + wsaBuffers, + count, out int bytesTransferred, _socketFlags, overlapped, IntPtr.Zero); + if (array is not null) + { + ArrayPool.Shared.Return(array); + } + return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); } catch @@ -838,10 +879,19 @@ internal unsafe SocketError DoOperationSendToMultiBuffer(SafeSocketHandle handle NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { + int count = _bufferListInternal!.Count; + WSABuffer[]? array = null; + + Span wsaBuffers = count <= MaxStackWSABuffers + ? stackalloc WSABuffer[count] + : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); + + SetupWsaBuffers(wsaBuffers); + SocketError socketError = Interop.Winsock.WSASendTo( handle, - _wsaBufferArrayPinned!, - _bufferListInternal!.Count, + wsaBuffers, + count, out int bytesTransferred, _socketFlags, PtrSocketAddressBuffer, @@ -849,6 +899,11 @@ internal unsafe SocketError DoOperationSendToMultiBuffer(SafeSocketHandle handle overlapped, IntPtr.Zero); + if (array is not null) + { + ArrayPool.Shared.Return(array); + } + return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); } catch @@ -890,18 +945,6 @@ private void SetupMultipleBuffers() _multipleBufferMemoryHandles[i] = _bufferListInternal[i].Array.AsMemory().Pin(); } - if (_wsaBufferArrayPinned == null || _wsaBufferArrayPinned.Length < bufferCount) - { - _wsaBufferArrayPinned = GC.AllocateUninitializedArray(bufferCount, pinned: true); - } - - for (int i = 0; i < bufferCount; i++) - { - ArraySegment localCopy = _bufferListInternal[i]; - _wsaBufferArrayPinned[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array!, localCopy.Offset); - _wsaBufferArrayPinned[i].Length = localCopy.Count; - } - _pinState = PinState.MultipleBuffer; } catch (Exception) @@ -912,6 +955,20 @@ private void SetupMultipleBuffers() } } + private void SetupWsaBuffers(Span wsaBuffers) + { + ReadOnlySpan> buffers = CollectionsMarshal.AsSpan(_bufferListInternal); + Debug.Assert(wsaBuffers.Length >= buffers.Length); + + for (int i = 0; i < buffers.Length; i++) + { + ref readonly ArraySegment segment = ref buffers[i]; + ref WSABuffer buffer = ref wsaBuffers[i]; + buffer.Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array!, segment.Offset); + buffer.Length = segment.Count; + } + } + // Ensures appropriate SocketAddress buffer is pinned. private void PinSocketAddressBuffer() { @@ -1086,11 +1143,13 @@ internal void LogBuffer(int size) if (_bufferList != null) { - for (int i = 0; i < _bufferListInternal!.Count; i++) + Debug.Assert(_bufferListInternal != null); + + for (int i = 0; i < _bufferListInternal.Count; i++) { - WSABuffer wsaBuffer = _wsaBufferArrayPinned![i]; - NetEventSource.DumpBuffer(this, wsaBuffer.Pointer, Math.Min(wsaBuffer.Length, size)); - if ((size -= wsaBuffer.Length) <= 0) + ArraySegment segment = _bufferListInternal[i]; + NetEventSource.DumpBuffer(this, Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array!, segment.Offset), Math.Min(segment.Count, size)); + if ((size -= segment.Count) <= 0) { break; } @@ -1241,22 +1300,25 @@ void CompleteCoreSpin() private unsafe void FinishOperationReceiveMessageFrom() { - Interop.Winsock.WSAMsg* PtrMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned!, 0); - - if (_controlBufferPinned!.Length == sizeof(Interop.Winsock.ControlData)) + byte[]? controlBuffer = _controlBufferPinned; + if (controlBuffer is null) { - // IPv4. - _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlData*)PtrMessage->controlBuffer.Pointer); + // Other. + _receiveMessageFromPacketInfo = default; + return; } - else if (_controlBufferPinned.Length == sizeof(Interop.Winsock.ControlDataIPv6)) + + Interop.Winsock.ControlDataIPv6* controlData = (Interop.Winsock.ControlDataIPv6*)Marshal.UnsafeAddrOfPinnedArrayElement(controlBuffer, 0); + + if ((int)controlData->length == sizeof(Interop.Winsock.ControlData)) { - // IPv6. - _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlDataIPv6*)PtrMessage->controlBuffer.Pointer); + // IPv4. + _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlData*)controlData); } else { - // Other. - _receiveMessageFromPacketInfo = default; + // IPv6. + _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation(controlData); } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs index e157c687fd4a1b..962ae62a6c1b1d 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs @@ -420,12 +420,6 @@ public static unsafe IPPacketInformation GetIPPacketInformation(Interop.Winsock. public static unsafe IPPacketInformation GetIPPacketInformation(Interop.Winsock.ControlDataIPv6* controlBuffer) { - if (controlBuffer->length == (UIntPtr)sizeof(Interop.Winsock.ControlData)) - { - // IPv4 client connectiong to dual mode socket. - return GetIPPacketInformation((Interop.Winsock.ControlData*)controlBuffer); - } - IPAddress address = controlBuffer->length != UIntPtr.Zero ? new IPAddress(new ReadOnlySpan(controlBuffer->address, Interop.Winsock.IPv6AddressLength)) : IPAddress.IPv6None; @@ -468,7 +462,7 @@ public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHan if (socket.WSARecvMsgBlocking( handle, - (IntPtr)(&wsaMsg), + &wsaMsg, out bytesTransferred) == SocketError.SocketError) { return GetLastSocketError(); @@ -484,7 +478,7 @@ public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHan if (socket.WSARecvMsgBlocking( handle, - (IntPtr)(&wsaMsg), + &wsaMsg, out bytesTransferred) == SocketError.SocketError) { return GetLastSocketError(); @@ -499,7 +493,7 @@ public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHan if (socket.WSARecvMsgBlocking( handle, - (IntPtr)(&wsaMsg), + &wsaMsg, out bytesTransferred) == SocketError.SocketError) { return GetLastSocketError(); From 323345f3f0b691acf43ff503de7a4c15e2aeb72a Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 18 May 2021 23:39:50 +0100 Subject: [PATCH 2/2] Tweak --- .../Sockets/SocketAsyncEventArgs.Windows.cs | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs index 3c172d0f3abf2a..f136711a4638f0 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs @@ -559,17 +559,18 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc if (_bufferList == null) { - fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span)) + fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span.Slice(_offset))) { Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None); _singleBufferHandleState = SingleBufferHandleState.InProcess; - WSABuffer fixedBuffers = default; + Span wsaBuffers = stackalloc WSABuffer[1]; - fixedBuffers.Pointer = (IntPtr)bufferPtr + _offset; - fixedBuffers.Length = _count; + wsaBuffers[0].Pointer = (IntPtr)bufferPtr; + wsaBuffers[0].Length = _count; - return Core(&fixedBuffers, 1); + SocketError socketError = Core(wsaBuffers); + return socketError; } } else @@ -578,17 +579,13 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc int count = _bufferListInternal!.Count; WSABuffer[]? array = null; - Span wsaBuffers = count <= MaxStackWSABuffers + Span wsaBuffers = (uint)count <= MaxStackWSABuffers ? stackalloc WSABuffer[count] : (array = ArrayPool.Shared.Rent(count)).AsSpan(0, count); SetupWsaBuffers(wsaBuffers); - SocketError socketError; - fixed (WSABuffer* buffersPtr = wsaBuffers) - { - socketError = Core(buffersPtr, (uint)count); - } + SocketError socketError = Core(wsaBuffers); if (array is not null) { @@ -600,7 +597,7 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc // Fill in WSAMessageBuffer, run WSARecvMsg and process the IOCP result. // Logic is in a separate method so we can share code between the (pinned) single buffer and the multi-buffer case - SocketError Core(WSABuffer* fixedBuffers, uint count) + SocketError Core(Span buffers) { IPAddress? ipAddress = (_socketAddress!.Family == AddressFamily.InterNetworkV6 ? _socketAddress.GetIPAddress() : null); bool ipv4 = (_currentSocket!.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode @@ -619,41 +616,44 @@ SocketError Core(WSABuffer* fixedBuffers, uint count) } // Fill in WSAMessageBuffer. - Interop.Winsock.WSAMsg message = new Interop.Winsock.WSAMsg() + fixed (WSABuffer* bufferPtr = &MemoryMarshal.GetReference(buffers)) { - socketAddress = PtrSocketAddressBuffer, - addressLength = (uint)_socketAddress.Size, - buffers = (IntPtr)fixedBuffers, - count = count, - flags = _socketFlags, - controlBuffer = new WSABuffer + Interop.Winsock.WSAMsg message = new Interop.Winsock.WSAMsg() { - Length = ipv6 ? sizeof(Interop.Winsock.ControlDataIPv6) : ipv4 ? sizeof(Interop.Winsock.ControlData) : 0, - Pointer = controlBuffer is not null ? Marshal.UnsafeAddrOfPinnedArrayElement(controlBuffer!, 0) : IntPtr.Zero - } - }; - - NativeOverlapped* overlapped = AllocateNativeOverlapped(); - try - { - SocketError socketError = socket.WSARecvMsg( - handle, - &message, - out int bytesTransferred, - overlapped, - IntPtr.Zero); - - socketError = _bufferList == null ? - ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped, cancellationToken) : - ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); + socketAddress = PtrSocketAddressBuffer, + addressLength = (uint)_socketAddress.Size, + buffers = (IntPtr)bufferPtr, + count = (uint)buffers.Length, + flags = _socketFlags, + controlBuffer = new WSABuffer + { + Length = ipv6 ? sizeof(Interop.Winsock.ControlDataIPv6) : ipv4 ? sizeof(Interop.Winsock.ControlData) : 0, + Pointer = controlBuffer is not null ? Marshal.UnsafeAddrOfPinnedArrayElement(controlBuffer!, 0) : IntPtr.Zero + } + }; - return socketError; - } - catch - { - _singleBufferHandleState = SingleBufferHandleState.None; - FreeNativeOverlapped(overlapped); - throw; + NativeOverlapped* overlapped = AllocateNativeOverlapped(); + try + { + SocketError socketError = socket.WSARecvMsg( + handle, + &message, + out int bytesTransferred, + overlapped, + IntPtr.Zero); + + socketError = _bufferList == null ? + ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped, cancellationToken) : + ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped); + + return socketError; + } + catch + { + _singleBufferHandleState = SingleBufferHandleState.None; + FreeNativeOverlapped(overlapped); + throw; + } } } }