Skip to content

Commit

Permalink
[QUIC] API QuicListener (dotnet#71579)
Browse files Browse the repository at this point in the history
* QuicListener new API shape including compilable implementation

* Quic and Http tests compile

* Tests work

* Feedback

* Fix Windows error

* Feedback

* Listener comment; PreviewFeature attribute

* Updated helix image with msquic

* Cleaned up PreviewFeature attribute.

* Feedback

* Split event handlers into methods.

* Added comments for pending connection.

* Switch expression for HandleEvent
  • Loading branch information
ManickaP authored Jul 10, 2022
1 parent 8aa77a9 commit 60af631
Show file tree
Hide file tree
Showing 46 changed files with 1,238 additions and 897 deletions.
2 changes: 1 addition & 1 deletion eng/pipelines/coreclr/templates/helix-queues-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
- (Debian.11.Amd64)[email protected]/dotnet-buildtools/prereqs:debian-11-helix-amd64-20210304164428-5a7c380
- Ubuntu.1804.Amd64
- (Centos.8.Amd64)[email protected]/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759
- (Fedora.34.Amd64)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220523142223-4f64125
- (Fedora.34.Amd64)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220708122731-4f64125
- RedHat.7.Amd64

# OSX arm64
Expand Down
4 changes: 2 additions & 2 deletions eng/pipelines/libraries/helix-queues-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ jobs:
- (Centos.8.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759
- RedHat.7.Amd64.Open
- SLES.15.Amd64.Open
- (Fedora.34.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220523142223-4f64125
- (Fedora.34.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220708122731-4f64125
- (Ubuntu.2204.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64-20220504035722-1b9461f
- (Debian.10.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:debian-10-helix-amd64-bfcd90a-20200121150006
- ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}:
- ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}:
- (Centos.8.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759
- SLES.15.Amd64.Open
- (Fedora.34.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220523142223-4f64125
- (Fedora.34.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-34-helix-20220708122731-4f64125
- (Ubuntu.2204.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64-20220504035722-1b9461f
- (Debian.11.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:debian-11-helix-amd64-20210304164428-5a7c380
- (Mariner.1.0.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:cbl-mariner-1.0-helix-20210528192219-92bf620
Expand Down
37 changes: 24 additions & 13 deletions src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed class Http3LoopbackServer : GenericLoopbackServer
private X509Certificate2 _cert;
private QuicListener _listener;

public override Uri Address => new Uri($"https://{_listener.ListenEndPoint}/");
public override Uri Address => new Uri($"https://{_listener.LocalEndPoint}/");

public Http3LoopbackServer(Http3Options options = null)
{
Expand All @@ -28,18 +28,29 @@ public Http3LoopbackServer(Http3Options options = null)
var listenerOptions = new QuicListenerOptions()
{
ListenEndPoint = new IPEndPoint(options.Address, 0),
ServerAuthenticationOptions = new SslServerAuthenticationOptions
ApplicationProtocols = new List<SslApplicationProtocol>
{
EnabledSslProtocols = options.SslProtocols,
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol(options.Alpn)
},
ServerCertificate = _cert,
ClientCertificateRequired = false
new SslApplicationProtocol(options.Alpn)
},
MaxUnidirectionalStreams = options.MaxUnidirectionalStreams,
MaxBidirectionalStreams = options.MaxBidirectionalStreams,
ConnectionOptionsCallback = (_, _, _) =>
{
var serverOptions = new QuicServerConnectionOptions()
{
MaxBidirectionalStreams = options.MaxBidirectionalStreams,
MaxUnidirectionalStreams = options.MaxUnidirectionalStreams,
ServerAuthenticationOptions = new SslServerAuthenticationOptions
{
EnabledSslProtocols = options.SslProtocols,
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol(options.Alpn)
},
ServerCertificate = _cert,
ClientCertificateRequired = false
}
};
return ValueTask.FromResult(serverOptions);
}
};

ValueTask<QuicListener> valueTask = QuicListener.ListenAsync(listenerOptions);
Expand All @@ -49,7 +60,7 @@ public Http3LoopbackServer(Http3Options options = null)

public override void Dispose()
{
_listener.Dispose();
_listener.DisposeAsync().GetAwaiter().GetResult();
_cert.Dispose();
}

Expand Down Expand Up @@ -133,7 +144,7 @@ public class Http3Options : GenericLoopbackOptions

public Http3Options()
{
MaxUnidirectionalStreams = 100;
MaxUnidirectionalStreams = 10;
MaxBidirectionalStreams = 100;
Alpn = SslApplicationProtocol.Http3.ToString();
}
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Net.Http/src/System.Net.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants);HTTP_DLL</DefineConstants>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-MacCatalyst;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-Solaris;$(NetCoreAppCurrent)-Android;$(NetCoreAppCurrent)</TargetFrameworks>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>
<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,14 @@ public static async ValueTask<SslStream> EstablishSslConnectionAsync(SslClientAu
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static async ValueTask<QuicConnection> ConnectQuicAsync(HttpRequestMessage request, DnsEndPoint endPoint, SslClientAuthenticationOptions clientAuthenticationOptions, CancellationToken cancellationToken)
public static async ValueTask<QuicConnection> ConnectQuicAsync(HttpRequestMessage request, DnsEndPoint endPoint, TimeSpan idleTimeout, SslClientAuthenticationOptions clientAuthenticationOptions, CancellationToken cancellationToken)
{
clientAuthenticationOptions = SetUpRemoteCertificateValidationCallback(clientAuthenticationOptions, request);
QuicConnection connection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions()
{
MaxBidirectionalStreams = 0, // Client doesn't support inbound streams: https://www.rfc-editor.org/rfc/rfc9114.html#name-bidirectional-streams. An extension might change this.
MaxUnidirectionalStreams = 5, // Minimum is 3: https://www.rfc-editor.org/rfc/rfc9114.html#unidirectional-streams (1x control stream + 2x QPACK). Set to 100 if/when support for PUSH streams is added.
IdleTimeout = idleTimeout,
RemoteEndPoint = endPoint,
ClientAuthenticationOptions = clientAuthenticationOptions
}, cancellationToken).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,8 @@ private async Task ProcessServerStreamAsync(QuicStream stream)
NetEventSource.Info(this, $"Ignoring server-initiated stream of unknown type {unknownStreamType}.");
}

stream.AbortWrite((long)Http3ErrorCode.StreamCreationError);
stream.AbortRead((long)Http3ErrorCode.StreamCreationError);
stream.Dispose();
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ private async ValueTask<Http3Connection> GetHttp3ConnectionAsync(HttpRequestMess
QuicConnection quicConnection;
try
{
quicConnection = await ConnectHelper.ConnectQuicAsync(request, new DnsEndPoint(authority.IdnHost, authority.Port), _sslOptionsHttp3!, cancellationToken).ConfigureAwait(false);
quicConnection = await ConnectHelper.ConnectQuicAsync(request, new DnsEndPoint(authority.IdnHost, authority.Port), _poolManager.Settings._pooledConnectionIdleTimeout, _sslOptionsHttp3!, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX</TargetFrameworks>
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>

<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
Expand Down
41 changes: 24 additions & 17 deletions src/libraries/System.Net.Quic/ref/System.Net.Quic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

namespace System.Net.Quic
{
public partial class QuicClientConnectionOptions : System.Net.Quic.QuicOptions
public sealed partial class QuicClientConnectionOptions : System.Net.Quic.QuicConnectionOptions
{
public QuicClientConnectionOptions() { }
public System.Net.Security.SslClientAuthenticationOptions? ClientAuthenticationOptions { get { throw null; } set { } }
public required System.Net.Security.SslClientAuthenticationOptions ClientAuthenticationOptions { get { throw null; } set { } }
public System.Net.IPEndPoint? LocalEndPoint { get { throw null; } set { } }
public System.Net.EndPoint? RemoteEndPoint { get { throw null; } set { } }
public required System.Net.EndPoint RemoteEndPoint { get { throw null; } set { } }
}
public sealed partial class QuicConnection : System.IDisposable
{
Expand All @@ -34,41 +34,48 @@ public void Dispose() { }
}
public partial class QuicConnectionAbortedException : System.Net.Quic.QuicException
{
public QuicConnectionAbortedException(string message, long errorCode) : base(default(string)) { }
public QuicConnectionAbortedException(string message, long errorCode) : base (default(string)) { }
public long ErrorCode { get { throw null; } }
}
public abstract partial class QuicConnectionOptions
{
internal QuicConnectionOptions() { }
public System.TimeSpan IdleTimeout { get { throw null; } set { } }
public int MaxBidirectionalStreams { get { throw null; } set { } }
public int MaxUnidirectionalStreams { get { throw null; } set { } }
}
public partial class QuicException : System.Exception
{
public QuicException(string? message) { }
public QuicException(string? message, System.Exception? innerException) { }
public QuicException(string? message, System.Exception? innerException, int result) { }
}
public sealed partial class QuicListener : System.IDisposable
public sealed partial class QuicListener : System.IAsyncDisposable
{
internal QuicListener() { }
public static bool IsSupported { get { throw null; } }
public System.Net.IPEndPoint ListenEndPoint { get { throw null; } }
public System.Net.IPEndPoint LocalEndPoint { get { throw null; } }
public System.Threading.Tasks.ValueTask<System.Net.Quic.QuicConnection> AcceptConnectionAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public void Dispose() { }
public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
public static System.Threading.Tasks.ValueTask<System.Net.Quic.QuicListener> ListenAsync(System.Net.Quic.QuicListenerOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override string ToString() { throw null; }
}
public partial class QuicListenerOptions : System.Net.Quic.QuicOptions
public sealed partial class QuicListenerOptions
{
public QuicListenerOptions() { }
public required System.Collections.Generic.List<System.Net.Security.SslApplicationProtocol> ApplicationProtocols { get { throw null; } set { } }
public required System.Func<System.Net.Quic.QuicConnection, System.Net.Security.SslClientHelloInfo, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask<System.Net.Quic.QuicServerConnectionOptions>> ConnectionOptionsCallback { get { throw null; } set { } }
public int ListenBacklog { get { throw null; } set { } }
public System.Net.IPEndPoint? ListenEndPoint { get { throw null; } set { } }
public System.Net.Security.SslServerAuthenticationOptions? ServerAuthenticationOptions { get { throw null; } set { } }
public required System.Net.IPEndPoint ListenEndPoint { get { throw null; } set { } }
}
public partial class QuicOperationAbortedException : System.Net.Quic.QuicException
{
public QuicOperationAbortedException(string message) : base(default(string)) { }
public QuicOperationAbortedException(string message) : base (default(string)) { }
}
public partial class QuicOptions
public sealed partial class QuicServerConnectionOptions : System.Net.Quic.QuicConnectionOptions
{
public QuicOptions() { }
public System.TimeSpan IdleTimeout { get { throw null; } set { } }
public int MaxBidirectionalStreams { get { throw null; } set { } }
public int MaxUnidirectionalStreams { get { throw null; } set { } }
public QuicServerConnectionOptions() { }
public required System.Net.Security.SslServerAuthenticationOptions ServerAuthenticationOptions { get { throw null; } set { } }
}
public sealed partial class QuicStream : System.IO.Stream
{
Expand Down Expand Up @@ -113,7 +120,7 @@ public override void WriteByte(byte value) { }
}
public partial class QuicStreamAbortedException : System.Net.Quic.QuicException
{
public QuicStreamAbortedException(string message, long errorCode) : base(default(string)) { }
public QuicStreamAbortedException(string message, long errorCode) : base (default(string)) { }
public long ErrorCode { get { throw null; } }
}
}
4 changes: 4 additions & 0 deletions src/libraries/System.Net.Quic/ref/System.Net.Quic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
</PropertyGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.Versioning.RequiresPreviewFeaturesAttribute" />
</ItemGroup>

<ItemGroup>
<Compile Include="System.Net.Quic.cs" />
</ItemGroup>
Expand Down
6 changes: 5 additions & 1 deletion src/libraries/System.Net.Quic/src/ExcludeApiList.PNSE.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
P:System.Net.Quic.QuicConnection.IsSupported
P:System.Net.Quic.QuicListener.IsSupported
P:System.Net.Quic.QuicListener.IsSupported
C:System.Net.Quic.QuicListenerOptions
C:System.Net.Quic.QuicConnectionOptions
C:System.Net.Quic.QuicClientConnectionOptions
C:System.Net.Quic.QuicServerConnectionOptions
3 changes: 3 additions & 0 deletions src/libraries/System.Net.Quic/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,8 @@
<data name="net_InvalidSocketAddressSize" xml:space="preserve">
<value>The supplied {0} is an invalid size for the {1} end point.</value>
</data>
<data name="net_quic_accept_not_allowed" xml:space="preserve">
<value>QuicConnection is configured to not accept any streams.</value>
</data>
</root>

25 changes: 8 additions & 17 deletions src/libraries/System.Net.Quic/src/System.Net.Quic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,12 @@
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetPlatformIdentifier)' == ''">SR.SystemNetQuic_PlatformNotSupported</GeneratePlatformNotSupportedAssemblyMessage>
<ApiExclusionListPath Condition="'$(TargetPlatformIdentifier)' == ''">ExcludeApiList.PNSE.txt</ApiExclusionListPath>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.Versioning.RequiresPreviewFeaturesAttribute" />
</ItemGroup>
<!-- Source files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' != ''">
<Compile Include="System\Net\Quic\NetEventSource.Quic.cs" />
<Compile Include="System\Net\Quic\QuicClientConnectionOptions.cs" />
<Compile Include="System\Net\Quic\QuicConnection.cs" />
<Compile Include="System\Net\Quic\QuicConnectionAbortedException.cs" />
<Compile Include="System\Net\Quic\QuicException.cs" />
<Compile Include="System\Net\Quic\QuicListener.cs" />
<Compile Include="System\Net\Quic\QuicListenerOptions.cs" />
<Compile Include="System\Net\Quic\QuicOperationAbortedException.cs" />
<Compile Include="System\Net\Quic\QuicOptions.cs" />
<Compile Include="System\Net\Quic\QuicStream.cs" />
<Compile Include="System\Net\Quic\QuicStreamAbortedException.cs" />
<Compile Include="System\Net\Quic\Implementations\*.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\*.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Internal\*.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\*.cs" />
<Compile Include="System\Net\Quic\**\*.cs" Exclude="System\Net\Quic\*.Unsupported.cs"/>
<!-- System.Net common -->
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs" Link="Common\DisableRuntimeMarshalling.cs" />
<Compile Include="$(CommonPath)System\Threading\Tasks\TaskToApm.cs" Link="Common\System\Threading\Tasks\TaskToApm.cs" />
Expand All @@ -41,8 +30,10 @@
</ItemGroup>
<!-- Unsupported platforms -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == ''">
<Compile Include="System\Net\Quic\QuicListener.Unsupported.cs" />
<Compile Include="System\Net\Quic\QuicConnection.Unsupported.cs" />
<Compile Include="System\Net\Quic\*.Unsupported.cs" />
<!-- [ActiveIssue("https://github.com/dotnet/runtime/issues/71559")]: PNSE generator cannot handle required keyword, so excluding affected classes in ExcludeApiList.PNSE.txt and including real code for now. -->
<Compile Include="System\Net\Quic\QuicListenerOptions.cs" />
<Compile Include="System\Net\Quic\QuicConnectionOptions.cs" />
</ItemGroup>
<!-- Windows specific files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@

using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Quic;

namespace System.Net.Quic.Implementations.MsQuic.Internal
{
internal static class MsQuicAddressHelpers
{
internal static unsafe IPEndPoint INetToIPEndPoint(IntPtr pInetAddress)
internal static unsafe IPEndPoint ToIPEndPoint(this ref QuicAddr quicAddress)
{
// MsQuic always uses storage size as if IPv6 was used
Span<byte> addressBytes = new Span<byte>((byte*)pInetAddress, Internals.SocketAddress.IPv6AddressSize);
// QuicAddr is native memory, it cannot be moved by GC, thus no need for fixed expression here.
Span<byte> addressBytes = new Span<byte>((byte*)Unsafe.AsPointer(ref quicAddress), Internals.SocketAddress.IPv6AddressSize);
return new Internals.SocketAddress(SocketAddressPal.GetAddressFamily(addressBytes), addressBytes).GetIPEndPoint();
}

Expand Down
Loading

0 comments on commit 60af631

Please sign in to comment.