未验证 提交 38fe4683 编写于 作者: R Radek Zikmund 提交者: GitHub

Use shared SocketAddress code in QUIC (#66794)

* Use shared SocketAddress code in QUIC

* Code review feedback

* Disable broken tests

* Rename file
上级 4ed3063d
......@@ -168,5 +168,12 @@
<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>
......@@ -50,6 +50,10 @@
<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)' == ''">
......@@ -70,12 +74,15 @@
<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" />
......@@ -97,6 +104,7 @@
<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'">
......@@ -129,6 +137,7 @@
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Collections.NonGeneric" />
......
......@@ -22,7 +22,7 @@ internal sealed class MockListener : QuicListenerProvider
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");
}
......
......@@ -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();
}
}
}
......@@ -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)
......
......@@ -422,7 +422,7 @@ internal struct NewConnectionInfo
SafeMsQuicListenerHandle listener,
QuicBuffer* alpnBuffers,
uint alpnBufferCount,
ref SOCKADDR_INET localAddress);
byte* localAddress);
internal delegate void ListenerStopDelegate(
SafeMsQuicListenerHandle listener);
......@@ -649,48 +649,6 @@ internal struct StreamEvent
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 @@ internal uint ListenerOpen(SafeMsQuicRegistrationHandle registration, ListenerCa
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 @@ internal uint ListenerStart(SafeMsQuicListenerHandle listener, QuicBuffer* alpnB
//
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
{
......
......@@ -252,10 +252,10 @@ private static uint HandleEventConnected(State state, ref ConnectionEvent connec
{
// 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 @@ internal override ValueTask ConnectAsync(CancellationToken cancellationToken = d
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 @@ internal override ValueTask ConnectAsync(CancellationToken cancellationToken = d
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
......
......@@ -13,6 +13,7 @@
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 @@ private unsafe IPEndPoint Start(QuicListenerOptions options)
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 @@ private unsafe IPEndPoint Start(QuicListenerOptions options)
{
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 @@ private unsafe IPEndPoint Start(QuicListenerOptions options)
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 @@ private void Stop()
{
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)
{
......
......@@ -8,12 +8,14 @@
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 @@ public async Task UntrustedClientCertificateFails()
}
[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 @@ public async Task CertificateCallbackThrowPropagates()
}
[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 @@ public async Task ConnectWithCertificateForDifferentName_Throws()
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();
......
......@@ -26,6 +26,22 @@ public async Task Listener_Backlog_Success()
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))]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册