From 5e20ff9d7b1690ee1c09738b55f28cdcd4b67d54 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Tue, 6 Sep 2022 14:01:39 -0700 Subject: [PATCH 1/4] Revert "Revert "Unload MsQuic after checking for QUIC support to free resources. (#74749)" (#74984)" This reverts commit 953f52482ac2460e4b3faff33e4f73c9b30cd7b4. --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 83 +++++++++++++------ 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index e28134ea4b6f52..c83386d40737d9 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.Quic; @@ -47,7 +48,8 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) } } - internal static MsQuicApi Api { get; } = null!; + private static readonly Lazy _api = new Lazy(AllocateMsQuicApi); + internal static MsQuicApi Api => _api.Value; internal static bool IsQuicSupported { get; } @@ -58,29 +60,21 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) static MsQuicApi() { - IntPtr 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)) + if (!TryLoadMsQuic(out IntPtr msQuicHandle)) { return; } try { - if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) - { - return; - } - - QUIC_API_TABLE* apiTable = null; - delegate* unmanaged[Cdecl] msQuicOpenVersion = (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; - if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable))) + if (!TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable)) { return; } try { + // Check version int arraySize = 4; uint* libVersion = stackalloc uint[arraySize]; uint size = (uint)arraySize * sizeof(uint); @@ -99,7 +93,7 @@ static MsQuicApi() return; } - // Assume SChannel is being used on windows and query for the actual provider from the library + // Assume SChannel is being used on windows and query for the actual provider from the library if querying is supported QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL; size = sizeof(QUIC_TLS_PROVIDER); apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider); @@ -122,26 +116,67 @@ static MsQuicApi() Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false); } - Api = new MsQuicApi(apiTable); IsQuicSupported = true; } finally { - if (!IsQuicSupported && NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose)) - { - // Gracefully close the API table - ((delegate* unmanaged[Cdecl])msQuicClose)(apiTable); - } + // Gracefully close the API table to free resources. The API table will be allocated lazily again if needed + bool closed = TryCloseMsQuic(msQuicHandle, apiTable); + Debug.Assert(closed, "Failed to close MsQuic"); } - } finally { - if (!IsQuicSupported) - { - NativeLibrary.Free(msQuicHandle); - } + // Unload the library, we will load it again when we actually use QUIC + NativeLibrary.Free(msQuicHandle); + } + } + + private static MsQuicApi AllocateMsQuicApi() + { + Debug.Assert(IsQuicSupported); + + if (TryLoadMsQuic(out IntPtr msQuicHandle) && + TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable)) + { + return new MsQuicApi(apiTable); + } + + throw new Exception("Failed to create MsQuicApi instance"); + } + + private static bool TryLoadMsQuic(out IntPtr msQuicHandle) => + 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); + + private static bool TryOpenMsQuic(IntPtr msQuicHandle, out QUIC_API_TABLE* apiTable) + { + apiTable = null; + if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) + { + return false; + } + + QUIC_API_TABLE* table = null; + delegate* unmanaged[Cdecl] msQuicOpenVersion = (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; + if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &table))) + { + return false; } + + apiTable = table; + return true; + } + + private static bool TryCloseMsQuic(IntPtr msQuicHandle, QUIC_API_TABLE* apiTable) + { + if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose)) + { + ((delegate* unmanaged[Cdecl])msQuicClose)(apiTable); + return true; + } + + return false; } private static bool IsWindowsVersionSupported() => OperatingSystem.IsWindowsVersionAtLeast(MinWindowsVersion.Major, From 07e8855d6388428a1c018c90ef9800f4e02a1dc1 Mon Sep 17 00:00:00 2001 From: wfurt Date: Tue, 6 Sep 2022 14:07:51 -0700 Subject: [PATCH 2/4] update helix images --- eng/pipelines/libraries/helix-queues-setup.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 52695356baf280..1dcb97d4cbf041 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -39,13 +39,13 @@ jobs: # Linux arm64 - ${{ if eq(parameters.platform, 'Linux_arm64') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220824230626-06f234f + - (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220831130402-06f234f - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220824230426-06f234f + - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220831130538-06f234f - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.10.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220820185240-06f234f + - (Debian.10.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220906200500-06f234f - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.11.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm64v8-20220820185253-06f234f + - (Debian.11.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220906200500-06f234f # Linux musl x64 - ${{ if eq(parameters.platform, 'Linux_musl_x64') }}: From f9bd0e31457d4b01a82a0d3dfccb59ad7f8d369f Mon Sep 17 00:00:00 2001 From: wfurt Date: Tue, 6 Sep 2022 18:53:19 -0700 Subject: [PATCH 3/4] update helix images --- eng/pipelines/libraries/helix-queues-setup.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 1dcb97d4cbf041..875fd96f4c75fc 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -39,13 +39,13 @@ jobs: # Linux arm64 - ${{ if eq(parameters.platform, 'Linux_arm64') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220831130402-06f234f + - (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220906173536-06f234f - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220831130538-06f234f + - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220906173506-06f234f - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Debian.10.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220906200500-06f234f - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.11.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220906200500-06f234f + - (Debian.11.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm64v8-20220906200540-06f234f # Linux musl x64 - ${{ if eq(parameters.platform, 'Linux_musl_x64') }}: From 3986f7108c1c82a33b4a557e3457f738c5418a21 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 2 Sep 2022 10:55:32 +0200 Subject: [PATCH 4/4] Improve diagnostics when opening MsQuic --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index c83386d40737d9..e3e4728610b14f 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -67,7 +67,7 @@ static MsQuicApi() try { - if (!TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable)) + if (!TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable, out _)) { return; } @@ -136,12 +136,17 @@ private static MsQuicApi AllocateMsQuicApi() { Debug.Assert(IsQuicSupported); + int openStatus = MsQuic.QUIC_STATUS_INTERNAL_ERROR; + if (TryLoadMsQuic(out IntPtr msQuicHandle) && - TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable)) + TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable, out openStatus)) { return new MsQuicApi(apiTable); } + ThrowHelper.ThrowIfMsQuicError(openStatus); + + // this should unreachable as TryOpenMsQuic returns non-success status on failure throw new Exception("Failed to create MsQuicApi instance"); } @@ -149,18 +154,30 @@ private static bool TryLoadMsQuic(out IntPtr msQuicHandle) => 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); - private static bool TryOpenMsQuic(IntPtr msQuicHandle, out QUIC_API_TABLE* apiTable) + private static bool TryOpenMsQuic(IntPtr msQuicHandle, out QUIC_API_TABLE* apiTable, out int openStatus) { apiTable = null; if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(null, "Failed to get MsQuicOpenVersion export in msquic library."); + } + + openStatus = MsQuic.QUIC_STATUS_NOT_FOUND; return false; } QUIC_API_TABLE* table = null; delegate* unmanaged[Cdecl] msQuicOpenVersion = (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; - if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &table))) + openStatus = msQuicOpenVersion((uint)MsQuicVersion.Major, &table); + if (StatusFailed(openStatus)) { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(null, $"MsQuicOpenVersion returned {openStatus} status code."); + } + return false; }