add ReceiveFromAsync and SendToAsync with SocketAddress overload (#90086)
authorTomas Weinfurt <tweinfurt@yahoo.com>
Tue, 8 Aug 2023 23:23:44 +0000 (16:23 -0700)
committerGitHub <noreply@github.com>
Tue, 8 Aug 2023 23:23:44 +0000 (16:23 -0700)
* cleanup

* update

* cleanup

* feedback

* udpdate

* pal

* windows

* equals

31 files changed:
src/libraries/Common/src/System/Net/IPEndPointExtensions.cs
src/libraries/Common/src/System/Net/Internals/IPAddressExtensions.cs [deleted file]
src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs [deleted file]
src/libraries/Common/src/System/Net/Internals/readme.md [deleted file]
src/libraries/Common/src/System/Net/SocketAddress.cs
src/libraries/Common/src/System/Net/SocketAddressExtensions.cs [new file with mode: 0644]
src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs
src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Windows.cs
src/libraries/Common/src/System/Net/SocketProtocolSupportPal.cs
src/libraries/Common/src/System/Net/Sockets/ProtocolType.cs
src/libraries/Common/src/System/Net/Sockets/SocketType.cs
src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj
src/libraries/System.Net.Primitives/tests/FunctionalTests/SocketAddressTest.cs
src/libraries/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj
src/libraries/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj
src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Unix.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs

index f1723a2..0e242e5 100644 (file)
@@ -58,5 +58,34 @@ namespace System.Net.Sockets
             SetIPAddress(destination, endPoint.Address);
             SocketAddressPal.SetPort(destination, (ushort)endPoint.Port);
         }
+
+        public static bool Equals(this IPEndPoint endPoint, ReadOnlySpan<byte> socketAddressBuffer)
+        {
+            if (socketAddressBuffer.Length >= SocketAddress.GetMaximumAddressSize(endPoint.AddressFamily) &&
+                endPoint.AddressFamily == SocketAddressPal.GetAddressFamily(socketAddressBuffer) &&
+                endPoint.Port == (int)SocketAddressPal.GetPort(socketAddressBuffer))
+            {
+                if (endPoint.AddressFamily == AddressFamily.InterNetwork)
+                {
+#pragma warning disable CS0618
+                    return endPoint.Address.Address == (long)SocketAddressPal.GetIPv4Address(socketAddressBuffer);
+#pragma warning restore CS0618
+                }
+                else
+                {
+                    Span<byte> addressBuffer1 = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
+                    Span<byte> addressBuffer2 = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
+                    SocketAddressPal.GetIPv6Address(socketAddressBuffer, addressBuffer1, out uint scopeid);
+                    if (endPoint.Address.ScopeId != (long)scopeid)
+                    {
+                        return false;
+                    }
+                    endPoint.Address.TryWriteBytes(addressBuffer2, out _);
+                    return addressBuffer1.SequenceEqual(addressBuffer2);
+                }
+            }
+
+            return false;
+        }
     }
 }
diff --git a/src/libraries/Common/src/System/Net/Internals/IPAddressExtensions.cs b/src/libraries/Common/src/System/Net/Internals/IPAddressExtensions.cs
deleted file mode 100644 (file)
index acd2aae..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics;
-
-namespace System.Net.Sockets
-{
-    internal static class IPAddressExtensions
-    {
-        public static IPAddress Snapshot(this IPAddress original)
-        {
-            switch (original.AddressFamily)
-            {
-                case AddressFamily.InterNetwork:
-#pragma warning disable CS0618 // IPAddress.Address is obsoleted, but it's the most efficient way to get the Int32 IPv4 address
-                    return new IPAddress(original.Address);
-#pragma warning restore CS0618
-
-                case AddressFamily.InterNetworkV6:
-                    Span<byte> addressBytes = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
-                    original.TryWriteBytes(addressBytes, out int bytesWritten);
-                    Debug.Assert(bytesWritten == IPAddressParserStatics.IPv6AddressBytes);
-                    return new IPAddress(addressBytes, (uint)original.ScopeId);
-
-                default:
-                    throw new InternalException(original.AddressFamily);
-            }
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs b/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs
deleted file mode 100644 (file)
index 590048a..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics;
-
-namespace System.Net.Sockets
-{
-    internal static partial class IPEndPointExtensions
-    {
-        public static Internals.SocketAddress Serialize(EndPoint endpoint)
-        {
-            Debug.Assert(!(endpoint is DnsEndPoint));
-
-            var ipEndPoint = endpoint as IPEndPoint;
-            if (ipEndPoint != null)
-            {
-                return new Internals.SocketAddress(ipEndPoint.Address, ipEndPoint.Port);
-            }
-
-            System.Net.SocketAddress address = endpoint.Serialize();
-            return GetInternalSocketAddress(address);
-        }
-
-        public static EndPoint Create(this EndPoint thisObj, Internals.SocketAddress socketAddress)
-        {
-            AddressFamily family = socketAddress.Family;
-            if (family != thisObj.AddressFamily)
-            {
-                throw new ArgumentException(SR.Format(SR.net_InvalidAddressFamily, family.ToString(), thisObj.GetType().FullName, thisObj.AddressFamily.ToString()), nameof(socketAddress));
-            }
-
-            if (family == AddressFamily.InterNetwork || family == AddressFamily.InterNetworkV6)
-            {
-                if (socketAddress.Size < 8)
-                {
-                    throw new ArgumentException(SR.Format(SR.net_InvalidSocketAddressSize, socketAddress.GetType().FullName, thisObj.GetType().FullName), nameof(socketAddress));
-                }
-
-                return socketAddress.GetIPEndPoint();
-            }
-            else if (family == AddressFamily.Unknown)
-            {
-                return thisObj;
-            }
-
-            System.Net.SocketAddress address = GetNetSocketAddress(socketAddress);
-            return thisObj.Create(address);
-        }
-
-        private static Internals.SocketAddress GetInternalSocketAddress(System.Net.SocketAddress address)
-        {
-            var result = new Internals.SocketAddress(address.Family, address.Size);
-            for (int index = 0; index < address.Size; index++)
-            {
-                result[index] = address[index];
-            }
-
-            return result;
-        }
-
-        internal static System.Net.SocketAddress GetNetSocketAddress(Internals.SocketAddress address)
-        {
-            var result = new System.Net.SocketAddress(address.Family, address.Size);
-            for (int index = 0; index < address.Size; index++)
-            {
-                result[index] = address[index];
-            }
-
-            return result;
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Net/Internals/readme.md b/src/libraries/Common/src/System/Net/Internals/readme.md
deleted file mode 100644 (file)
index 5835373..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Contracts such as NameResolution and Sockets require internal access to Primitive types. Binary copies of these types have been made within the System.Net.Internals namespace using #ifdef pragmas (source code is reused).
-
-An adaptation layer between .Internals and public types exists within the Extensions classes.
-
index 8c844c3..f4b6522 100644 (file)
@@ -1,26 +1,14 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System.Buffers.Binary;
 using System.Diagnostics;
-using System.Globalization;
 using System.Net.Sockets;
-using System.Text;
 
-#if SYSTEM_NET_PRIMITIVES_DLL
 namespace System.Net
-#else
-namespace System.Net.Internals
-#endif
 {
     // This class is used when subclassing EndPoint, and provides indication
     // on how to format the memory buffers that the platform uses for network addresses.
-#if SYSTEM_NET_PRIMITIVES_DLL
-    public
-#else
-    internal sealed
-#endif
-    class SocketAddress : System.IEquatable<SocketAddress>
+    public class SocketAddress : IEquatable<SocketAddress>
     {
 #pragma warning disable CA1802 // these could be const on Windows but need to be static readonly for Unix
         internal static readonly int IPv6AddressSize = SocketAddressPal.IPv6AddressSize;
@@ -52,7 +40,7 @@ namespace System.Net.Internals
             set
             {
                 ArgumentOutOfRangeException.ThrowIfGreaterThan(value, _buffer.Length);
-                ArgumentOutOfRangeException.ThrowIfLessThan(value, MinSize);
+                ArgumentOutOfRangeException.ThrowIfLessThan(value, 0);
                 _size = value;
             }
         }
@@ -137,13 +125,6 @@ namespace System.Net.Internals
             SocketAddressPal.SetPort(_buffer, unchecked((ushort)port));
         }
 
-        internal SocketAddress(AddressFamily addressFamily, ReadOnlySpan<byte> buffer)
-        {
-            _buffer = buffer.ToArray();
-            _size = _buffer.Length;
-            SocketAddressPal.SetAddressFamily(_buffer, addressFamily);
-        }
-
         /// <summary>This represents underlying memory that can be passed to native OS calls.</summary>
         /// <remarks>
         /// Content of the memory can be invalidated if <see cref="Size"/> is changed or if the SocketAddress is used in another receive call.
@@ -152,44 +133,10 @@ namespace System.Net.Internals
         {
             get
             {
-                return new Memory<byte>(_buffer, 0, _size);
-            }
-        }
-
-        internal IPAddress GetIPAddress()
-        {
-            if (Family == AddressFamily.InterNetworkV6)
-            {
-                Debug.Assert(Size >= IPv6AddressSize);
-
-                Span<byte> address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
-                uint scope;
-                SocketAddressPal.GetIPv6Address(_buffer, address, out scope);
-
-                return new IPAddress(address, (long)scope);
-            }
-            else if (Family == AddressFamily.InterNetwork)
-            {
-                Debug.Assert(Size >= IPv4AddressSize);
-                long address = (long)SocketAddressPal.GetIPv4Address(_buffer) & 0x0FFFFFFFF;
-                return new IPAddress(address);
-            }
-            else
-            {
-#if SYSTEM_NET_PRIMITIVES_DLL
-                throw new SocketException(SocketError.AddressFamilyNotSupported);
-#else
-                throw new SocketException((int)SocketError.AddressFamilyNotSupported);
-#endif
+                return new Memory<byte>(_buffer);
             }
         }
 
-        internal int GetPort() => (int)SocketAddressPal.GetPort(_buffer);
-
-        internal IPEndPoint GetIPEndPoint()
-        {
-            return new IPEndPoint(GetIPAddress(), GetPort());
-        }
 
         public override bool Equals(object? comparand) =>
             comparand is SocketAddress other && Equals(other);
diff --git a/src/libraries/Common/src/System/Net/SocketAddressExtensions.cs b/src/libraries/Common/src/System/Net/SocketAddressExtensions.cs
new file mode 100644 (file)
index 0000000..b260ce1
--- /dev/null
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Net;
+
+namespace System.Net.Sockets
+{
+    internal static partial class SocketAddressExtensions
+    {
+        public static IPAddress GetIPAddress(this SocketAddress socketAddress) => IPEndPointExtensions.GetIPAddress(socketAddress.Buffer.Span);
+        public static int GetPort(this SocketAddress socketAddress)
+        {
+            Debug.Assert(socketAddress.Family == AddressFamily.InterNetwork || socketAddress.Family == AddressFamily.InterNetworkV6);
+            return (int)SocketAddressPal.GetPort(socketAddress.Buffer.Span);
+        }
+
+        public static IPEndPoint GetIPEndPoint(this SocketAddress socketAddress)
+        {
+            return new IPEndPoint(socketAddress.GetIPAddress(), socketAddress.GetPort());
+        }
+
+        public static bool Equals(this SocketAddress socketAddress, EndPoint? endPoint)
+        {
+            if (socketAddress.Family == endPoint?.AddressFamily && endPoint is IPEndPoint ipe)
+            {
+                return ipe.Equals(socketAddress.Buffer.Span);
+            }
+
+            // We could serialize other EndPoints and compare socket addresses.
+            // But that would do two allocations and is probably as expensive as
+            // allocating new EndPoint.
+            // This may change if https://github.com/dotnet/runtime/issues/78993 is done
+            return false;
+        }
+    }
+}
index a7115c9..cb81412 100644 (file)
@@ -8,6 +8,8 @@ namespace System.Net
 {
     internal static partial class SocketProtocolSupportPal
     {
+        private const int DgramSocketType = 2;
+
         private static unsafe bool IsSupported(AddressFamily af)
         {
             // Check for AF_UNIX on iOS/tvOS. The OS claims to support this, but returns EPERM on bind.
index 4cc5ffc..063d04f 100644 (file)
@@ -10,13 +10,14 @@ namespace System.Net
     {
         private static bool IsSupported(AddressFamily af)
         {
+            const int StreamSocketType = 1;
             Interop.Winsock.EnsureInitialized();
 
             IntPtr INVALID_SOCKET = (IntPtr)(-1);
             IntPtr socket = INVALID_SOCKET;
             try
             {
-                socket = Interop.Winsock.WSASocketW(af, DgramSocketType, 0, IntPtr.Zero, 0, (int)Interop.Winsock.SocketConstructorFlags.WSA_FLAG_NO_HANDLE_INHERIT);
+                socket = Interop.Winsock.WSASocketW(af, StreamSocketType, 0, IntPtr.Zero, 0, (int)Interop.Winsock.SocketConstructorFlags.WSA_FLAG_NO_HANDLE_INHERIT);
                 return
                     socket != INVALID_SOCKET ||
                     (SocketError)Marshal.GetLastPInvokeError() != SocketError.AddressFamilyNotSupported;
index d6906e3..a61f47a 100644 (file)
@@ -14,8 +14,6 @@ namespace System.Net
         public static bool OSSupportsIPv4 { get; } = IsSupported(AddressFamily.InterNetwork);
         public static bool OSSupportsUnixDomainSockets { get; } = IsSupported(AddressFamily.Unix);
 
-        private const int DgramSocketType = 2;
-
         private static bool IsIPv6Disabled()
         {
             // First check for the AppContext switch, giving it priority over the environment variable.
index c93b254..ce2090e 100644 (file)
@@ -1,15 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-#if SYSTEM_NET_SOCKETS_DLL
 namespace System.Net.Sockets
 {
     public
-#else
-namespace System.Net.Internals
-{
-    internal
-#endif
     // Specifies the protocols that the Socket class supports.
     enum ProtocolType
     {
index 58dc09a..c3f082f 100644 (file)
@@ -1,15 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-#if SYSTEM_NET_SOCKETS_DLL
 namespace System.Net.Sockets
 {
     public
-#else
-namespace System.Net.Internals
-{
-    internal
-#endif
     // Specifies the type of socket an instance of the System.Net.Sockets.Socket class represents.
     enum SocketType
     {
index e41eda1..39bf0e8 100644 (file)
@@ -60,6 +60,8 @@
              Link="Common\System\Net\CookieParser.cs" />
     <Compile Include="$(CommonPath)System\Net\IPAddressParserStatics.cs"
              Link="Common\System\Net\IPAddressParserStatics.cs" />
+    <Compile Include="$(CommonPath)System\Net\IPEndPointExtensions.cs"
+                 Link="Common\System\Net\IPEndPointExtensions.cs" />
     <Compile Include="$(CommonPath)System\Net\HttpKnownHeaderNames.cs"
              Link="Common\System\Net\HttpKnownHeaderNames.cs" />
     <Compile Include="$(CommonPath)System\Net\TcpValidationHelpers.cs"
@@ -68,6 +70,8 @@
              Link="Common\System\Net\UriScheme.cs" />
     <Compile Include="$(CommonPath)System\Net\SocketAddress.cs"
              Link="Common\System\Net\SocketAddress.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressExtensions.cs"
+             Link="Common\System\Net\SocketAddressExtensions.cs" />
     <Compile Include="$(CommonPath)System\Net\NegotiationInfoClass.cs"
              Link="Common\System\Net\NegotiationInfoClass.cs" />
     <Compile Include="$(CommonPath)System\Net\NetworkInformation\HostInformation.cs"
index 0a185b7..edf913b 100644 (file)
@@ -48,9 +48,8 @@ namespace System.Net.Primitives.Functional.Tests
         {
             SocketAddress sa = new SocketAddress(AddressFamily.InterNetwork);
             Assert.Throws<ArgumentOutOfRangeException>(() => sa.Size = sa.Size + 1);
-
-            sa.Size = 4;
-            Assert.Equal(4, sa.Buffer.Length);
+            sa.Size = 0;
+            Assert.Throws<ArgumentOutOfRangeException>(() => sa.Size = - 1);
         }
 
         [Fact]
index a48a8e9..03c17ba 100644 (file)
              Link="Common\System\HexConverter.cs" />
     <Compile Include="$(CommonPath)System\Obsoletions.cs"
              Link="Common\System\Obsoletions.cs" />
+    <Compile Include="$(CommonPath)System\Net\IPEndPointExtensions.cs"
+             Link="Common\System\Net\IPEndPointExtensions.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressExtensions.cs"
+             Link="Common\System\Net\SocketAddressExtensions.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="HostInformationPalTest.cs" />
index 3bbac4f..0510554 100644 (file)
              Link="Common\System\HexConverter.cs" />
     <Compile Include="$(CommonPath)System\Obsoletions.cs"
              Link="Common\System\Obsoletions.cs" />
+    <Compile Include="$(CommonPath)System\Net\IPEndPointExtensions.cs"
+             Link="Common\System\Net\IPEndPointExtensions.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressExtensions.cs"
+             Link="Common\System\Net\SocketAddressExtensions.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="CookieCollectionTest.cs" />
index 57de68d..fca21b5 100644 (file)
@@ -400,11 +400,12 @@ namespace System.Net.Sockets
         public int ReceiveFrom(byte[] buffer, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; }
         public int ReceiveFrom(System.Span<byte> buffer, ref System.Net.EndPoint remoteEP) { throw null; }
         public int ReceiveFrom(System.Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; }
-        public int ReceiveFrom(System.Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress receivedSocketAddress) { throw null; }
+        public int ReceiveFrom(System.Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress receivedAddress) { throw null; }
         public System.Threading.Tasks.Task<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.ArraySegment<byte> buffer, System.Net.EndPoint remoteEndPoint) { throw null; }
         public System.Threading.Tasks.Task<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.ArraySegment<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; }
         public System.Threading.Tasks.ValueTask<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.Memory<byte> buffer, System.Net.EndPoint remoteEndPoint, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public System.Threading.Tasks.ValueTask<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.Memory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public System.Threading.Tasks.ValueTask<int> ReceiveFromAsync(System.Memory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress receivedAddress, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public bool ReceiveFromAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; }
         public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP, out System.Net.Sockets.IPPacketInformation ipPacketInformation) { throw null; }
         public int ReceiveMessageFrom(System.Span<byte> buffer, ref System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP, out System.Net.Sockets.IPPacketInformation ipPacketInformation) { throw null; }
@@ -451,6 +452,7 @@ namespace System.Net.Sockets
         public bool SendToAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; }
         public System.Threading.Tasks.ValueTask<int> SendToAsync(System.ReadOnlyMemory<byte> buffer, System.Net.EndPoint remoteEP, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public System.Threading.Tasks.ValueTask<int> SendToAsync(System.ReadOnlyMemory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public System.Threading.Tasks.ValueTask<int> SendToAsync(System.ReadOnlyMemory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress socketAddress, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
         public void SetIPProtectionLevel(System.Net.Sockets.IPProtectionLevel level) { }
         public void SetRawSocketOption(int optionLevel, int optionName, System.ReadOnlySpan<byte> optionValue) { }
index d013d5e..41fe916 100644 (file)
              Link="Common\System\Net\ExceptionCheck.cs" />
     <Compile Include="$(CommonPath)System\Net\RangeValidationHelpers.cs"
              Link="Common\System\Net\RangeValidationHelpers.cs" />
-    <Compile Include="$(CommonPath)System\Net\SocketAddress.cs"
-             Link="Common\System\Net\SocketAddress.cs" />
     <Compile Include="$(CommonPath)System\Net\TcpValidationHelpers.cs"
              Link="Common\System\Net\TcpValidationHelpers.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressExtensions.cs"
+             Link="Common\System\Net\SocketAddressExtensions.cs" />
     <Compile Include="$(CommonPath)System\Net\SocketProtocolSupportPal.cs"
              Link="Common\System\Net\SocketProtocolSupportPal.cs" />
-    <!-- System.Net.Internals -->
-    <Compile Include="$(CommonPath)System\Net\Internals\IPEndPointExtensions.cs"
-             Link="Common\System\Net\Internals\IPEndPointExtensions.cs" />
-    <Compile Include="$(CommonPath)System\Net\Internals\IPAddressExtensions.cs"
-             Link="Common\System\Net\Internals\IPAddressExtensions.cs" />
     <Compile Include="$(CommonPath)System\Net\Sockets\SocketExceptionFactory.cs"
              Link="Common\System\Net\Sockets\SocketExceptionFactory.cs" />
     <Compile Include="$(CommonPath)System\Net\Sockets\ProtocolFamily.cs"
index 9631bb6..a04605b 100644 (file)
@@ -414,11 +414,52 @@ namespace System.Net.Sockets
             saea.SetBuffer(buffer);
             saea.SocketFlags = socketFlags;
             saea.RemoteEndPoint = remoteEndPoint;
+            saea._socketAddress = new SocketAddress(AddressFamily);
+            if (remoteEndPoint!.AddressFamily != AddressFamily && AddressFamily == AddressFamily.InterNetworkV6 && IsDualMode)
+            {
+                saea.RemoteEndPoint = s_IPEndPointIPv6;
+            }
             saea.WrapExceptionsForNetworkStream = false;
             return saea.ReceiveFromAsync(this, cancellationToken);
         }
 
         /// <summary>
+        /// Receives data and returns the endpoint of the sending host.
+        /// </summary>
+        /// <param name="buffer">The buffer for the received data.</param>
+        /// <param name="socketFlags">A bitwise combination of SocketFlags values that will be used when receiving the data.</param>
+        /// <param name="receivedAddress">An <see cref="SocketAddress"/>, that will be updated with value of the remote peer.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used to signal the asynchronous operation should be canceled.</param>
+        /// <returns>An asynchronous task that completes with a <see cref="SocketReceiveFromResult"/> containing the number of bytes received and the endpoint of the sending host.</returns>
+        public ValueTask<int> ReceiveFromAsync(Memory<byte> buffer, SocketFlags socketFlags, SocketAddress receivedAddress, CancellationToken cancellationToken = default)
+        {
+            ThrowIfDisposed();
+            ArgumentNullException.ThrowIfNull(receivedAddress, nameof(receivedAddress));
+
+            if (receivedAddress.Size < SocketAddress.GetMaximumAddressSize(AddressFamily))
+            {
+                throw new ArgumentOutOfRangeException(nameof(receivedAddress), SR.net_sockets_address_small);
+            }
+
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return ValueTask.FromCanceled<int>(cancellationToken);
+            }
+
+            AwaitableSocketAsyncEventArgs saea =
+                Interlocked.Exchange(ref _singleBufferReceiveEventArgs, null) ??
+                new AwaitableSocketAsyncEventArgs(this, isReceiveForCaching: true);
+
+            Debug.Assert(saea.BufferList == null);
+            saea.SetBuffer(buffer);
+            saea.SocketFlags = socketFlags;
+            saea.RemoteEndPoint = null;
+            saea._socketAddress = receivedAddress;
+            saea.WrapExceptionsForNetworkStream = false;
+            return saea.ReceiveFromSocketAddressAsync(this, cancellationToken);
+        }
+
+        /// <summary>
         /// Receives data and returns additional information about the sender of the message.
         /// </summary>
         /// <param name="buffer">The buffer for the received data.</param>
@@ -636,12 +677,43 @@ namespace System.Net.Sockets
             Debug.Assert(saea.BufferList == null);
             saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
             saea.SocketFlags = socketFlags;
+            saea._socketAddress = null;
             saea.RemoteEndPoint = remoteEP;
             saea.WrapExceptionsForNetworkStream = false;
             return saea.SendToAsync(this, cancellationToken);
         }
 
         /// <summary>
+        /// Sends data to the specified remote host.
+        /// </summary>
+        /// <param name="buffer">The buffer for the data to send.</param>
+        /// <param name="socketFlags">A bitwise combination of SocketFlags values that will be used when sending the data.</param>
+        /// <param name="socketAddress">The remote host to which to send the data.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
+        /// <returns>An asynchronous task that completes with the number of bytes sent.</returns>
+        public ValueTask<int> SendToAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, SocketAddress socketAddress, CancellationToken cancellationToken = default)
+        {
+            ThrowIfDisposed();
+            ArgumentNullException.ThrowIfNull(socketAddress);
+
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return ValueTask.FromCanceled<int>(cancellationToken);
+            }
+
+            AwaitableSocketAsyncEventArgs saea =
+                Interlocked.Exchange(ref _singleBufferSendEventArgs, null) ??
+                new AwaitableSocketAsyncEventArgs(this, isReceiveForCaching: false);
+
+            Debug.Assert(saea.BufferList == null);
+            saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
+            saea.SocketFlags = socketFlags;
+            saea._socketAddress = socketAddress;
+            saea.WrapExceptionsForNetworkStream = false;
+            return saea.SendToAsync(this, cancellationToken);
+        }
+
+        /// <summary>
         /// Sends the file <paramref name="fileName"/> to a connected <see cref="Socket"/> object.
         /// </summary>
         /// <param name="fileName">A <see cref="string"/> that contains the path and name of the file to be sent. This parameter can be <see langword="null"/>.</param>
@@ -1019,6 +1091,24 @@ namespace System.Net.Sockets
                     ValueTask.FromException<SocketReceiveFromResult>(CreateException(error));
             }
 
+            internal ValueTask<int> ReceiveFromSocketAddressAsync(Socket socket, CancellationToken cancellationToken)
+            {
+                if (socket.ReceiveFromAsync(this, cancellationToken))
+                {
+                    _cancellationToken = cancellationToken;
+                    return new ValueTask<int>(this, _mrvtsc.Version);
+                }
+
+                int bytesTransferred = BytesTransferred;
+                SocketError error = SocketError;
+
+                ReleaseForSyncCompletion();
+
+                return error == SocketError.Success ?
+                    new ValueTask<int>(bytesTransferred) :
+                    ValueTask.FromException<int>(CreateException(error));
+            }
+
             public ValueTask<SocketReceiveMessageFromResult> ReceiveMessageFromAsync(Socket socket, CancellationToken cancellationToken)
             {
                 if (socket.ReceiveMessageFromAsync(this, cancellationToken))
index 8eae5f8..c7fd839 100644 (file)
@@ -26,12 +26,12 @@ namespace System.Net.Sockets
         private sealed class CachedSerializedEndPoint
         {
             public readonly IPEndPoint IPEndPoint;
-            public readonly Internals.SocketAddress SocketAddress;
+            public readonly SocketAddress SocketAddress;
 
             public CachedSerializedEndPoint(IPAddress address)
             {
                 IPEndPoint = new IPEndPoint(address, 0);
-                SocketAddress = IPEndPointExtensions.Serialize(IPEndPoint);
+                SocketAddress = IPEndPoint.Serialize();
             }
         }
 
@@ -70,7 +70,7 @@ namespace System.Net.Sockets
             IPAddress tempAddress = _addressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any;
             IPEndPoint ep = new IPEndPoint(tempAddress, 0);
 
-            Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(ep);
+            SocketAddress socketAddress = ep.Serialize();
             int size = socketAddress.Buffer.Length;
             unsafe
             {
index d54fac5..b918ceb 100644 (file)
@@ -7,7 +7,6 @@ using System.ComponentModel;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
-using System.Net.Internals;
 using System.Runtime.CompilerServices;
 using System.Runtime.ExceptionServices;
 using System.Runtime.InteropServices;
@@ -24,6 +23,7 @@ namespace System.Net.Sockets
         internal const int DefaultCloseTimeout = -1; // NOTE: changing this default is a breaking change.
 
         private static readonly IPAddress s_IPAddressAnyMapToIPv6 = IPAddress.Any.MapToIPv6();
+        private static readonly IPEndPoint s_IPEndPointIPv6 = new IPEndPoint(s_IPAddressAnyMapToIPv6, 0);
 
         private SafeSocketHandle _handle;
 
@@ -152,7 +152,6 @@ namespace System.Net.Sockets
 
                     // Try to get the local end point.  That will in turn enable the remote
                     // end point to be retrieved on-demand when the property is accessed.
-                    Internals.SocketAddress? socketAddress = null;
                     switch (_addressFamily)
                     {
                         case AddressFamily.InterNetwork:
@@ -170,8 +169,7 @@ namespace System.Net.Sockets
                             break;
 
                         case AddressFamily.Unix:
-                            socketAddress = new Internals.SocketAddress(AddressFamily.Unix, buffer.Slice(0, bufferLength));
-                            _rightEndPoint = new UnixDomainSocketEndPoint(IPEndPointExtensions.GetNetSocketAddress(socketAddress));
+                            _rightEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength));
                             break;
                     }
 
@@ -203,8 +201,7 @@ namespace System.Net.Sockets
                                             break;
 
                                         case AddressFamily.Unix:
-                                            socketAddress = new Internals.SocketAddress(AddressFamily.Unix, buffer.Slice(0, bufferLength));
-                                            _remoteEndPoint = new UnixDomainSocketEndPoint(IPEndPointExtensions.GetNetSocketAddress(socketAddress));
+                                            _remoteEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength));
                                             break;
                                     }
 
@@ -764,11 +761,11 @@ namespace System.Net.Sockets
 
             if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"localEP:{localEP}");
 
-            Internals.SocketAddress socketAddress = Serialize(ref localEP);
+            SocketAddress socketAddress = Serialize(ref localEP);
             DoBind(localEP, socketAddress);
         }
 
-        private void DoBind(EndPoint endPointSnapshot, Internals.SocketAddress socketAddress)
+        private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
         {
             // Mitigation for Blue Screen of Death (Win7, maybe others).
             IPEndPoint? ipEndPoint = endPointSnapshot as IPEndPoint;
@@ -781,7 +778,7 @@ namespace System.Net.Sockets
             SocketError errorCode = SocketPal.Bind(
                 _handle,
                 _protocolType,
-                socketAddress.Buffer.Span);
+                socketAddress.Buffer.Span.Slice(0, socketAddress.Size));
 
             // Throw an appropriate SocketException if the native call fails.
             if (errorCode != SocketError.Success)
@@ -834,7 +831,7 @@ namespace System.Net.Sockets
 
             ValidateForMultiConnect(isMultiEndpoint: false);
 
-            Internals.SocketAddress socketAddress = Serialize(ref remoteEP);
+            SocketAddress socketAddress = Serialize(ref remoteEP);
             _pendingConnectRightEndPoint = remoteEP;
             _nonBlockingConnectInProgress = !Blocking;
 
@@ -1010,10 +1007,7 @@ namespace System.Net.Sockets
             ValidateBlockingMode();
             if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"SRC:{LocalEndPoint}");
 
-            Internals.SocketAddress socketAddress =
-                _addressFamily == AddressFamily.InterNetwork || _addressFamily == AddressFamily.InterNetworkV6 ?
-                    IPEndPointExtensions.Serialize(_rightEndPoint) :
-                    new Internals.SocketAddress(_addressFamily, SocketPal.MaximumAddressSize); // may be different size.
+            SocketAddress socketAddress = new SocketAddress(_addressFamily);
 
             if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStart(socketAddress);
 
@@ -1287,10 +1281,10 @@ namespace System.Net.Sockets
             ValidateBlockingMode();
             if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"SRC:{LocalEndPoint} size:{size} remoteEP:{remoteEP}");
 
-            Internals.SocketAddress socketAddress = Serialize(ref remoteEP);
+            SocketAddress socketAddress = Serialize(ref remoteEP);
 
             int bytesTransferred;
-            SocketError errorCode = SocketPal.SendTo(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, out bytesTransferred);
+            SocketError errorCode = SocketPal.SendTo(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer.Slice(0, socketAddress.Size), out bytesTransferred);
 
             // Throw an appropriate SocketException if the native call fails.
             if (errorCode != SocketError.Success)
@@ -1359,10 +1353,10 @@ namespace System.Net.Sockets
 
             ValidateBlockingMode();
 
-            Internals.SocketAddress socketAddress = Serialize(ref remoteEP);
+            SocketAddress socketAddress = Serialize(ref remoteEP);
 
             int bytesTransferred;
-            SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.Buffer, out bytesTransferred);
+            SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.Buffer.Slice(0, socketAddress.Size), out bytesTransferred);
 
             // Throw an appropriate SocketException if the native call fails.
             if (errorCode != SocketError.Success)
@@ -1401,7 +1395,7 @@ namespace System.Net.Sockets
             ValidateBlockingMode();
 
             int bytesTransferred;
-            SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.Buffer, out bytesTransferred);
+            SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.Buffer.Slice(0, socketAddress.Size), out bytesTransferred);
 
             // Throw an appropriate SocketException if the native call fails.
             if (errorCode != SocketError.Success)
@@ -1578,14 +1572,11 @@ namespace System.Net.Sockets
             // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
             // with the right address family.
             EndPoint endPointSnapshot = remoteEP;
-            Internals.SocketAddress socketAddress = Serialize(ref endPointSnapshot);
-
-            // Save a copy of the original EndPoint.
-            Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);
+            SocketAddress socketAddress = Serialize(ref endPointSnapshot);
 
             SetReceivingPacketInformation();
 
-            Internals.SocketAddress receiveAddress;
+            SocketAddress receiveAddress;
             int bytesTransferred;
             SocketError errorCode = SocketPal.ReceiveMessageFrom(this, _handle, buffer, offset, size, ref socketFlags, socketAddress, out receiveAddress, out ipPacketInformation, out bytesTransferred);
 
@@ -1601,7 +1592,7 @@ namespace System.Net.Sockets
                 if (errorCode == SocketError.Success && SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived();
             }
 
-            if (!socketAddressOriginal.Equals(receiveAddress))
+            if (!SocketAddressExtensions.Equals(socketAddress, remoteEP))
             {
                 try
                 {
@@ -1666,14 +1657,11 @@ namespace System.Net.Sockets
             // WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
             // with the right address family.
             EndPoint endPointSnapshot = remoteEP;
-            Internals.SocketAddress socketAddress = Serialize(ref endPointSnapshot);
-
-            // Save a copy of the original EndPoint.
-            Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);
+            SocketAddress socketAddress = Serialize(ref endPointSnapshot);
 
             SetReceivingPacketInformation();
 
-            Internals.SocketAddress receiveAddress;
+            SocketAddress receiveAddress;
             int bytesTransferred;
             SocketError errorCode = SocketPal.ReceiveMessageFrom(this, _handle, buffer, ref socketFlags, socketAddress, out receiveAddress, out ipPacketInformation, out bytesTransferred);
 
@@ -1689,7 +1677,7 @@ namespace System.Net.Sockets
                 if (errorCode == SocketError.Success && SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived();
             }
 
-            if (!socketAddressOriginal.Equals(receiveAddress))
+            if (!SocketAddressExtensions.Equals(socketAddress, remoteEP))
             {
                 try
                 {
@@ -1721,8 +1709,11 @@ namespace System.Net.Sockets
             // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
             // with the right address family.
             EndPoint endPointSnapshot = remoteEP;
-            Internals.SocketAddress socketAddress = Serialize(ref endPointSnapshot);
-            Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);
+            SocketAddress socketAddress = new SocketAddress(AddressFamily);
+            if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
+            {
+               endPointSnapshot = s_IPEndPointIPv6;
+            }
 
             int bytesTransferred;
             SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, out int socketAddressLength, out bytesTransferred);
@@ -1749,15 +1740,19 @@ namespace System.Net.Sockets
 
             socketAddress.Size = socketAddressLength;
 
-            if (!socketAddressOriginal.Equals(socketAddress))
+            if (socketAddressLength > 0 && !socketAddress.Equals(remoteEP) || remoteEP.AddressFamily != socketAddress.Family)
             {
                 try
                 {
                     if (endPointSnapshot.AddressFamily == socketAddress.Family)
                     {
-                        remoteEP = _remoteEndPoint != null ? _remoteEndPoint.Create(socketAddress) : socketAddress.GetIPEndPoint();
+                        remoteEP = endPointSnapshot.Create(socketAddress);
                     }
-                    else if (endPointSnapshot.AddressFamily == AddressFamily.InterNetworkV6 && socketAddress.Family == AddressFamily.InterNetwork)
+                    //else if (socketAddress.Family == AddressFamily.InterNetworkV6 && IsDualMode)
+                    //{
+                    //    remoteEP = socketAddress.GetIPEndPoint();
+                    //}
+                    else if (AddressFamily == AddressFamily.InterNetworkV6 && socketAddress.Family == AddressFamily.InterNetwork)
                     {
                         // We expect IPv6 on DualMode sockets but we can also get plain old IPv4
                         remoteEP = new IPEndPoint(socketAddress.GetIPAddress().MapToIPv6(), socketAddress.GetPort());
@@ -1830,8 +1825,11 @@ namespace System.Net.Sockets
             // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
             // with the right address family.
             EndPoint endPointSnapshot = remoteEP;
-            Internals.SocketAddress socketAddress = Serialize(ref endPointSnapshot);
-            Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);
+            SocketAddress socketAddress = new SocketAddress(AddressFamily);
+            if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
+            {
+                endPointSnapshot = s_IPEndPointIPv6;
+            }
 
             int bytesTransferred;
             SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, socketAddress.Buffer, out int socketAddressLength, out bytesTransferred);
@@ -1857,13 +1855,13 @@ namespace System.Net.Sockets
             }
 
             socketAddress.Size = socketAddressLength;
-            if (!socketAddressOriginal.Equals(socketAddress))
+            if (socketAddressLength > 0 && !socketAddress.Equals(remoteEP) || remoteEP.AddressFamily != socketAddress.Family)
             {
                 try
                 {
                     if (endPointSnapshot.AddressFamily == socketAddress.Family)
                     {
-                        remoteEP = _remoteEndPoint != null ? _remoteEndPoint.Create(socketAddress) : socketAddress.GetIPEndPoint();
+                          remoteEP = endPointSnapshot.Create(socketAddress);
                     }
                     else if (endPointSnapshot.AddressFamily == AddressFamily.InterNetworkV6 && socketAddress.Family == AddressFamily.InterNetwork)
                     {
@@ -1892,28 +1890,27 @@ namespace System.Net.Sockets
         /// </summary>
         /// <param name="buffer">A span of bytes that is the storage location for received data.</param>
         /// <param name="socketFlags">A bitwise combination of the <see cref="SocketFlags"/> values.</param>
-        /// <param name="receivedSocketAddress">An <see cref="SocketAddress"/>, that will be updated with value of the remote peer.</param>
+        /// <param name="receivedAddress">An <see cref="SocketAddress"/>, that will be updated with value of the remote peer.</param>
         /// <returns>The number of bytes received.</returns>
         /// <exception cref="ArgumentNullException"><c>remoteEP</c> is <see langword="null" />.</exception>
         /// <exception cref="SocketException">An error occurred when attempting to access the socket.</exception>
         /// <exception cref="ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
-        public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, SocketAddress receivedSocketAddress)
+        public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, SocketAddress receivedAddress)
         {
             ThrowIfDisposed();
+            ArgumentNullException.ThrowIfNull(receivedAddress, nameof(receivedAddress));
 
-            if (receivedSocketAddress.Size < SocketAddress.GetMaximumAddressSize(AddressFamily))
+            if (receivedAddress.Size < SocketAddress.GetMaximumAddressSize(AddressFamily))
             {
-                throw new ArgumentOutOfRangeException(nameof(receivedSocketAddress), SR.net_sockets_address_small);
+                throw new ArgumentOutOfRangeException(nameof(receivedAddress), SR.net_sockets_address_small);
             }
 
             ValidateBlockingMode();
 
             int bytesTransferred;
-            SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, receivedSocketAddress.Buffer, out int socketAddressSize, out bytesTransferred);
-            if (socketAddressSize > 0)
-            {
-                receivedSocketAddress.Size = socketAddressSize;
-            }
+            SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, receivedAddress.Buffer, out int socketAddressSize, out bytesTransferred);
+            receivedAddress.Size = socketAddressSize;
+
             UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred);
             // If the native call fails we'll throw a SocketException.
             if (errorCode != SocketError.Success)
@@ -2934,20 +2931,33 @@ namespace System.Net.Sockets
             ThrowIfDisposed();
 
             ArgumentNullException.ThrowIfNull(e);
-            if (e.RemoteEndPoint == null)
-            {
-                throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e));
-            }
-            if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily))
+            EndPoint? endPointSnapshot = e.RemoteEndPoint;
+            if (e._socketAddress == null)
             {
-                throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), nameof(e));
-            }
+                if (endPointSnapshot is DnsEndPoint)
+                {
+                    throw new ArgumentException(SR.Format(SR.net_sockets_invalid_dnsendpoint, "e.RemoteEndPoint"), nameof(e));
+                }
 
-            // We don't do a CAS demand here because the contents of remoteEP aren't used by
-            // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
-            // with the right address family.
-            EndPoint endPointSnapshot = e.RemoteEndPoint;
-            e._socketAddress = Serialize(ref endPointSnapshot);
+                if (endPointSnapshot == null)
+                {
+                    throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e));
+                }
+                if (!CanTryAddressFamily(endPointSnapshot.AddressFamily))
+                {
+                    throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, endPointSnapshot.AddressFamily, _addressFamily), nameof(e));
+                }
+
+                // We don't do a CAS demand here because the contents of remoteEP aren't used by
+                // WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
+                // with the right address family.
+
+                if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork && IsDualMode)
+                {
+                    endPointSnapshot = s_IPEndPointIPv6;
+                }
+                e._socketAddress ??= new SocketAddress(AddressFamily);
+            }
 
             // DualMode sockets may have updated the endPointSnapshot, and it has to have the same AddressFamily as
             // e.m_SocketAddres for Create to work later.
@@ -3083,14 +3093,18 @@ namespace System.Net.Sockets
             ThrowIfDisposed();
 
             ArgumentNullException.ThrowIfNull(e);
-            if (e.RemoteEndPoint == null)
+
+            EndPoint? endPointSnapshot = e.RemoteEndPoint;
+            if (e._socketAddress == null)
             {
-                throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e));
-            }
+                if (endPointSnapshot == null)
+                {
+                    throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e));
+                }
 
-            // Prepare SocketAddress
-            EndPoint endPointSnapshot = e.RemoteEndPoint;
-            e._socketAddress = Serialize(ref endPointSnapshot);
+                // Prepare SocketAddress
+                e._socketAddress = Serialize(ref endPointSnapshot);
+            }
 
             // Prepare for and make the native call.
             e.StartOperationCommon(this, SocketAsyncOperation.SendTo);
@@ -3131,7 +3145,7 @@ namespace System.Net.Sockets
         // Internal and private methods
         //
 
-        internal static void GetIPProtocolInformation(AddressFamily addressFamily, Internals.SocketAddress socketAddress, out bool isIPv4, out bool isIPv6)
+        internal static void GetIPProtocolInformation(AddressFamily addressFamily, SocketAddress socketAddress, out bool isIPv4, out bool isIPv6)
         {
             bool isIPv4MappedToIPv6 = socketAddress.Family == AddressFamily.InterNetworkV6 && socketAddress.GetIPAddress().IsIPv4MappedToIPv6;
             isIPv4 = addressFamily == AddressFamily.InterNetwork || isIPv4MappedToIPv6; // DualMode
@@ -3147,7 +3161,7 @@ namespace System.Net.Sockets
                 endPoint.Serialize().Size;
         }
 
-        private Internals.SocketAddress Serialize(ref EndPoint remoteEP)
+        private SocketAddress Serialize(ref EndPoint remoteEP)
         {
             if (remoteEP is IPEndPoint ip)
             {
@@ -3163,16 +3177,16 @@ namespace System.Net.Sockets
                 throw new ArgumentException(SR.Format(SR.net_sockets_invalid_dnsendpoint, nameof(remoteEP)), nameof(remoteEP));
             }
 
-            return IPEndPointExtensions.Serialize(remoteEP);
+            return remoteEP.Serialize();
         }
 
-        private void DoConnect(EndPoint endPointSnapshot, Internals.SocketAddress socketAddress)
+        private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
         {
             SocketsTelemetry.Log.ConnectStart(socketAddress);
             SocketError errorCode;
             try
             {
-                errorCode = SocketPal.Connect(_handle, socketAddress.Buffer);
+                errorCode = SocketPal.Connect(_handle, socketAddress.Buffer.Slice(0, socketAddress.Size));
             }
             catch (Exception ex)
             {
@@ -3756,6 +3770,12 @@ namespace System.Net.Sockets
         private void ValidateReceiveFromEndpointAndState(EndPoint remoteEndPoint, string remoteEndPointArgumentName)
         {
             ArgumentNullException.ThrowIfNull(remoteEndPoint, remoteEndPointArgumentName);
+
+            if (remoteEndPoint is DnsEndPoint)
+            {
+                throw new ArgumentException(SR.Format(SR.net_sockets_invalid_dnsendpoint, remoteEndPointArgumentName), remoteEndPointArgumentName);
+            }
+
             if (!CanTryAddressFamily(remoteEndPoint.AddressFamily))
             {
                 throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, remoteEndPoint.AddressFamily, _addressFamily), remoteEndPointArgumentName);
index ba34da0..26b3cf8 100644 (file)
@@ -196,7 +196,7 @@ namespace System.Net.Sockets
             bool isIPv4, isIPv6;
             Socket.GetIPProtocolInformation(socket.AddressFamily, _socketAddress!, out isIPv4, out isIPv6);
 
-            int socketAddressSize = _socketAddress!.Size;
+            int socketAddressSize = _socketAddress!.Buffer.Length;
             int bytesReceived;
             SocketFlags receivedFlags;
             IPPacketInformation ipPacketInformation;
@@ -336,7 +336,7 @@ namespace System.Net.Sockets
             }
         }
 
-        private SocketError FinishOperationAccept(Internals.SocketAddress remoteSocketAddress)
+        private SocketError FinishOperationAccept(SocketAddress remoteSocketAddress)
         {
             new ReadOnlySpan<byte>(_acceptBuffer, 0, _acceptAddressBufferCount).CopyTo(remoteSocketAddress.Buffer.Span);
             remoteSocketAddress.Size = _acceptAddressBufferCount;
@@ -366,7 +366,7 @@ namespace System.Net.Sockets
             return SocketError.Success;
         }
 
-        private void UpdateReceivedSocketAddress(Internals.SocketAddress socketAddress)
+        private void UpdateReceivedSocketAddress(SocketAddress socketAddress)
         {
             if (_socketAddressSize > 0)
             {
index 2aa782d..bd193ee 100644 (file)
@@ -1029,7 +1029,7 @@ namespace System.Net.Sockets
             }
         }
 
-        private unsafe SocketError FinishOperationAccept(Internals.SocketAddress remoteSocketAddress)
+        private unsafe SocketError FinishOperationAccept(SocketAddress remoteSocketAddress)
         {
             SocketError socketError;
             IntPtr localAddr;
@@ -1120,7 +1120,7 @@ namespace System.Net.Sockets
             }
         }
 
-        private unsafe void UpdateReceivedSocketAddress(Internals.SocketAddress socketAddress)
+        private unsafe void UpdateReceivedSocketAddress(SocketAddress socketAddress)
         {
             Debug.Assert(_socketAddressPtr != IntPtr.Zero);
             int size = *((int*)_socketAddressPtr);
index b56873a..e04739d 100644 (file)
@@ -65,7 +65,7 @@ namespace System.Net.Sockets
         private int _acceptAddressBufferCount;
 
         // Internal SocketAddress buffer.
-        internal Internals.SocketAddress? _socketAddress;
+        internal SocketAddress? _socketAddress;
 
         // Misc state variables.
         private readonly bool _flowExecutionContext;
@@ -866,7 +866,7 @@ namespace System.Net.Sockets
             {
                 case SocketAsyncOperation.Accept:
                     // Get the endpoint.
-                    Internals.SocketAddress remoteSocketAddress = IPEndPointExtensions.Serialize(_currentSocket!._rightEndPoint!);
+                    SocketAddress remoteSocketAddress = _currentSocket!._rightEndPoint!.Serialize();
 
                     socketError = FinishOperationAccept(remoteSocketAddress);
 
@@ -923,8 +923,7 @@ namespace System.Net.Sockets
                 case SocketAsyncOperation.ReceiveFrom:
                     // Deal with incoming address.
                     UpdateReceivedSocketAddress(_socketAddress!);
-                    Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(_remoteEndPoint!);
-                    if (!socketAddressOriginal.Equals(_socketAddress))
+                    if (_remoteEndPoint != null && !SocketAddressExtensions.Equals(_socketAddress!, _remoteEndPoint))
                     {
                         try
                         {
@@ -946,8 +945,7 @@ namespace System.Net.Sockets
                 case SocketAsyncOperation.ReceiveMessageFrom:
                     // Deal with incoming address.
                     UpdateReceivedSocketAddress(_socketAddress!);
-                    socketAddressOriginal = IPEndPointExtensions.Serialize(_remoteEndPoint!);
-                    if (!socketAddressOriginal.Equals(_socketAddress))
+                    if (!SocketAddressExtensions.Equals(_socketAddress!, _remoteEndPoint))
                     {
                         try
                         {
index c57639f..0220f9b 100644 (file)
@@ -842,12 +842,6 @@ namespace System.Net.Sockets
                 {
                     bytesReceived = received;
                     errorCode = SocketError.Success;
-                    if (socketAddress.Length > 0 && receivedSocketAddressLength == 0)
-                    {
-                        // We can fail to get peer address on TCP
-                        receivedSocketAddressLength = socketAddress.Length;
-                        SocketAddressPal.Clear(socketAddress);
-                    }
                     return true;
                 }
 
@@ -1273,7 +1267,7 @@ namespace System.Net.Sockets
             return completed ? errorCode : SocketError.WouldBlock;
         }
 
-        public static SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, byte[] buffer, int offset, int count, ref SocketFlags socketFlags, Internals.SocketAddress socketAddress, out Internals.SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
+        public static SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, byte[] buffer, int offset, int count, ref SocketFlags socketFlags, SocketAddress socketAddress, out SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
         {
             int socketAddressLen;
 
@@ -1299,7 +1293,7 @@ namespace System.Net.Sockets
         }
 
 
-        public static SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, Span<byte> buffer, ref SocketFlags socketFlags, Internals.SocketAddress socketAddress, out Internals.SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
+        public static SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, Span<byte> buffer, ref SocketFlags socketFlags, SocketAddress socketAddress, out SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
         {
             int socketAddressLen;
 
index b474447..d47c3bd 100644 (file)
@@ -433,12 +433,12 @@ namespace System.Net.Sockets
             return new IPPacketInformation(address, (int)controlBuffer->index);
         }
 
-        public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, byte[] buffer, int offset, int size, ref SocketFlags socketFlags, Internals.SocketAddress socketAddress, out Internals.SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
+        public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, byte[] buffer, int offset, int size, ref SocketFlags socketFlags, SocketAddress socketAddress, out SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
         {
             return ReceiveMessageFrom(socket, handle, new Span<byte>(buffer, offset, size), ref socketFlags, socketAddress, out receiveAddress, out ipPacketInformation, out bytesTransferred);
         }
 
-        public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, Span<byte> buffer, ref SocketFlags socketFlags, Internals.SocketAddress socketAddress, out Internals.SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
+        public static unsafe SocketError ReceiveMessageFrom(Socket socket, SafeSocketHandle handle, Span<byte> buffer, ref SocketFlags socketFlags, SocketAddress socketAddress, out SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
         {
             bool ipv4, ipv6;
             Socket.GetIPProtocolInformation(socket.AddressFamily, socketAddress, out ipv4, out ipv6);
index 9790aea..bea730b 100644 (file)
@@ -77,7 +77,7 @@ namespace System.Net.Sockets
         }
 
         [NonEvent]
-        public void ConnectStart(Internals.SocketAddress address)
+        public void ConnectStart(SocketAddress address)
         {
             Interlocked.Increment(ref _currentOutgoingConnectAttempts);
 
@@ -107,7 +107,7 @@ namespace System.Net.Sockets
         }
 
         [NonEvent]
-        public void AcceptStart(Internals.SocketAddress address)
+        public void AcceptStart(SocketAddress address)
         {
             if (IsEnabled(EventLevel.Informational, EventKeywords.All))
             {
index 0a06e5d..fab23b5 100644 (file)
@@ -64,19 +64,13 @@ namespace System.Net.Sockets
 
         internal static int MaxAddressSize => s_nativeAddressSize;
 
-        internal UnixDomainSocketEndPoint(SocketAddress socketAddress)
+        internal UnixDomainSocketEndPoint(ReadOnlySpan<byte> socketAddress)
         {
-            ArgumentNullException.ThrowIfNull(socketAddress);
+            Debug.Assert(AddressFamily.Unix == SocketAddressPal.GetAddressFamily(socketAddress));
 
-            if (socketAddress.Family != EndPointAddressFamily ||
-                socketAddress.Size > s_nativeAddressSize)
+            if (socketAddress.Length > s_nativePathOffset)
             {
-                throw new ArgumentOutOfRangeException(nameof(socketAddress));
-            }
-
-            if (socketAddress.Size > s_nativePathOffset)
-            {
-                _encodedPath = new byte[socketAddress.Size - s_nativePathOffset];
+                _encodedPath = new byte[socketAddress.Length - s_nativePathOffset];
                 for (int i = 0; i < _encodedPath.Length; i++)
                 {
                     _encodedPath[i] = socketAddress[s_nativePathOffset + i];
@@ -118,7 +112,7 @@ namespace System.Net.Sockets
         /// <summary>Creates an <see cref="EndPoint"/> instance from a <see cref="SocketAddress"/> instance.</summary>
         /// <param name="socketAddress">The socket address that serves as the endpoint for a connection.</param>
         /// <returns>A new <see cref="EndPoint"/> instance that is initialized from the specified <see cref="SocketAddress"/> instance.</returns>
-        public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress);
+        public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress.Buffer.Span.Slice(0, socketAddress.Size));
 
         /// <summary>Gets the address family to which the endpoint belongs.</summary>
         /// <value>One of the <see cref="AddressFamily"/> values.</value>
index d9d75bf..6c5c2d8 100644 (file)
@@ -975,7 +975,7 @@ namespace System.Net.Sockets.Tests
             
             int port = socket.BindToAnonymousPort(IPAddress.IPv6Loopback);
             EndPoint receivedFrom = new DnsEndPoint("localhost", port, AddressFamily.InterNetworkV6);
-            await AssertExtensions.ThrowsAsync<ArgumentException>("remoteEP", () => ReceiveFromAsync(socket, new byte[1], receivedFrom));
+            await Assert.ThrowsAsync<ArgumentException>(() => ReceiveFromAsync(socket, new byte[1], receivedFrom));
         }
 
         [Fact]
index 1a720df..1a5ec7d 100644 (file)
@@ -1,8 +1,6 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System.Collections.Generic;
-using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
 using Xunit;
@@ -65,6 +63,16 @@ namespace System.Net.Sockets.Tests
         }
 
         [Fact]
+        public async Task NullSocketAddress_Throws_ArgumentException()
+        {
+            using Socket socket = CreateSocket();
+            SocketAddress socketAddress = null;
+
+            Assert.Throws<ArgumentNullException>(() => socket.ReceiveFrom(new byte[1], SocketFlags.None, socketAddress));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => socket.ReceiveFromAsync(new Memory<byte>(new byte[1]), SocketFlags.None, socketAddress).AsTask());
+        }
+
+        [Fact]
         public async Task AddressFamilyDoesNotMatch_Throws_ArgumentException()
         {
             using var ipv4Socket = CreateSocket();
@@ -151,6 +159,12 @@ namespace System.Net.Sockets.Tests
                 AssertExtensions.SequenceEqual(emptyBuffer, new ReadOnlySpan<byte>(receiveInternalBuffer, 0, Offset));
                 AssertExtensions.SequenceEqual(sendBuffer, new ReadOnlySpan<byte>(receiveInternalBuffer, Offset, DatagramSize));
                 Assert.Equal(sender.LocalEndPoint, result.RemoteEndPoint);
+                remoteEp = (IPEndPoint)result.RemoteEndPoint;
+                if (i > 0)
+                {
+                    // reference should be same after first round
+                    Assert.True(remoteEp == result.RemoteEndPoint);
+                }
             }
         }
 
@@ -195,7 +209,50 @@ namespace System.Net.Sockets.Tests
                 Assert.Equal(sa, serverSA);
                 Assert.Equal(server.LocalEndPoint, server.LocalEndPoint.Create(sa));
                 Assert.True(new Span<byte>(receiveBuffer, 0, readBytes).SequenceEqual(sendBuffer));
+            }
+        }
+
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public async Task ReceiveSent_SocketAddressAsync_Success(bool ipv4)
+        {
+            const int DatagramSize = 256;
+            const int DatagramsToSend = 16;
+
+            IPAddress address = ipv4 ? IPAddress.Loopback : IPAddress.IPv6Loopback;
+            using Socket server = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+            using Socket client = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+
+            client.BindToAnonymousPort(address);
+            server.BindToAnonymousPort(address);
+
+            byte[] sendBuffer = new byte[DatagramSize];
+            byte[] receiveBuffer = new byte[DatagramSize];
+
+            SocketAddress serverSA = server.LocalEndPoint.Serialize();
+            SocketAddress clientSA = client.LocalEndPoint.Serialize();
+            SocketAddress sa = new SocketAddress(address.AddressFamily);
+
+            Random rnd = new Random(0);
+
+            for (int i = 0; i < DatagramsToSend; i++)
+            {
+                rnd.NextBytes(sendBuffer);
+                await client.SendToAsync(sendBuffer, SocketFlags.None, serverSA);
+
+                int readBytes = await server.ReceiveFromAsync(receiveBuffer, SocketFlags.None, sa);
+                Assert.Equal(sa, clientSA);
+                Assert.Equal(client.LocalEndPoint, client.LocalEndPoint.Create(sa));
+                Assert.True(new Span<byte>(receiveBuffer, 0, readBytes).SequenceEqual(sendBuffer));
 
+                // and send it back to make sure it works.
+                rnd.NextBytes(sendBuffer);
+                await server.SendToAsync(sendBuffer, SocketFlags.None, sa);
+                readBytes = await client.ReceiveFromAsync(receiveBuffer, SocketFlags.None, sa);
+                Assert.Equal(sa, serverSA);
+                Assert.Equal(server.LocalEndPoint, server.LocalEndPoint.Create(sa));
+                Assert.True(new Span<byte>(receiveBuffer, 0, readBytes).SequenceEqual(sendBuffer));
             }
         }
 
index f747570..bf0ad14 100644 (file)
@@ -64,6 +64,16 @@ namespace System.Net.Sockets.Tests
         }
 
         [Fact]
+        public async Task NullSocketAddress_Throws_ArgumentException()
+        {
+            using Socket socket = CreateSocket();
+            SocketAddress socketAddress = null;
+
+            Assert.Throws<ArgumentNullException>(() => socket.SendTo(new byte[1], SocketFlags.None, socketAddress));
+            await AssertThrowsSynchronously<ArgumentNullException>(() => socket.SendToAsync(new byte[1], SocketFlags.None, socketAddress).AsTask());
+        }
+
+        [Fact]
         public async Task Datagram_UDP_ShouldImplicitlyBindLocalEndpoint()
         {
             using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
index ba0fbd7..3a8139b 100644 (file)
@@ -5,6 +5,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Runtime.InteropServices;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.DotNet.RemoteExecutor;
@@ -400,13 +401,13 @@ namespace System.Net.Sockets.Tests
                 }
                 // An abstract socket address starts with a zero byte.
                 serverAddress = '\0' + Guid.NewGuid().ToString();
-                clientAddress = '\0' + Guid.NewGuid().ToString();
+                clientAddress = '\0' + Guid.NewGuid().ToString() + "ABC";
                 expectedClientAddress = '@' + clientAddress.Substring(1);
             }
             else
             {
                 serverAddress = GetRandomNonExistingFilePath();
-                clientAddress = GetRandomNonExistingFilePath();
+                clientAddress = GetRandomNonExistingFilePath() + "ABC";
                 expectedClientAddress = clientAddress;
             }
 
@@ -536,6 +537,55 @@ namespace System.Net.Sockets.Tests
             Assert.NotEqual(endPoint2, endPoint3);
         }
 
+        [ConditionalTheory(typeof(Socket), nameof(Socket.OSSupportsUnixDomainSockets))]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/26189", TestPlatforms.Windows)]
+        [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")]
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task ReceiveFrom_EndPoints_Correct(bool useAsync)
+        {
+            string serverAddress = GetRandomNonExistingFilePath();
+            string clientAddress = GetRandomNonExistingFilePath() + "ABCD";
+
+            using (Socket server = new Socket(AddressFamily.Unix, SocketType.Dgram, ProtocolType.Unspecified))
+            {
+                server.Bind(new UnixDomainSocketEndPoint(serverAddress));
+                using (Socket client = new Socket(AddressFamily.Unix, SocketType.Dgram, ProtocolType.Unspecified))
+                {
+                    byte[] data = Encoding.ASCII.GetBytes(nameof(ReceiveFrom_EndPoints_Correct));
+                    // Bind the client.
+                    client.Bind(new UnixDomainSocketEndPoint(clientAddress));
+
+                    var sender = new UnixDomainSocketEndPoint(GetRandomNonExistingFilePath());
+                    EndPoint senderRemote = (EndPoint)sender;
+                    int transferredBytes;
+                    if (useAsync)
+                    {
+                        transferredBytes = await client.SendToAsync(data, server.LocalEndPoint);
+                    }
+                    else
+                    {
+                        transferredBytes = client.SendTo(data, server.LocalEndPoint);
+                    }
+                    Assert.Equal(data.Length, transferredBytes);
+
+                    byte[] buffer = new byte[data.Length * 2];
+                    if (useAsync)
+                    {
+                        SocketReceiveFromResult result = await server.ReceiveFromAsync(buffer, senderRemote);
+                        Assert.Equal(clientAddress, result.RemoteEndPoint.ToString());
+                        Assert.Equal(data.Length, result.ReceivedBytes);
+                    }
+                    else
+                    {
+                        transferredBytes = server.ReceiveFrom(buffer, ref senderRemote);
+                        Assert.Equal(data.Length, transferredBytes);
+                        Assert.Equal(clientAddress, senderRemote.ToString());
+                    }
+                }
+            }
+        }
+
         private static string GetRandomNonExistingFilePath()
         {
             string result;