Skip to content

Commit 1147c86

Browse files
committed
Unload MsQuic after checking for QUIC support to free resources (dotnet#75163)
* Revert "Revert "Unload MsQuic after checking for QUIC support to free resources. (dotnet#74749)" (dotnet#74984)" This reverts commit 953f524. * update helix images * update helix images * Improve diagnostics when opening MsQuic Co-authored-by: Radek Zikmund <radekzikmund@microsoft.com>
1 parent e8649de commit 1147c86

File tree

2 files changed

+80
-24
lines changed

2 files changed

+80
-24
lines changed

eng/pipelines/libraries/helix-queues-setup.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ jobs:
3939
# Linux arm64
4040
- ${{ if eq(parameters.platform, 'Linux_arm64') }}:
4141
- ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}:
42-
- (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220504035342-1b9461f
42+
- (Ubuntu.2204.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8-20220906173536-06f234f
4343
- ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}:
44-
- (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220427172132-97d8652
44+
- (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20220906173506-06f234f
45+
- ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}:
46+
- (Debian.10.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm64v8-20220906200500-06f234f
47+
- ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}:
48+
- (Debian.11.Arm64.Open)Ubuntu.1804.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm64v8-20220906200540-06f234f
4549

4650
# Linux musl x64
4751
- ${{ if eq(parameters.platform, 'Linux_musl_x64') }}:

src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Diagnostics.CodeAnalysis;
56
using System.Runtime.InteropServices;
67
using Microsoft.Quic;
@@ -47,7 +48,8 @@ private MsQuicApi(QUIC_API_TABLE* apiTable)
4748
}
4849
}
4950

50-
internal static MsQuicApi Api { get; } = null!;
51+
private static readonly Lazy<MsQuicApi> _api = new Lazy<MsQuicApi>(AllocateMsQuicApi);
52+
internal static MsQuicApi Api => _api.Value;
5153

5254
internal static bool IsQuicSupported { get; }
5355

@@ -58,29 +60,21 @@ private MsQuicApi(QUIC_API_TABLE* apiTable)
5860

5961
static MsQuicApi()
6062
{
61-
IntPtr msQuicHandle;
62-
if (!NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) &&
63-
!NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle))
63+
if (!TryLoadMsQuic(out IntPtr msQuicHandle))
6464
{
6565
return;
6666
}
6767

6868
try
6969
{
70-
if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
71-
{
72-
return;
73-
}
74-
75-
QUIC_API_TABLE* apiTable = null;
76-
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
77-
if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
70+
if (!TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable, out _))
7871
{
7972
return;
8073
}
8174

8275
try
8376
{
77+
// Check version
8478
int arraySize = 4;
8579
uint* libVersion = stackalloc uint[arraySize];
8680
uint size = (uint)arraySize * sizeof(uint);
@@ -99,7 +93,7 @@ static MsQuicApi()
9993
return;
10094
}
10195

102-
// Assume SChannel is being used on windows and query for the actual provider from the library
96+
// Assume SChannel is being used on windows and query for the actual provider from the library if querying is supported
10397
QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL;
10498
size = sizeof(QUIC_TLS_PROVIDER);
10599
apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider);
@@ -122,26 +116,84 @@ static MsQuicApi()
122116
Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false);
123117
}
124118

125-
Api = new MsQuicApi(apiTable);
126119
IsQuicSupported = true;
127120
}
128121
finally
129122
{
130-
if (!IsQuicSupported && NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose))
131-
{
132-
// Gracefully close the API table
133-
((delegate* unmanaged[Cdecl]<QUIC_API_TABLE*, void>)msQuicClose)(apiTable);
134-
}
123+
// Gracefully close the API table to free resources. The API table will be allocated lazily again if needed
124+
bool closed = TryCloseMsQuic(msQuicHandle, apiTable);
125+
Debug.Assert(closed, "Failed to close MsQuic");
135126
}
136-
137127
}
138128
finally
139129
{
140-
if (!IsQuicSupported)
130+
// Unload the library, we will load it again when we actually use QUIC
131+
NativeLibrary.Free(msQuicHandle);
132+
}
133+
}
134+
135+
private static MsQuicApi AllocateMsQuicApi()
136+
{
137+
Debug.Assert(IsQuicSupported);
138+
139+
int openStatus = MsQuic.QUIC_STATUS_INTERNAL_ERROR;
140+
141+
if (TryLoadMsQuic(out IntPtr msQuicHandle) &&
142+
TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable, out openStatus))
143+
{
144+
return new MsQuicApi(apiTable);
145+
}
146+
147+
ThrowHelper.ThrowIfMsQuicError(openStatus);
148+
149+
// this should unreachable as TryOpenMsQuic returns non-success status on failure
150+
throw new Exception("Failed to create MsQuicApi instance");
151+
}
152+
153+
private static bool TryLoadMsQuic(out IntPtr msQuicHandle) =>
154+
NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) ||
155+
NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle);
156+
157+
private static bool TryOpenMsQuic(IntPtr msQuicHandle, out QUIC_API_TABLE* apiTable, out int openStatus)
158+
{
159+
apiTable = null;
160+
if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
161+
{
162+
if (NetEventSource.Log.IsEnabled())
163+
{
164+
NetEventSource.Info(null, "Failed to get MsQuicOpenVersion export in msquic library.");
165+
}
166+
167+
openStatus = MsQuic.QUIC_STATUS_NOT_FOUND;
168+
return false;
169+
}
170+
171+
QUIC_API_TABLE* table = null;
172+
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
173+
openStatus = msQuicOpenVersion((uint)MsQuicVersion.Major, &table);
174+
if (StatusFailed(openStatus))
175+
{
176+
if (NetEventSource.Log.IsEnabled())
141177
{
142-
NativeLibrary.Free(msQuicHandle);
178+
NetEventSource.Info(null, $"MsQuicOpenVersion returned {openStatus} status code.");
143179
}
180+
181+
return false;
182+
}
183+
184+
apiTable = table;
185+
return true;
186+
}
187+
188+
private static bool TryCloseMsQuic(IntPtr msQuicHandle, QUIC_API_TABLE* apiTable)
189+
{
190+
if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose))
191+
{
192+
((delegate* unmanaged[Cdecl]<QUIC_API_TABLE*, void>)msQuicClose)(apiTable);
193+
return true;
144194
}
195+
196+
return false;
145197
}
146198

147199
private static bool IsWindowsVersionSupported() => OperatingSystem.IsWindowsVersionAtLeast(MinWindowsVersion.Major,

0 commit comments

Comments
 (0)