Skip to content

Commit

Permalink
"[QUIC] Adopted msquic generated interop (dotnet#68288)" attempt no 2 (
Browse files Browse the repository at this point in the history
…dotnet#69009)

* Revert "Revert "[QUIC] Adopted msquic generated interop (dotnet#68288)" (dotnet#68940)"

This reverts commit 4820674.

* Exclude S.N.Quic from Mono AOT

* Fix dotnet#68954
  • Loading branch information
ManickaP committed May 11, 2022
1 parent 094b787 commit 122c9d0
Show file tree
Hide file tree
Showing 41 changed files with 3,935 additions and 2,566 deletions.
8 changes: 8 additions & 0 deletions THIRD-PARTY-NOTICES.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -1065,3 +1065,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

License notice for MsQuic
--------------------------------------

Copyright (c) Microsoft Corporation.
Licensed under the MIT License.

Available at
https://github.com/microsoft/msquic/blob/main/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ private async Task HandleControlStreamAsync(Http3LoopbackStream controlStream)
throw new Exception("Received second control stream from client???");
}

Assert.False(controlStream.CanWrite);

long? streamType = await controlStream.ReadIntegerAsync();
Assert.Equal(Http3LoopbackStream.ControlStream, streamType);

Expand All @@ -143,19 +145,37 @@ private async Task HandleControlStreamAsync(Http3LoopbackStream controlStream)
// This will automatically handle the control stream, including validating its contents
public async Task<Http3LoopbackStream> AcceptRequestStreamAsync()
{
Http3LoopbackStream stream;
Http3LoopbackStream requestStream = null;

while (true)
{
stream = await AcceptStreamAsync().ConfigureAwait(false);
var stream = await AcceptStreamAsync().ConfigureAwait(false);

// Accepted request stream.
if (stream.CanWrite)
{
return stream;
// Only one expected.
Assert.True(requestStream is null, "Expected single request stream, got a second");

// Control stream is set --> return the request stream.
if (_inboundControlStream is not null)
{
return stream;
}

// Control stream not set --> need to accept another stream.
requestStream = stream;
continue;
}

// Must be the control stream
// Must be the control stream.
await HandleControlStreamAsync(stream);

// We've already accepted request stream --> return it.
if (requestStream is not null)
{
return requestStream;
}
}
}

Expand Down
25 changes: 3 additions & 22 deletions src/libraries/System.Net.Quic/src/System.Net.Quic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,16 @@
<Compile Include="System\Net\Quic\Implementations\Mock\*.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\MsQuicAlpnHelper.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicEnums.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicNativeMethods.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusCodes.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusHelper.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicTraceHelper.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\SafeMsQuicConfigurationHandle.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\SafeMsQuicConnectionHandle.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\SafeMsQuicListenerHandle.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\SafeMsQuicRegistrationHandle.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\SafeMsQuicStreamHandle.cs" />
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs">
<Link>Common\DisableRuntimeMarshalling.cs</Link>
</Compile>
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\*.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" />
<Compile Include="$(CommonPath)System\Net\ArrayBuffer.cs" Link="Common\System\Net\ArrayBuffer.cs" />
<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 -->
Expand All @@ -74,7 +61,6 @@
<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'">
Expand Down Expand Up @@ -107,26 +93,21 @@
</ItemGroup>
<!-- Linux specific files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'Linux'">
<Compile Include="$(CommonPath)Interop\Linux\Interop.Libraries.cs" Link="Common\Interop\Linux\Interop.Libraries.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusCodes.Linux.cs" />
<Compile Include="$(CommonPath)System\Net\Security\CertificateValidation.Unix.cs" Link="Common\System\Net\Security\CertificateValidation.Unix.cs" />
<Compile Include="$(CommonPath)Interop\Linux\Interop.Libraries.cs" Link="Common\Interop\Linux\Interop.Libraries.cs" />
</ItemGroup>
<!-- FreeBSD specific files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'FreeBSD' ">
<Compile Include="$(CommonPath)System\Net\Security\CertificateValidation.Unix.cs" Link="Common\System\Net\Security\CertificateValidation.Unix.cs" />
<Compile Include="$(CommonPath)Interop\FreeBSD\Interop.Libraries.cs" Link="Common\Interop\FreeBSD\Interop.Libraries.cs" />
<!-- Assume similarity with OSX for now -->
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusCodes.OSX.cs" />
</ItemGroup>
<!-- OSX specific files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'OSX'">
<Compile Include="$(CommonPath)System\Net\Security\CertificateValidation.OSX.cs" Link="Common\System\Net\Security\CertificateValidation.OSX.cs" />
<Compile Include="$(CommonPath)Interop\OSX\Interop.Libraries.cs" Link="Common\Interop\OSX\Interop.Libraries.cs" />
<Compile Include="System\Net\Quic\Implementations\MsQuic\Interop\MsQuicStatusCodes.OSX.cs" />
</ItemGroup>

<!-- Project references -->

<ItemGroup>
<PackageReference Include="System.Net.MsQuic.Transport"
Version="$(SystemNetMsQuicTransportVersion)"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net.Sockets;
using System.Runtime.InteropServices;
using static System.Net.Quic.Implementations.MsQuic.Internal.MsQuicNativeMethods;

namespace System.Net.Quic.Implementations.MsQuic.Internal
{
internal static class MsQuicAddressHelpers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@

using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Quic;

using static Microsoft.Quic.MsQuic;

#if TARGET_WINDOWS
using Microsoft.Win32;
#endif

using static System.Net.Quic.Implementations.MsQuic.Internal.MsQuicNativeMethods;

namespace System.Net.Quic.Implementations.MsQuic.Internal
{
internal sealed unsafe class MsQuicApi
{
private static readonly byte[] s_appName = Encoding.ASCII.GetBytes("System.Net.Quic");

private static readonly Version MinWindowsVersion = new Version(10, 0, 20145, 1000);

private static readonly Version MsQuicVersion = new Version(2, 0);

public SafeMsQuicRegistrationHandle Registration { get; }

public QUIC_API_TABLE* ApiTable { get; }

// This is workaround for a bug in ILTrimmer.
// Without these DynamicDependency attributes, .ctor() will be removed from the safe handles.
// Remove once fixed: https://github.com/mono/linker/issues/1660
Expand All @@ -26,89 +34,28 @@ internal sealed unsafe class MsQuicApi
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(SafeMsQuicListenerHandle))]
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(SafeMsQuicConnectionHandle))]
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(SafeMsQuicStreamHandle))]
private MsQuicApi(NativeApi* vtable)
private MsQuicApi(QUIC_API_TABLE* apiTable)
{
uint status;

SetParamDelegate =
new SetParamDelegate(new DelegateHelper(vtable->SetParam).SetParam);

GetParamDelegate =
new GetParamDelegate(new DelegateHelper(vtable->GetParam).GetParam);

SetCallbackHandlerDelegate =
new SetCallbackHandlerDelegate(new DelegateHelper(vtable->SetCallbackHandler).SetCallbackHandler);

RegistrationOpenDelegate =
new RegistrationOpenDelegate(new DelegateHelper(vtable->RegistrationOpen).RegistrationOpen);
RegistrationCloseDelegate =
Marshal.GetDelegateForFunctionPointer<RegistrationCloseDelegate>(
vtable->RegistrationClose);

ConfigurationOpenDelegate =
new ConfigurationOpenDelegate(new DelegateHelper(vtable->ConfigurationOpen).ConfigurationOpen);
ConfigurationCloseDelegate =
Marshal.GetDelegateForFunctionPointer<ConfigurationCloseDelegate>(
vtable->ConfigurationClose);
ConfigurationLoadCredentialDelegate =
new ConfigurationLoadCredentialDelegate(new DelegateHelper(vtable->ConfigurationLoadCredential).ConfigurationLoadCredential);

ListenerOpenDelegate =
new ListenerOpenDelegate(new DelegateHelper(vtable->ListenerOpen).ListenerOpen);
ListenerCloseDelegate =
Marshal.GetDelegateForFunctionPointer<ListenerCloseDelegate>(
vtable->ListenerClose);
ListenerStartDelegate =
new ListenerStartDelegate(new DelegateHelper(vtable->ListenerStart).ListenerStart);
ListenerStopDelegate =
new ListenerStopDelegate(new DelegateHelper(vtable->ListenerStop).ListenerStop);

ConnectionOpenDelegate =
new ConnectionOpenDelegate(new DelegateHelper(vtable->ConnectionOpen).ConnectionOpen);
ConnectionCloseDelegate =
Marshal.GetDelegateForFunctionPointer<ConnectionCloseDelegate>(
vtable->ConnectionClose);
ConnectionSetConfigurationDelegate =
new ConnectionSetConfigurationDelegate(new DelegateHelper(vtable->ConnectionSetConfiguration).ConnectionSetConfiguration);
ConnectionShutdownDelegate =
new ConnectionShutdownDelegate(new DelegateHelper(vtable->ConnectionShutdown).ConnectionShutdown);
ConnectionStartDelegate =
new ConnectionStartDelegate(new DelegateHelper(vtable->ConnectionStart).ConnectionStart);

StreamOpenDelegate =
new StreamOpenDelegate(new DelegateHelper(vtable->StreamOpen).StreamOpen);
StreamCloseDelegate =
Marshal.GetDelegateForFunctionPointer<StreamCloseDelegate>(
vtable->StreamClose);
StreamStartDelegate =
new StreamStartDelegate(new DelegateHelper(vtable->StreamStart).StreamStart);
StreamShutdownDelegate =
new StreamShutdownDelegate(new DelegateHelper(vtable->StreamShutdown).StreamShutdown);
StreamSendDelegate =
new StreamSendDelegate(new DelegateHelper(vtable->StreamSend).StreamSend);
StreamReceiveCompleteDelegate =
new StreamReceiveCompleteDelegate(new DelegateHelper(vtable->StreamReceiveComplete).StreamReceiveComplete);
StreamReceiveSetEnabledDelegate =
new StreamReceiveSetEnabledDelegate(new DelegateHelper(vtable->StreamReceiveSetEnabled).StreamReceiveSetEnabled);

var cfg = new RegistrationConfig
ApiTable = apiTable;

fixed (byte* pAppName = s_appName)
{
AppName = ".NET",
ExecutionProfile = QUIC_EXECUTION_PROFILE.QUIC_EXECUTION_PROFILE_LOW_LATENCY
};
var cfg = new QUIC_REGISTRATION_CONFIG {
AppName = (sbyte*)pAppName,
ExecutionProfile = QUIC_EXECUTION_PROFILE.LOW_LATENCY
};

status = RegistrationOpenDelegate(ref cfg, out SafeMsQuicRegistrationHandle handle);
QuicExceptionHelpers.ThrowIfFailed(status, "RegistrationOpen failed.");
QUIC_HANDLE* handle;
ThrowIfFailure(ApiTable->RegistrationOpen(&cfg, &handle), "RegistrationOpen failed");

Registration = handle;
Registration = new SafeMsQuicRegistrationHandle(handle);
}
}

internal static MsQuicApi Api { get; } = null!;

internal static bool IsQuicSupported { get; }

private const int MsQuicVersion = 2;

internal static bool Tls13MayBeDisabled { get; }

static MsQuicApi()
Expand All @@ -129,21 +76,36 @@ static MsQuicApi()
}

IntPtr msQuicHandle;
if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) ||
if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) ||
NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle))
{
try
{
if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
{
NativeApi* vtable;
delegate* unmanaged[Cdecl]<uint, NativeApi**, uint> msQuicOpenVersion =
(delegate* unmanaged[Cdecl]<uint, NativeApi**, uint>)msQuicOpenVersionAddress;
uint status = msQuicOpenVersion(MsQuicVersion, &vtable);
if (MsQuicStatusHelper.SuccessfulStatusCode(status))
QUIC_API_TABLE* apiTable;
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
if (StatusSucceeded(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
{
IsQuicSupported = true;
Api = new MsQuicApi(vtable);
int arraySize = 4;
uint* libVersion = stackalloc uint[arraySize];
uint size = (uint)arraySize * sizeof(uint);
if (StatusSucceeded(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion)))
{
var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]);
if (version >= MsQuicVersion)
{
Api = new MsQuicApi(apiTable);
IsQuicSupported = true;
}
else
{
if (NetEventSource.Log.IsEnabled())
{
NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'");
}
}
}
}
}
}
Expand Down Expand Up @@ -182,38 +144,5 @@ private static bool IsTls13Disabled()
#endif
return false;
}

// TODO: Consider updating all of these delegates to instead use function pointers.
internal RegistrationOpenDelegate RegistrationOpenDelegate { get; }
internal RegistrationCloseDelegate RegistrationCloseDelegate { get; }

internal ConfigurationOpenDelegate ConfigurationOpenDelegate { get; }
internal ConfigurationCloseDelegate ConfigurationCloseDelegate { get; }
internal ConfigurationLoadCredentialDelegate ConfigurationLoadCredentialDelegate { get; }

internal ListenerOpenDelegate ListenerOpenDelegate { get; }
internal ListenerCloseDelegate ListenerCloseDelegate { get; }
internal ListenerStartDelegate ListenerStartDelegate { get; }
internal ListenerStopDelegate ListenerStopDelegate { get; }

// TODO: missing SendResumptionTicket
internal ConnectionOpenDelegate ConnectionOpenDelegate { get; }
internal ConnectionCloseDelegate ConnectionCloseDelegate { get; }
internal ConnectionShutdownDelegate ConnectionShutdownDelegate { get; }
internal ConnectionStartDelegate ConnectionStartDelegate { get; }
internal ConnectionSetConfigurationDelegate ConnectionSetConfigurationDelegate { get; }

internal StreamOpenDelegate StreamOpenDelegate { get; }
internal StreamCloseDelegate StreamCloseDelegate { get; }
internal StreamStartDelegate StreamStartDelegate { get; }
internal StreamShutdownDelegate StreamShutdownDelegate { get; }
internal StreamSendDelegate StreamSendDelegate { get; }
internal StreamReceiveCompleteDelegate StreamReceiveCompleteDelegate { get; }
internal StreamReceiveSetEnabledDelegate StreamReceiveSetEnabledDelegate { get; }

internal SetCallbackHandlerDelegate SetCallbackHandlerDelegate { get; }

internal SetParamDelegate SetParamDelegate { get; }
internal GetParamDelegate GetParamDelegate { get; }
}
}
Loading

0 comments on commit 122c9d0

Please sign in to comment.