Skip to content
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

[QUIC] API Update #49823

Merged
merged 15 commits into from
Mar 26, 2021
Merged

[QUIC] API Update #49823

merged 15 commits into from
Mar 26, 2021

Conversation

ManickaP
Copy link
Member

@ManickaP ManickaP commented Mar 18, 2021

Updated API to microsoft/msquic@cc104e8, branched in my fork: https://github.com/ManickaP/msquic/commits/mapichov/net6_2020_03_18

The change mostly taken from https://github.com/scalablecory/runtime/tree/msquic-update. Plus: updated the msquic version to the newest main, adjusted the API, made compilable, fixed obvious test errors.

Fixes #44580, #31695

It still needs more work, but I don't want to hold msquic API update on refactorings / clean ups.

@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Mar 18, 2021

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Updated API to microsoft/msquic@cc104e8, branched in my fork: https://github.com/ManickaP/msquic/commits/mapichov/net6_2020_03_18

The change mostly taken from https://github.com/scalablecory/runtime/tree/msquic-update

Fixes #44580, #31695

Author: ManickaP
Assignees: -
Labels:

area-System.Net.Quic, new-api-needs-documentation

Milestone: -

@ManickaP ManickaP marked this pull request as ready for review March 18, 2021 14:26
<Content Include="libmsquic.so" Condition="Exists('libmsquic.so')">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="msquic.pdb" Condition="Exists('msquic.pdb')">
<Content Include="libmsquic.lttng.so" Condition="Exists('libmsquic.lttng.so')">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@scalablecory could we reference the System.Net.Experimental.Quic here instead now? https://github.com/dotnet/runtimelab/tree/feature/System.Net.Experimental.MsQuic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You won't need that package for .NET 6.

@@ -299,58 +446,68 @@ internal struct ConnectionEvent
IntPtr context,
ref ConnectionEvent connectionEvent);

// TODO: order is Open, Close, Shutdown, Start, SetConfiguration, SendResumptionTicket
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be removed now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, that's my comment. The order (in the comment) is taken from msquic.h, we do not follow that in here. I didn't want to generate more diffs in this PR. I'll plan to do follow up that does not change the behavior at all, just shuffles things around to be more like msquic.h.

default:
return MsQuicStatusCodes.InternalError;
}
return MsQuicStatusCodes.InternalError;
Copy link
Member

@JamesNK JamesNK Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the plan for logging inside System.Net.Quic?

For example, here there should be a log message that an unknown callback was received, including the unexpected evt.Type value. A generic InternalError status code isn't enough to understand what went wrong.

(logging can be added in the future, not blocking for this PR)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this - #32072

/// Default is 100.
/// </summary>
// TODO consider constraining these limits to 0 to whatever the max of the QUIC library we are using.
public long MaxBidirectionalStreams { get; set; } = 100;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need validation to stop invalid values (e.g. 0 or -50). Applies to all options.

Create an issue if you would prefer to do it in a follow up PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of this #32079:

How should we be validating these limits?

public class MsQuicTestBase
{
public SslServerAuthenticationOptions GetSslServerAuthenticationOptions()
{
return new SslServerAuthenticationOptions()
{
ApplicationProtocols = new List<SslApplicationProtocol>() { new SslApplicationProtocol("quictest") }
ApplicationProtocols = new List<SslApplicationProtocol>() { new SslApplicationProtocol("quictest") },
// TODO: use a cert. MsQuic currently only allows certs that are trusted.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the cause of this trusted limitation? Is it a requirement of QUIC, or because we haven't added configuration to ignore invalid certificates yet?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may need to plumb custom validation callback to managed code. I'm not sure if that was already done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_state.Connection = this;
try
{
uint status = MsQuicApi.Api.ConnectionStartDelegate(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to have QuicStatus enum here? While the list of errors may grow, there are really only three interesting values IMHO. We do that in some other places and it make debugging much easier as you can see the enum instead of number.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have something: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/MsQuicStatusCodes.cs
The codes differ on different platforms, that's why it's separate. Could we define an enum per platform and use it? I guess we could. Is it worth it? Depends on what we decide to do about the generated interop.
Otherwise, better messages are covered by #32066.


namespace System.Net.Quic.Implementations.MsQuic.Internal
{
internal enum QUIC_EXECUTION_PROFILE : uint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really NOT the style guy but in some other places we made the names C# friendly.

internal enum SecurityStatusPalErrorCode
{
NotSet = 0,
OK,
ContinueNeeded,
CompleteNeeded,

and we use int unless uint is really needed (even if underlying C is uint)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't change the naming scheme in this PR, that's too revolutionary 😃.
We might change it in a separate one or we might go a different direction if we chose to generate the interop.

QuicBuffer[]? buffers = null;
try
{
MsQuicAlpnHelper.Prepare(alpnProtocols, out handles, out buffers);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need safe handles here. Since this only needs preserve through the call and never be exposed outside of this function I'm wondering if there is easier way. I'm sure the handles will work but feel heavy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you can rely on MsQuic to copy what it needs in the function call. The memory doesn't have to exist beyond that,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultimately I'd love to have a configuration API -- something like SocketsHttpHandler really doesn't need more than a single configuration, while the current code will allocate one for every new connection it opens.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultimately I'd love to have a configuration API -- something like SocketsHttpHandler really doesn't need more than a single configuration, while the current code will allocate one for every new connection it opens.

Creating a configuration is a very heavy weight operation. I'd highly recommend one of the next things you do is to refactor this like @scalablecory mentions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean that ConfigurationLoadCredential might be called multiple times on the same configuration with different certificate?
Or how should I go about sharing the configuration?

Am I wrong in my train of thought: instance of SocketsHttpHandler corresponds to one connection pool which corresponds to a single QuicConnection which holds one configuration.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, you create one configuration for each unique security configuration. On server that usually maps 1:1 with each server certificate. On client most times there is only one, unless they're creating clients with different configurations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This is captured in #42642)

Copy link
Member

@wfurt wfurt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I think there is opportunity for improvements I feel there is value in getting something in and working in improvements over time. This is not cast in stone and underlying code may be fluid.

Copy link
Contributor

@scalablecory scalablecory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -91,7 +91,9 @@ internal override bool Connected
}

// TODO: Should clone the endpoint since it is mutable
internal override IPEndPoint LocalEndPoint => _localEndPoint;
// TODO: could this be made back to non-nullable?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get rid of instance method ConnectAsync and make a static ValueTask<QuicConnection> QuicConnection.ConnectAsync(), then we can always have LocalEndPoint be non-null.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I consider the TODO as work that needs to be done/resolved. But I don't want to hold the PR on those issues. The work will be done in follow up PRs.


private readonly IntPtr _registrationContext;
SetParamDelegate =
Marshal.GetDelegateForFunctionPointer<SetParamDelegate>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider using function pointers instead of delegates.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been pointed out by Stephen and is captured here:

// TODO: Consider updating all of these delegates to instead use function pointers.

It's on the plate.

QuicBuffer[]? buffers = null;
try
{
MsQuicAlpnHelper.Prepare(alpnProtocols, out handles, out buffers);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultimately I'd love to have a configuration API -- something like SocketsHttpHandler really doesn't need more than a single configuration, while the current code will allocate one for every new connection it opens.

private GCHandle _handle;
// TODO: remove this.
// This is only used for client-initiated connections, and isn't needed even then once Connect() has been called.
private readonly SafeMsQuicConfigurationHandle? _configuration;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another thing that'd be removable if we switched to a static Connect as in a former comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I consider the TODO as work that needs to be done/resolved. But I don't want to hold the PR on those issues. The work will be done in follow up PRs.

@ManickaP

This comment has been minimized.

@azure-pipelines

This comment has been minimized.

Copy link
Contributor

@jkotalik jkotalik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@ManickaP
Copy link
Member Author

Only waiting for the build to finish, then I'll merge.

@ManickaP ManickaP merged commit 484a807 into dotnet:main Mar 26, 2021
@ManickaP ManickaP deleted the mapichov/44580_quic_update branch March 26, 2021 17:21
@ghost ghost locked as resolved and limited conversation to collaborators Apr 25, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update MsQuic
7 participants