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 ;
54using System . Diagnostics . CodeAnalysis ;
65using System . Runtime . InteropServices ;
76using Microsoft . Quic ;
@@ -48,8 +47,7 @@ private MsQuicApi(QUIC_API_TABLE* apiTable)
4847 }
4948 }
5049
51- private static readonly Lazy < MsQuicApi > _api = new Lazy < MsQuicApi > ( AllocateMsQuicApi ) ;
52- internal static MsQuicApi Api => _api . Value ;
50+ internal static MsQuicApi Api { get ; } = null ! ;
5351
5452 internal static bool IsQuicSupported { get ; }
5553
@@ -60,21 +58,29 @@ private MsQuicApi(QUIC_API_TABLE* apiTable)
6058
6159 static MsQuicApi ( )
6260 {
63- if ( ! TryLoadMsQuic ( out IntPtr msQuicHandle ) )
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 ) )
6464 {
6565 return ;
6666 }
6767
6868 try
6969 {
70- if ( ! TryOpenMsQuic ( msQuicHandle , out QUIC_API_TABLE * apiTable ) )
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 ) ) )
7178 {
7279 return ;
7380 }
7481
7582 try
7683 {
77- // Check version
7884 int arraySize = 4 ;
7985 uint * libVersion = stackalloc uint [ arraySize ] ;
8086 uint size = ( uint ) arraySize * sizeof ( uint ) ;
@@ -93,7 +99,7 @@ static MsQuicApi()
9399 return ;
94100 }
95101
96- // Assume SChannel is being used on windows and query for the actual provider from the library if querying is supported
102+ // Assume SChannel is being used on windows and query for the actual provider from the library
97103 QUIC_TLS_PROVIDER provider = OperatingSystem . IsWindows ( ) ? QUIC_TLS_PROVIDER . SCHANNEL : QUIC_TLS_PROVIDER . OPENSSL ;
98104 size = sizeof ( QUIC_TLS_PROVIDER ) ;
99105 apiTable ->GetParam ( null , QUIC_PARAM_GLOBAL_TLS_PROVIDER , & size , & provider ) ;
@@ -116,67 +122,26 @@ static MsQuicApi()
116122 Tls13ClientMayBeDisabled = IsTls13Disabled ( isServer : false ) ;
117123 }
118124
125+ Api = new MsQuicApi ( apiTable ) ;
119126 IsQuicSupported = true ;
120127 }
121128 finally
122129 {
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" ) ;
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+ }
126135 }
127- }
128- finally
129- {
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- if ( TryLoadMsQuic ( out IntPtr msQuicHandle ) &&
140- TryOpenMsQuic ( msQuicHandle , out QUIC_API_TABLE * apiTable ) )
141- {
142- return new MsQuicApi ( apiTable ) ;
143- }
144-
145- throw new Exception ( "Failed to create MsQuicApi instance" ) ;
146- }
147136
148- private static bool TryLoadMsQuic ( out IntPtr msQuicHandle ) =>
149- NativeLibrary . TryLoad ( $ "{ Interop . Libraries . MsQuic } .{ MsQuicVersion . Major } ", typeof ( MsQuicApi ) . Assembly , DllImportSearchPath . AssemblyDirectory , out msQuicHandle ) ||
150- NativeLibrary . TryLoad ( Interop . Libraries . MsQuic , typeof ( MsQuicApi ) . Assembly , DllImportSearchPath . AssemblyDirectory , out msQuicHandle ) ;
151-
152- private static bool TryOpenMsQuic ( IntPtr msQuicHandle , out QUIC_API_TABLE * apiTable )
153- {
154- apiTable = null ;
155- if ( ! NativeLibrary . TryGetExport ( msQuicHandle , "MsQuicOpenVersion" , out IntPtr msQuicOpenVersionAddress ) )
156- {
157- return false ;
158137 }
159-
160- QUIC_API_TABLE * table = null ;
161- delegate * unmanaged[ Cdecl] < uint , QUIC_API_TABLE * * , int > msQuicOpenVersion = ( delegate * unmanaged[ Cdecl] < uint , QUIC_API_TABLE * * , int > ) msQuicOpenVersionAddress ;
162- if ( StatusFailed ( msQuicOpenVersion ( ( uint ) MsQuicVersion . Major , & table ) ) )
163- {
164- return false ;
165- }
166-
167- apiTable = table ;
168- return true ;
169- }
170-
171- private static bool TryCloseMsQuic ( IntPtr msQuicHandle , QUIC_API_TABLE * apiTable )
172- {
173- if ( NativeLibrary . TryGetExport ( msQuicHandle , "MsQuicClose" , out IntPtr msQuicClose ) )
138+ finally
174139 {
175- ( ( delegate * unmanaged[ Cdecl] < QUIC_API_TABLE * , void > ) msQuicClose ) ( apiTable ) ;
176- return true ;
140+ if ( ! IsQuicSupported )
141+ {
142+ NativeLibrary . Free ( msQuicHandle ) ;
143+ }
177144 }
178-
179- return false ;
180145 }
181146
182147 private static bool IsWindowsVersionSupported ( ) => OperatingSystem . IsWindowsVersionAtLeast ( MinWindowsVersion . Major ,
0 commit comments