Use shared SocketAddress code in QUIC (#66794)
authorRadek Zikmund <32671551+rzikm@users.noreply.github.com>
Wed, 30 Mar 2022 10:40:32 +0000 (12:40 +0200)
committerGitHub <noreply@github.com>
Wed, 30 Mar 2022 10:40:32 +0000 (12:40 +0200)
* Use shared SocketAddress code in QUIC

* Code review feedback

* Disable broken tests

* Rename file

src/libraries/System.Net.Quic/src/Resources/Strings.resx
src/libraries/System.Net.Quic/src/System.Net.Quic.csproj
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockListener.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicAddressHelpers.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicParameterHelpers.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/MsQuicNativeMethods.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs
src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicListener.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs

index af6bfa4..4eb23ec 100644 (file)
   <data name="net_quic_tls_version_notsupported" xml:space="preserve">
     <value>Could not use a TLS version required by Quic. TLS 1.3 may have been disabled in the registry.</value>
   </data>
+  <!-- Referenced in shared IPEndPointExtensions.cs-->
+  <data name="net_InvalidAddressFamily" xml:space="preserve">
+    <value>The AddressFamily {0} is not valid for the {1} end point, use {2} instead.</value>
+  </data>
+  <data name="net_InvalidSocketAddressSize" xml:space="preserve">
+    <value>The supplied {0} is an invalid size for the {1} end point.</value>
+  </data>
 </root>
 
index 171290f..c1f0c1a 100644 (file)
     <Compile Include="$(CommonPath)System\Net\MultiArrayBuffer.cs" Link="Common\System\Net\MultiArrayBuffer.cs" />
     <Compile Include="$(CommonPath)System\Net\Logging\NetEventSource.Common.cs" Link="Common\System\Net\Logging\NetEventSource.Common.cs" />
     <Compile Include="$(CommonPath)System\Net\StreamBuffer.cs" Link="Common\System\Net\StreamBuffer.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddress.cs" Link="Common\System\Net\SocketAddress.cs" />
+    <Compile Include="$(CommonPath)System\Net\IPAddressParserStatics.cs" Link="Common\System\Net\IPAddressParserStatics.cs" />
+    <!-- System.Net.Internals -->
+    <Compile Include="$(CommonPath)System\Net\Internals\IPEndPointExtensions.cs" Link="Common\System\Net\Internals\IPEndPointExtensions.cs" />
   </ItemGroup>
   <!-- Unsupported platforms -->
   <ItemGroup Condition="'$(TargetPlatformIdentifier)' == ''">
     <Compile Include="$(CommonPath)Interop\Windows\Crypt32\Interop.MsgEncodingType.cs" Link="Common\Interop\Windows\Crypt32\Interop.Interop.MsgEncodingType.cs" />
     <Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs" Link="Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs" />
     <Compile Include="$(CommonPath)System\Net\Security\CertificateValidation.Windows.cs" Link="Common\System\Net\Security\CertificateValidation.Windows.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressPal.Windows.cs" Link="Common\System\Net\SocketAddressPal.Windows.cs" />
     <Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusCodes.Windows.cs" />
   </ItemGroup>
   <!-- Unix (OSX + Linux) specific files -->
   <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'Linux' or '$(TargetPlatformIdentifier)' == 'OSX' or '$(TargetPlatformIdentifier)' == 'FreeBSD'">
     <Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\Interop.Errors.cs" Link="Common\Interop\Unix\Interop.Errors.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketAddress.cs" Link="Common\Interop\Unix\System.Native\Interop.SocketAddress.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs" />
     <Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs" Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs" />
     <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs" Link="Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs" />
     <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs" Link="Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs" />
     <Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeHandleCache.cs" Link="Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs" />
+    <Compile Include="$(CommonPath)System\Net\SocketAddressPal.Unix.cs" Link="Common\System\Net\SocketAddressPal.Unix.cs" />
   </ItemGroup>
   <!-- Linux specific files -->
   <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'Linux'">
   </ItemGroup>
 
   <ItemGroup>
+    <Reference Include="Microsoft.Win32.Primitives" />
     <Reference Include="System.Collections" />
     <Reference Include="System.Collections.Concurrent" />
     <Reference Include="System.Collections.NonGeneric" />
index 48ebf8a..1be3400 100644 (file)
@@ -22,7 +22,7 @@ namespace System.Net.Quic.Implementations.Mock
 
         internal MockListener(QuicListenerOptions options)
         {
-            if (options.ListenEndPoint is null || options.ListenEndPoint.Address != IPAddress.Loopback || options.ListenEndPoint.Port != 0)
+            if (options.ListenEndPoint is null || (options.ListenEndPoint.Address != IPAddress.Loopback && options.ListenEndPoint.Address != IPAddress.IPv6Loopback) || options.ListenEndPoint.Port != 0)
             {
                 throw new ArgumentException("Must pass loopback address and port 0");
             }
index d280fb8..9163794 100644 (file)
@@ -9,46 +9,11 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
 {
     internal static class MsQuicAddressHelpers
     {
-        internal static unsafe IPEndPoint INetToIPEndPoint(ref SOCKADDR_INET inetAddress)
+        internal static unsafe IPEndPoint INetToIPEndPoint(IntPtr pInetAddress)
         {
-            if (inetAddress.si_family == QUIC_ADDRESS_FAMILY.INET)
-            {
-                return new IPEndPoint(new IPAddress(MemoryMarshal.CreateReadOnlySpan<byte>(ref inetAddress.Ipv4.sin_addr[0], 4)), (ushort)IPAddress.NetworkToHostOrder((short)inetAddress.Ipv4.sin_port));
-            }
-            else
-            {
-                return new IPEndPoint(new IPAddress(MemoryMarshal.CreateReadOnlySpan<byte>(ref inetAddress.Ipv6.sin6_addr[0], 16)), (ushort)IPAddress.NetworkToHostOrder((short)inetAddress.Ipv6.sin6_port));
-            }
-        }
-
-        internal static unsafe SOCKADDR_INET IPEndPointToINet(IPEndPoint endpoint)
-        {
-            SOCKADDR_INET socketAddress = default;
-            if (!endpoint.Address.Equals(IPAddress.Any) && !endpoint.Address.Equals(IPAddress.IPv6Any))
-            {
-                switch (endpoint.Address.AddressFamily)
-                {
-                    case AddressFamily.InterNetwork:
-                        endpoint.Address.TryWriteBytes(MemoryMarshal.CreateSpan<byte>(ref socketAddress.Ipv4.sin_addr[0], 4), out _);
-                        socketAddress.Ipv4.sin_family = QUIC_ADDRESS_FAMILY.INET;
-                        break;
-                    case AddressFamily.InterNetworkV6:
-                        endpoint.Address.TryWriteBytes(MemoryMarshal.CreateSpan<byte>(ref socketAddress.Ipv6.sin6_addr[0], 16), out _);
-                        socketAddress.Ipv6.sin6_family = QUIC_ADDRESS_FAMILY.INET6;
-                        break;
-                    default:
-                        throw new ArgumentException(SR.net_quic_addressfamily_notsupported);
-                }
-            }
-
-            SetPort(endpoint.Address.AddressFamily, ref socketAddress, endpoint.Port);
-            return socketAddress;
-        }
-
-        private static void SetPort(AddressFamily addressFamily, ref SOCKADDR_INET socketAddrInet, int originalPort)
-        {
-            ushort convertedPort = (ushort)IPAddress.HostToNetworkOrder((short)originalPort);
-            socketAddrInet.Ipv4.sin_port = convertedPort;
+            // MsQuic always uses storage size as if IPv6 was used
+            Span<byte> addressBytes = new Span<byte>((byte*)pInetAddress, Internals.SocketAddress.IPv6AddressSize);
+            return new Internals.SocketAddress(SocketAddressPal.GetAddressFamily(addressBytes), addressBytes).GetIPEndPoint();
         }
     }
 }
index 63672d2..33ba189 100644 (file)
@@ -3,22 +3,46 @@
 
 using System.Diagnostics;
 using System.Runtime.InteropServices;
+using System.Net.Sockets;
 using static System.Net.Quic.Implementations.MsQuic.Internal.MsQuicNativeMethods;
 
 namespace System.Net.Quic.Implementations.MsQuic.Internal
 {
     internal static class MsQuicParameterHelpers
     {
-        internal static unsafe SOCKADDR_INET GetINetParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param)
+        internal static unsafe IPEndPoint GetIPEndPointParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param)
         {
-            SOCKADDR_INET value;
-            uint valueLen = (uint)sizeof(SOCKADDR_INET);
+            // MsQuic always uses storage size as if IPv6 was used
+            uint valueLen = (uint)Internals.SocketAddress.IPv6AddressSize;
+            Span<byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize];
 
-            uint status = api.GetParamDelegate(nativeObject, level, param, ref valueLen, (byte*)&value);
-            QuicExceptionHelpers.ThrowIfFailed(status, "GetINETParam failed.");
-            Debug.Assert(valueLen == sizeof(SOCKADDR_INET));
+            fixed (byte* paddress = &MemoryMarshal.GetReference(address))
+            {
+                uint status = api.GetParamDelegate(nativeObject, level, param, ref valueLen, paddress);
+                QuicExceptionHelpers.ThrowIfFailed(status, "GetIPEndPointParam failed.");
+            }
 
-            return value;
+            address = address.Slice(0, (int)valueLen);
+
+            return new Internals.SocketAddress(SocketAddressPal.GetAddressFamily(address), address)
+                .GetIPEndPoint();
+        }
+
+        internal static unsafe void SetIPEndPointParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param, IPEndPoint value)
+        {
+            Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(value);
+
+            // MsQuic always reads same amount of memory as if IPv6 was used, so we can't pass pointer to socketAddress.Buffer directly
+            Span<byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize];
+            socketAddress.Buffer.AsSpan(0, socketAddress.Size).CopyTo(address);
+            address.Slice(socketAddress.Size).Clear();
+
+            fixed (byte* paddress = &MemoryMarshal.GetReference(address))
+            {
+                QuicExceptionHelpers.ThrowIfFailed(
+                    api.SetParamDelegate(nativeObject, level, param, (uint)address.Length, paddress),
+                    "Could not set IPEndPoint");
+            }
         }
 
         internal static unsafe ushort GetUShortParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param)
index d863398..681bc94 100644 (file)
@@ -422,7 +422,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
             SafeMsQuicListenerHandle listener,
             QuicBuffer* alpnBuffers,
             uint alpnBufferCount,
-            ref SOCKADDR_INET localAddress);
+            byte* localAddress);
 
         internal delegate void ListenerStopDelegate(
             SafeMsQuicListenerHandle listener);
@@ -649,48 +649,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
             internal StreamEventDataUnion Data;
         }
 
-        // TODO: rename to C#-like
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct SOCKADDR_IN
-        {
-#if SOCKADDR_HAS_LENGTH
-            internal byte sin_len;
-#endif
-            internal QUIC_ADDRESS_FAMILY sin_family;
-            internal ushort sin_port;
-            internal fixed byte sin_addr[4];
-        }
-
-        // TODO: rename to C#-like
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct SOCKADDR_IN6
-        {
-#if SOCKADDR_HAS_LENGTH
-            internal byte sin6_len;
-#endif
-            internal QUIC_ADDRESS_FAMILY sin6_family;
-            internal ushort sin6_port;
-            internal uint sin6_flowinfo;
-            internal fixed byte sin6_addr[16];
-            internal uint sin6_scope_id;
-        }
-
-        // TODO: rename to C#-like
-        [StructLayout(LayoutKind.Explicit)]
-        internal struct SOCKADDR_INET
-        {
-            [FieldOffset(0)]
-            internal SOCKADDR_IN Ipv4;
-            [FieldOffset(0)]
-            internal SOCKADDR_IN6 Ipv6;
-#if SOCKADDR_HAS_LENGTH
-            [FieldOffset(1)]
-#else
-            [FieldOffset(0)]
-#endif
-            internal QUIC_ADDRESS_FAMILY si_family;
-        }
-
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         internal delegate uint StreamCallbackDelegate(
             IntPtr stream,
@@ -1061,9 +1019,9 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
 
                 return __retVal;
             }
-            internal uint ListenerStart(SafeMsQuicListenerHandle listener, QuicBuffer* alpnBuffers, uint alpnBufferCount, ref SOCKADDR_INET localAddress)
+            internal uint ListenerStart(SafeMsQuicListenerHandle listener, QuicBuffer* alpnBuffers, uint alpnBufferCount, byte* localAddress)
             {
-                IntPtr __listener_gen_native = default;
+                IntPtr __listener_gen_native;
                 uint __retVal;
                 //
                 // Setup
@@ -1076,10 +1034,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
                     //
                     listener.DangerousAddRef(ref listener__addRefd);
                     __listener_gen_native = listener.DangerousGetHandle();
-                    fixed (SOCKADDR_INET* __localAddress_gen_native = &localAddress)
-                    {
-                        __retVal = ((delegate* unmanaged[Cdecl]<IntPtr, QuicBuffer*, uint, SOCKADDR_INET*, uint>)_functionPointer)(__listener_gen_native, alpnBuffers, alpnBufferCount, __localAddress_gen_native);
-                    }
+                    __retVal = ((delegate* unmanaged[Cdecl]<IntPtr, QuicBuffer*, uint, byte*, uint>)_functionPointer)(__listener_gen_native, alpnBuffers, alpnBufferCount, localAddress);
                 }
                 finally
                 {
index 7b9903a..5d3a7e8 100644 (file)
@@ -252,10 +252,10 @@ namespace System.Net.Quic.Implementations.MsQuic
             {
                 // Connected will already be true for connections accepted from a listener.
                 Debug.Assert(!Monitor.IsEntered(state));
-                SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS);
+
 
                 Debug.Assert(state.Connection != null);
-                state.Connection._localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress);
+                state.Connection._localEndPoint = MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS);
                 state.Connection.SetNegotiatedAlpn(connectionEvent.Data.Connected.NegotiatedAlpn, connectionEvent.Data.Connected.NegotiatedAlpnLength);
                 state.Connection = null;
 
@@ -640,24 +640,18 @@ namespace System.Net.Quic.Implementations.MsQuic
             string targetHost;
             int port;
 
-            if (_remoteEndPoint is IPEndPoint)
+            if (_remoteEndPoint is IPEndPoint ipEndPoint)
             {
-                SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet((IPEndPoint)_remoteEndPoint);
-                unsafe
-                {
-                    Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
-                    status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte*)&address);
-                    QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer.");
-                }
-
+                Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
+                MsQuicParameterHelpers.SetIPEndPointParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, ipEndPoint);
                 targetHost = _state.TargetHost ?? ((IPEndPoint)_remoteEndPoint).Address.ToString();
                 port = ((IPEndPoint)_remoteEndPoint).Port;
 
             }
-            else if (_remoteEndPoint is DnsEndPoint)
+            else if (_remoteEndPoint is DnsEndPoint dnsEndPoint)
             {
-                port = ((DnsEndPoint)_remoteEndPoint).Port;
-                string dnsHost = ((DnsEndPoint)_remoteEndPoint).Host!;
+                port = dnsEndPoint.Port;
+                string dnsHost = dnsEndPoint.Host!;
 
                 // We don't have way how to set separate SNI and name for connection at this moment.
                 // If the name is actually IP address we can use it to make at least some cases work for people
@@ -665,13 +659,8 @@ namespace System.Net.Quic.Implementations.MsQuic
                 if (!string.IsNullOrEmpty(_state.TargetHost) && !dnsHost.Equals(_state.TargetHost, StringComparison.InvariantCultureIgnoreCase) && IPAddress.TryParse(dnsHost, out IPAddress? address))
                 {
                     // This is form of IPAddress and _state.TargetHost is set to different string
-                    SOCKADDR_INET quicAddress = MsQuicAddressHelpers.IPEndPointToINet(new IPEndPoint(address, port));
-                    unsafe
-                    {
-                        Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
-                        status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte*)&quicAddress);
-                        QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer.");
-                    }
+                    Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
+                    MsQuicParameterHelpers.SetIPEndPointParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, new IPEndPoint(address, port));
                     targetHost = _state.TargetHost!;
                 }
                 else
index 0e65bf6..ab4969a 100644 (file)
@@ -13,6 +13,7 @@ using System.Threading;
 using System.Threading.Channels;
 using System.Threading.Tasks;
 using static System.Net.Quic.Implementations.MsQuic.Internal.MsQuicNativeMethods;
+using System.Net.Sockets;
 
 namespace System.Net.Quic.Implementations.MsQuic
 {
@@ -176,7 +177,7 @@ namespace System.Net.Quic.Implementations.MsQuic
             List<SslApplicationProtocol> applicationProtocols = options.ServerAuthenticationOptions!.ApplicationProtocols!;
             IPEndPoint listenEndPoint = options.ListenEndPoint!;
 
-            SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet(listenEndPoint);
+            Internals.SocketAddress address = IPEndPointExtensions.Serialize(listenEndPoint);
 
             uint status;
 
@@ -188,7 +189,10 @@ namespace System.Net.Quic.Implementations.MsQuic
             {
                 Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
                 MsQuicAlpnHelper.Prepare(applicationProtocols, out handles, out buffers);
-                status = MsQuicApi.Api.ListenerStartDelegate(_state.Handle, (QuicBuffer*)Marshal.UnsafeAddrOfPinnedArrayElement(buffers, 0), (uint)applicationProtocols.Count, ref address);
+                fixed (byte* paddress = address.Buffer)
+                {
+                    status = MsQuicApi.Api.ListenerStartDelegate(_state.Handle, (QuicBuffer*)Marshal.UnsafeAddrOfPinnedArrayElement(buffers, 0), (uint)applicationProtocols.Count, paddress);
+                }
             }
             catch
             {
@@ -203,8 +207,7 @@ namespace System.Net.Quic.Implementations.MsQuic
             QuicExceptionHelpers.ThrowIfFailed(status, "ListenerStart failed.");
 
             Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
-            SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS);
-            return MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress);
+            return MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS);
         }
 
         private void Stop()
@@ -244,8 +247,9 @@ namespace System.Net.Quic.Implementations.MsQuic
             {
                 ref NewConnectionInfo connectionInfo = ref *evt->Data.NewConnection.Info;
 
-                IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.LocalAddress);
-                IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.RemoteAddress);
+                IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(connectionInfo.LocalAddress);
+                IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(connectionInfo.RemoteAddress);
+
                 string targetHost = string.Empty;   // compat with SslStream
                 if (connectionInfo.ServerNameLength > 0 && connectionInfo.ServerName != IntPtr.Zero)
                 {
index be36ad9..7db083a 100644 (file)
@@ -8,12 +8,14 @@ using System.Diagnostics.Tracing;
 using System.Linq;
 using System.Net.Security;
 using System.Net.Sockets;
+using System.Runtime.InteropServices;
 using System.Security.Authentication;
 using System.Security.Cryptography;
 using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.DotNet.XUnitExtensions;
 using Xunit;
 using Xunit.Abstractions;
 
@@ -141,6 +143,7 @@ namespace System.Net.Quic.Tests
         }
 
         [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/67301", TestPlatforms.Linux)]
         public async Task CertificateCallbackThrowPropagates()
         {
             using CancellationTokenSource cts = new CancellationTokenSource(PassingTestTimeout);
@@ -182,6 +185,7 @@ namespace System.Net.Quic.Tests
         }
 
         [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/67301", TestPlatforms.Linux)]
         public async Task ConnectWithCertificateCallback()
         {
             X509Certificate2 c1 = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
@@ -311,6 +315,13 @@ namespace System.Net.Quic.Tests
         public async Task ConnectWithCertificateForLoopbackIP_IndicatesExpectedError(string ipString, bool expectsError)
         {
             var ipAddress = IPAddress.Parse(ipString);
+
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
+            {
+                // [ActiveIssue("https://github.com/dotnet/runtime/issues/67301")]
+                throw new SkipTestException("IPv6 on Linux is temporarily broken");
+            }
+
             (X509Certificate2 certificate, _) = System.Net.Security.Tests.TestHelper.GenerateCertificates(expectsError ? "badhost" : "localhost");
 
             var listenerOptions = new QuicListenerOptions();
index 7e3097f..bacc79b 100644 (file)
@@ -26,6 +26,22 @@ namespace System.Net.Quic.Tests
                 await clientStreamTask;
             }).WaitAsync(TimeSpan.FromSeconds(6));
         }
+
+        [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/67301", TestPlatforms.Linux)]
+        public async Task Listener_Backlog_Success_IPv6()
+        {
+            await Task.Run(async () =>
+            {
+                using QuicListener listener = CreateQuicListener(new IPEndPoint(IPAddress.IPv6Loopback, 0));
+
+                using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
+                var clientStreamTask = clientConnection.ConnectAsync();
+
+                using QuicConnection serverConnection = await listener.AcceptConnectionAsync();
+                await clientStreamTask;
+            }).WaitAsync(TimeSpan.FromSeconds(6));
+        }
     }
 
     [ConditionalClass(typeof(QuicTestBase<MockProviderFactory>), nameof(QuicTestBase<MockProviderFactory>.IsSupported))]