-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: [QUIC] QuicConnection #68902
Comments
Tagging subscribers to this area: @dotnet/ncl Issue DetailsBackground and motivationAPI design for exposing QuicConnection and related classes to the public. The API shape is based on the current internal shape of the class with the exception of postponing the connection configuration until the Related issues:
Discussed Considerations
API Proposalpublic sealed class QuicConnection : IAsyncDisposable
{
public static QuicConnection Create();
/// <summary>Indicates whether the QuicConnection is connected.</summary>
public bool Connected { get; }
/// <summary>Remote endpoint to which the connection try to get / is connected. Throws if Connected is false.</summary>
public IPEndPoint RemoteEndPoint { get; }
/// <summary>Local endpoint to which the connection will be / is bound. Throws if Connected is false.</summary>
public IPEndPoint LocalEndPoint { get; }
/// <summary>Peer's certificate, available only after the connection is fully connected (Connected is true) and the peer provided the certificate.</summary>
public X509Certificate? RemoteCertificate { get; }
/// <summary>Final, negotiated ALPN, available only after the connection is fully connected (Connected is true).</summary>
public SslApplicationProtocol NegotiatedApplicationProtocol { get; }
/// <summary>
/// Connects to the remote endpoint.
/// </summary>
public ValueTask ConnectAsync(QuicClientConnectionOptions options, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the maximum number of uni/bidirectional streams that can be made to the peer.
/// </summary>
public int GetAvailableStreamCount(StreamDirection direction);
/// <summary>
/// Create an outbound uni/bidirectional stream.
/// </summary>
public ValueTask<QuicStream> OpenStreamAsync(StreamDirection direction, CancellationToken cancellationToken = default);
/// <summary>
/// Create an outbound bidirectional stream.
/// </summary>
public ValueTask<QuicStream> OpenBidirectionalStreamAsync();
/// <summary>
/// Accept an incoming stream.
/// </summary>
public ValueTask<QuicStream> AcceptStreamAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Close the connection and terminate any active streams.
/// </summary>
public ValueTask CloseAsync(long errorCode, CancellationToken cancellationToken = default);
}
public enum StreamDirection
{
Unidirectional,
Bidirectional
}
/// <summary>Options for a new connection, the same options are used for incoming and outgoing connections.</summary>
public class QuicConnectionOptions
{
/// <summary>Limit on the number of bidirectional streams the remote peer connection can create on an open connection.</summary>
public int MaxBidirectionalStreams { get; init; } = 100;
/// <summary>Limit on the number of unidirectional streams the remote peer connection can create on an open connection.</summary>
public int MaxUnidirectionalStreams { get; init; } = 100;
/// <summary>Idle timeout for connections, after which the connection will be closed.</summary>
public TimeSpan IdleTimeout { get; init; } = TimeSpan.FromMinutes(2);
// This class will potentially expand with other connection options which we'll deem interesting for user to set.
}
/// <summary>Options for a new connection, only used for outgoing connections.</summary>
public class QuicClientConnectionOptions : QuicConnectionOptions
{
/// <summary>SSL options for the outgoing connection.</summary>
[Required]
public SslClientAuthenticationOptions ClientAuthenticationOptions { get; init; }
/// <summary>The endpoint to connect to.</summary>
[Required]
public EndPoint RemoteEndPoint { get; init; }
/// <summary>Optional local endpoint from which the connection is to be established.</summary>
public IPEndPoint? LocalEndPoint { get; init; }
} API UsageTODO Alternative DesignsTODO RisksAs I'll state with all QUIC APIs. We might consider making all of these
|
Some feedback:
cc @thhous-msft |
We have the same for
I haven't know about this. I have to read the specs and we need to discuss this. Thanks for pointing this out!
We were using it for multiple connections support, but we don't need it now and it's an additive API, so, I'll remove it for now.
That's true, also
We prefer to keep APIs minimal and add incrementally only when necessary (to reduce amount of code, to prevent mistakes in APIs, etc.). Also we don't want to lock us down only with msquic implementation. All of these are great comments and I'll discuss them with our team, thanks Nick. |
namespace System.Net.Quic;
public sealed class QuicConnection : IAsyncDisposable
{
public static bool IsSupported { get; }
public static ValueTask<QuicConnection> ConnectAsync(QuicConnectionOptions options,
CancellationToken cancellationToken = default);
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }
public X509Certificate2? RemoteCertificate { get; }
public SslApplicationProtocol NegotiatedApplicationProtocol { get; }
public ValueTask<QuicStream> OpenStreamAsync(QuicStreamType type, CancellationToken cancellationToken = default);
public ValueTask<QuicStream> AcceptStreamAsync(CancellationToken cancellationToken = default);
public ValueTask CloseAsync(long errorCode, CancellationToken cancellationToken = default);
public ValueTask DisposeAsync();
} |
namespace System.Net.Quic;
public abstract class QuicConnectionOptions
{
public int MaxBidirectionalStreams { get; set; } = 100;
public int MaxUnidirectionalStreams { get; set; } = 100;
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(2);
public long DefaultStreamErrorCode { get; set; }
public long DefaultConnectionErrorCode { get; set; }
public Action<QuicConnection>? EndPointChanged { get; set; }
}
public sealed class QuicClientConnectionOptions : QuicConnectionOptions
{
public QuicClientConnectionOptions();
public SslClientAuthenticationOptions ClientAuthenticationOptions { get; set; }
public EndPoint RemoteEndPoint { get; set; }
public IPEndPoint? LocalEndPoint { get; set; }
}
public sealed class QuicServerConnectionOptions : QuicConnectionOptions
{
public QuicServerConnectionOptions();
public SslServerAuthenticationOptions ServerAuthenticationOptions { get; set; }
} |
API Review CommentsQuicConnection.RemoteCertificate
QuicConnection.OpenStreamAsync
QuicConnection
QuicConnectionOptions
|
namespace System.Net.Quic;
public sealed class QuicConnection : IAsyncDisposable
{
public static bool IsSupported { get; }
public IPEndPoint RemoteEndPoint { get; }
public IPEndPoint LocalEndPoint { get; }
public X509Certificate2? RemoteCertificate { get; }
public SslApplicationProtocol NegotiatedApplicationProtocol { get; }
public static ValueTask<QuicConnection> ConnectAsync(QuicConnectionOptions options, CancellationToken cancellationToken = default);
public ValueTask<QuicStream> OpenOutboundStreamAsync(QuicStreamType type, CancellationToken cancellationToken = default);
public ValueTask<QuicStream> AcceptInboundStreamAsync(CancellationToken cancellationToken = default);
public ValueTask CloseAsync(long errorCode, CancellationToken cancellationToken = default);
public void DisposeAsync();
}
public abstract class QuicConnectionOptions
{
public int MaxInboundBidirectionalStreams { get; set; }
public int MaxInboundUnidirectionalStreams { get; set; }
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
public long DefaultStreamErrorCode { get; set; }
public long DefaultCloseErrorCode { get; set; }
}
public sealed class QuicClientConnectionOptions : QuicConnectionOptions
{
public QuicClientConnectionOptions();
public SslClientAuthenticationOptions ClientAuthenticationOptions { get; set; }
public EndPoint RemoteEndPoint { get; set; }
public IPEndPoint? LocalEndPoint { get; set; }
}
public sealed class QuicServerConnectionOptions : QuicConnectionOptions
{
public QuicServerConnectionOptions();
public SslServerAuthenticationOptions ServerAuthenticationOptions { get; set; }
} |
Background and motivation
API design for exposing QuicConnection and related classes to the public.
The API shape is based on the current internal shape of the class with the exception of merging the
ConnectAsync
intoQuicProvider.CreateConnectionAsync
.Related issues:
QUIC API: Consider passing QuicConnectionOptions to Quic.Connection.ConnectAsync #56009
Consider passing QuicConnectionOptions to Quic.Connection.ConnectAsync: we don't need to hold them just for the meantime between ctor and
ConnectAsync
[QUIC] Rewrite Open(Uni|Bidi)rectionalStream to leverage async stream opening #67302
Async stream open: perf need, coming from our benchmarks
HTTP/3: Create additional connections when maximum active streams is reached #51775
Multiple connections: same as H/2 requirement
[API Proposal]: QuicConnection.CancelPendingAcceptStream #60818
CancelPendingAcceptStream: used only for closing the connection, it's not as hot path as originally thought, I'd prefer not to do it now.
[API Proposal]: Expose TLS details for QUIC connection #70184
TLS details for QUIC connection
Discussed Considerations
--> YES
a) inside options in
ConnectAsync
fits better withSocket
/SslStream
--> YES, also keep them non-nullable and throw if not connected yet
b) inside ctor allows us to have
RemoteEndPoint
non-nullable and better aligns with incoming connections (they have both side address, but are not "configured" with options yet)--> NO
Socket
does, means that we need to create MsQuic connection object, try to connect it, let it fail, release it and then repeat for another IPCreate
, it would need to be done inConnectAsync
--> Properties are
IPEndPoint
, provided isEndPoint
that can also beDnsEndPoint
ConnectAsync
- we don't need them past the connection establishement moment so putting them intoCreate
doesn't make much senseCreate
+ConnectAsync
(==> we might consider makingQuicListener
Create
async as well)Create
parameter less, put everything to options and letConnectAsync
deal with it, this is not consistent withQuicListener
though (does it matter or not?)--> YES, options in
ConnectAsync
,Create
is ctor replacementTryOpenStreamAsync
+WaitForStreamAsync
(not prototyped yet)API Proposal
API Usage
Client usage:
Server usage:
Alternative Designs
QuicConnection
.Risks
As I'll state with all QUIC APIs. We might consider making all of these
PreviewFeature
. Not to deter user from using it, but to give us flexibility to tune the API shape based on customer feedback.We don't have many users now and we're mostly making these APIs based on what Kestrel needs, our limited experience with System.Net.Quic and my meager experiments with other QUIC implementations.
The text was updated successfully, but these errors were encountered: