Skip to content

Commit a58e25a

Browse files
ManickaPrzikm
andauthored
Close MsQuic after checking for QUIC support to free resources (#75163, #75441) (#80785)
Co-authored-by: Radek Zikmund <[email protected]>
1 parent 955f05e commit a58e25a

File tree

1 file changed

+56
-21
lines changed
  • src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal

1 file changed

+56
-21
lines changed

Diff for: src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs

+56-21
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 static System.Net.Quic.Implementations.MsQuic.Internal.MsQuicNativeMethods;
@@ -117,12 +118,17 @@ private MsQuicApi(NativeApi* vtable)
117118
Registration = handle;
118119
}
119120

120-
internal static MsQuicApi Api { get; } = null!;
121+
private static readonly delegate* unmanaged[Cdecl]<uint, NativeApi**, uint> MsQuicOpenVersion;
122+
private static readonly delegate* unmanaged[Cdecl]<NativeApi*, void> MsQuicClose;
123+
124+
private static readonly Lazy<MsQuicApi> s_api = new Lazy<MsQuicApi>(AllocateMsQuicApi);
125+
internal static MsQuicApi Api => s_api.Value;
121126

122127
internal static bool IsQuicSupported { get; }
123128

124129
private const int MsQuicVersion = 1;
125130

131+
#pragma warning disable CA1810 // Initialize all static fields in 'MsQuicApi' when those fields are declared and remove the explicit static constructor
126132
static MsQuicApi()
127133
{
128134
if (OperatingSystem.IsWindows() && !IsWindowsVersionSupported())
@@ -135,30 +141,59 @@ static MsQuicApi()
135141
return;
136142
}
137143

138-
if (NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out IntPtr msQuicHandle))
144+
if (!NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out IntPtr msQuicHandle))
139145
{
140-
try
141-
{
142-
if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
143-
{
144-
delegate* unmanaged[Cdecl]<uint, out NativeApi*, uint> msQuicOpenVersion =
145-
(delegate* unmanaged[Cdecl]<uint, out NativeApi*, uint>)msQuicOpenVersionAddress;
146-
uint status = msQuicOpenVersion(MsQuicVersion, out NativeApi* vtable);
147-
if (MsQuicStatusHelper.SuccessfulStatusCode(status))
148-
{
149-
IsQuicSupported = true;
150-
Api = new MsQuicApi(vtable);
151-
}
152-
}
153-
}
154-
finally
146+
// MsQuic library not loaded
147+
return;
148+
}
149+
150+
MsQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, NativeApi**, uint>)NativeLibrary.GetExport(msQuicHandle, nameof(MsQuicOpenVersion));
151+
MsQuicClose = (delegate* unmanaged[Cdecl]<NativeApi*, void>)NativeLibrary.GetExport(msQuicHandle, nameof(MsQuicClose));
152+
153+
if (!TryOpenMsQuic(out NativeApi* apiTable, out _))
154+
{
155+
// Different version of the library.
156+
return;
157+
}
158+
159+
IsQuicSupported = true;
160+
161+
// Gracefully close the API table to free resources. The API table will be allocated lazily again if needed
162+
MsQuicClose(apiTable);
163+
}
164+
#pragma warning restore CA1810
165+
166+
private static MsQuicApi AllocateMsQuicApi()
167+
{
168+
Debug.Assert(IsQuicSupported);
169+
170+
if (!TryOpenMsQuic(out NativeApi* apiTable, out uint openStatus))
171+
{
172+
QuicExceptionHelpers.ThrowIfFailed(openStatus);
173+
}
174+
175+
return new MsQuicApi(apiTable);
176+
}
177+
178+
private static bool TryOpenMsQuic(out NativeApi* apiTable, out uint openStatus)
179+
{
180+
Debug.Assert(MsQuicOpenVersion != null);
181+
182+
NativeApi* table = null;
183+
openStatus = MsQuicOpenVersion((uint)MsQuicVersion, &table);
184+
if (!MsQuicStatusHelper.SuccessfulStatusCode(openStatus))
185+
{
186+
if (NetEventSource.Log.IsEnabled())
155187
{
156-
if (!IsQuicSupported)
157-
{
158-
NativeLibrary.Free(msQuicHandle);
159-
}
188+
NetEventSource.Info(null, $"MsQuicOpenVersion(version: {MsQuicVersion}) returned {MsQuicStatusCodes.GetError(openStatus)} status code.");
160189
}
190+
191+
apiTable = null;
192+
return false;
161193
}
194+
195+
apiTable = table;
196+
return true;
162197
}
163198

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

0 commit comments

Comments
 (0)