avoid GCHandle in ConnectEx and SendTo on Windows (#86524)
authorTomas Weinfurt <tweinfurt@yahoo.com>
Sat, 20 May 2023 21:58:12 +0000 (14:58 -0700)
committerGitHub <noreply@github.com>
Sat, 20 May 2023 21:58:12 +0000 (17:58 -0400)
* avoid GCHandle in ConnectEx and SendTo on Windows

* s/Span/ReadOnlySpan/ndd

src/libraries/Common/src/Interop/Windows/WinSock/Interop.WSASendTo.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/DynamicWinsockMethods.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs

index 997af04..1f77c3a 100644 (file)
@@ -18,7 +18,7 @@ internal static partial class Interop
             int bufferCount,
             out int bytesTransferred,
             SocketFlags socketFlags,
-            IntPtr socketAddress,
+            ReadOnlySpan<byte> socketAddress,
             int socketAddressSize,
             NativeOverlapped* overlapped,
             IntPtr completionRoutine);
@@ -29,8 +29,7 @@ internal static partial class Interop
             int bufferCount,
             out int bytesTransferred,
             SocketFlags socketFlags,
-            IntPtr socketAddress,
-            int socketAddressSize,
+            ReadOnlySpan<byte> socketAddress,
             NativeOverlapped* overlapped,
             IntPtr completionRoutine)
         {
@@ -38,7 +37,7 @@ internal static partial class Interop
             // We don't want to cause a race in async scenarios.
             // The WSABuffer struct should be unchanged anyway.
             WSABuffer localBuffer = buffer;
-            return WSASendTo(socketHandle, &localBuffer, bufferCount, out bytesTransferred, socketFlags, socketAddress, socketAddressSize, overlapped, completionRoutine);
+            return WSASendTo(socketHandle, &localBuffer, bufferCount, out bytesTransferred, socketFlags, socketAddress, socketAddress.Length, overlapped, completionRoutine);
         }
 
         internal static unsafe SocketError WSASendTo(
@@ -47,15 +46,14 @@ internal static partial class Interop
             int bufferCount,
             [Out] out int bytesTransferred,
             SocketFlags socketFlags,
-            IntPtr socketAddress,
-            int socketAddressSize,
+            ReadOnlySpan<byte> socketAddress,
             NativeOverlapped* overlapped,
             IntPtr completionRoutine)
         {
             Debug.Assert(buffers != null && buffers.Length > 0);
             fixed (WSABuffer* buffersPtr = &buffers[0])
             {
-                return WSASendTo(socketHandle, buffersPtr, bufferCount, out bytesTransferred, socketFlags, socketAddress, socketAddressSize, overlapped, completionRoutine);
+                return WSASendTo(socketHandle, buffersPtr, bufferCount, out bytesTransferred, socketFlags, socketAddress, socketAddress.Length, overlapped, completionRoutine);
             }
         }
     }
index a3abe36..3ade534 100644 (file)
@@ -174,7 +174,7 @@ namespace System.Net.Sockets
                 Marshal.SetLastPInvokeError(Marshal.GetLastSystemError());
 
             }
-            internal unsafe bool ConnectEx(SafeSocketHandle socketHandle, IntPtr socketAddress, int socketAddressSize, IntPtr buffer, int dataLength, out int bytesSent, NativeOverlapped* overlapped)
+            internal unsafe bool ConnectEx(SafeSocketHandle socketHandle, ReadOnlySpan<byte> socketAddress, IntPtr buffer, int dataLength, out int bytesSent, NativeOverlapped* overlapped)
             {
                 IntPtr __socketHandle_gen_native = default;
                 bytesSent = default;
@@ -192,8 +192,9 @@ namespace System.Net.Sockets
                     socketHandle.DangerousAddRef(ref socketHandle__addRefd);
                     __socketHandle_gen_native = socketHandle.DangerousGetHandle();
                     fixed (int* __bytesSent_gen_native = &bytesSent)
+                    fixed (void* socketAddressPtr = &MemoryMarshal.GetReference(socketAddress))
                     {
-                        __retVal_gen_native = ((delegate* unmanaged<IntPtr, IntPtr, int, IntPtr, int, int*, NativeOverlapped*, int>)_target)(__socketHandle_gen_native, socketAddress, socketAddressSize, buffer, dataLength, __bytesSent_gen_native, overlapped);
+                        __retVal_gen_native = ((delegate* unmanaged<IntPtr, void*, int, IntPtr, int, int*, NativeOverlapped*, int>)_target)(__socketHandle_gen_native, socketAddressPtr, socketAddress.Length, buffer, dataLength, __bytesSent_gen_native, overlapped);
                     }
                     Marshal.SetLastPInvokeError(Marshal.GetLastSystemError());
                     //
@@ -338,8 +339,7 @@ namespace System.Net.Sockets
 
     internal unsafe delegate bool ConnectExDelegate(
                 SafeSocketHandle socketHandle,
-                IntPtr socketAddress,
-                int socketAddressSize,
+                ReadOnlySpan<byte> socketAddress,
                 IntPtr buffer,
                 int dataLength,
                 out int bytesSent,
index 11a5607..c7467ee 100644 (file)
@@ -266,8 +266,7 @@ namespace System.Net.Sockets
         }
 
         internal unsafe bool ConnectEx(SafeSocketHandle socketHandle,
-            IntPtr socketAddress,
-            int socketAddressSize,
+            ReadOnlySpan<byte> socketAddress,
             IntPtr buffer,
             int dataLength,
             out int bytesSent,
@@ -275,7 +274,7 @@ namespace System.Net.Sockets
         {
             ConnectExDelegate connectEx = GetDynamicWinsockMethods().GetConnectExDelegate(socketHandle);
 
-            return connectEx(socketHandle, socketAddress, socketAddressSize, buffer, dataLength, out bytesSent, overlapped);
+            return connectEx(socketHandle, socketAddress, buffer, dataLength, out bytesSent, overlapped);
         }
 
         internal unsafe SocketError WSARecvMsg(SafeSocketHandle socketHandle, IntPtr msg, out int bytesTransferred, NativeOverlapped* overlapped, IntPtr completionRoutine)
index 9a6c84a..004b8da 100644 (file)
@@ -295,8 +295,6 @@ namespace System.Net.Sockets
 
             // ConnectEx uses a sockaddr buffer containing the remote address to which to connect.
             // It can also optionally take a single buffer of data to send after the connection is complete.
-            // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
-            PinSocketAddressBuffer();
 
             fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
             {
@@ -305,8 +303,7 @@ namespace System.Net.Sockets
                 {
                     bool success = socket.ConnectEx(
                         handle,
-                        PtrSocketAddressBuffer,
-                        _socketAddress!.Size,
+                        _socketAddress!.Buffer.AsSpan(),
                         (IntPtr)(bufferPtr + _offset),
                         _count,
                         out int bytesTransferred,
@@ -743,9 +740,6 @@ namespace System.Net.Sockets
             // receive data and from which to send data respectively. Single and multiple buffers
             // are handled differently so as to optimize performance for the more common single buffer case.
             //
-            // WSARecvFrom and WSASendTo also uses a sockaddr buffer in which to store the address from which the data was received.
-            // The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
-            PinSocketAddressBuffer();
 
             return _bufferList == null ?
                 DoOperationSendToSingleBuffer(handle, cancellationToken) :
@@ -769,8 +763,7 @@ namespace System.Net.Sockets
                         1,
                         out int bytesTransferred,
                         _socketFlags,
-                        PtrSocketAddressBuffer,
-                        _socketAddress!.Size,
+                        _socketAddress!.Buffer.AsSpan(),
                         overlapped,
                         IntPtr.Zero);
 
@@ -797,8 +790,7 @@ namespace System.Net.Sockets
                     _bufferListInternal!.Count,
                     out int bytesTransferred,
                     _socketFlags,
-                    PtrSocketAddressBuffer,
-                    _socketAddress!.Size,
+                    _socketAddress!.Buffer.AsSpan(),
                     overlapped,
                     IntPtr.Zero);