-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Unload MsQuic after checking for QUIC support to free resources. #74749
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -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!; | ||||||
internal static Lazy<MsQuicApi> _api = new Lazy<MsQuicApi>(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]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress; | ||||||
if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable))) | ||||||
if (!TryOpenMsQuic(msQuicHandle, out QUIC_API_TABLE* apiTable)) | ||||||
{ | ||||||
return; | ||||||
} | ||||||
|
||||||
try | ||||||
{ | ||||||
// check version | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uber nitty nit 😄
Suggested change
|
||||||
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]<QUIC_API_TABLE*, void>)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); | ||||||
} | ||||||
} | ||||||
|
||||||
internal 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"); | ||||||
} | ||||||
|
||||||
internal static bool TryLoadMsQuic(out IntPtr msQuicHandle) => | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should those be private? |
||||||
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); | ||||||
|
||||||
internal static bool TryOpenMsQuic(IntPtr msQuicHandle, out QUIC_API_TABLE* apiTable) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could alternatively use [LibraryImport] for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They already have imports in: runtime/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs Line 2593 in bf47ac0
I'm not an expert on this, but we control which version of libmsquic we're loading in Anyway, we might at least use |
||||||
{ | ||||||
apiTable = null; | ||||||
if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) | ||||||
{ | ||||||
return false; | ||||||
} | ||||||
|
||||||
QUIC_API_TABLE* table = null; | ||||||
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress; | ||||||
if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &table))) | ||||||
{ | ||||||
return false; | ||||||
} | ||||||
|
||||||
apiTable = table; | ||||||
return true; | ||||||
} | ||||||
|
||||||
internal static bool TryCloseMsQuic(IntPtr msQuicHandle, QUIC_API_TABLE* apiTable) | ||||||
{ | ||||||
if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose)) | ||||||
{ | ||||||
((delegate* unmanaged[Cdecl]<QUIC_API_TABLE*, void>)msQuicClose)(apiTable); | ||||||
return true; | ||||||
} | ||||||
|
||||||
return false; | ||||||
} | ||||||
|
||||||
private static bool IsWindowsVersionSupported() => OperatingSystem.IsWindowsVersionAtLeast(MinWindowsVersion.Major, | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private readonly?