static MsQuicApi() { // TODO: Consider updating all of these delegates to instead use function pointers. if (NativeLibrary.TryLoad(Interop.Libraries.MsQuic, out IntPtr msQuicHandle)) { try { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpen", out IntPtr msQuicOpenAddress)) { MsQuicOpenDelegate msQuicOpen = Marshal.GetDelegateForFunctionPointer <MsQuicOpenDelegate>(msQuicOpenAddress); uint status = msQuicOpen(out NativeApi * vtable); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { IsQuicSupported = true; Api = new MsQuicApi(vtable); } } } finally { if (!IsQuicSupported) { NativeLibrary.Free(msQuicHandle); } } } }
static MsQuicApi() { // MsQuicOpen will succeed even if the platform will not support it. It will then fail with unspecified // platform-specific errors in subsequent callbacks. For now, check for the minimum build we've tested it on. // TODO: // - Hopefully, MsQuicOpen will perform this check for us and give us a consistent error code. // - Otherwise, dial this in to reflect actual minimum requirements and add some sort of platform // error code mapping when creating exceptions. // OperatingSystem ver = Environment.OSVersion; // if (ver.Platform == PlatformID.Win32NT && ver.Version < new Version(10, 0, 19041, 0)) // { // IsQuicSupported = false; // return; // } // TODO: try to initialize TLS 1.3 in SslStream. try { Api = new MsQuicApi(); IsQuicSupported = true; } catch (NotSupportedException) { IsQuicSupported = false; } }
internal static unsafe void SetULongParam(MsQuicApi api, MsQuicSafeHandle nativeObject, uint param, ulong value) { ThrowIfFailure(api.ApiTable->SetParam( nativeObject.QuicHandle, param, sizeof(ulong), (byte *)&value), "Could not set ulong"); }
internal static unsafe void SetSecurityConfig(MsQuicApi api, IntPtr nativeObject, uint level, uint param, IntPtr value) { QuicBuffer buffer = new QuicBuffer() { Length = (uint)sizeof(void *), Buffer = (byte *)&value }; MsQuicStatusException.ThrowIfFailed(api.UnsafeSetParam(nativeObject, level, param, buffer)); }
internal static unsafe void SetULongParam(MsQuicApi api, IntPtr nativeObject, uint level, uint param, ulong value) { QuicBuffer buffer = new QuicBuffer() { Length = sizeof(ulong), Buffer = (byte *)&value }; MsQuicStatusException.ThrowIfFailed(api.UnsafeGetParam(nativeObject, level, param, ref buffer)); }
internal static unsafe ulong GetULongParam(MsQuicApi api, IntPtr nativeObject, uint level, uint param) { byte * ptr = stackalloc byte[sizeof(ulong)]; QuicBuffer buffer = new QuicBuffer() { Length = sizeof(ulong), Buffer = ptr }; MsQuicStatusException.ThrowIfFailed(api.UnsafeGetParam(nativeObject, level, param, ref buffer)); return(*(ulong *)ptr); }
internal static unsafe ulong GetULongParam(MsQuicApi api, SafeHandle nativeObject, uint param) { ulong value; uint valueLen = (uint)sizeof(ulong); uint status = api.GetParamDelegate(nativeObject, param, ref valueLen, (byte *)&value); QuicExceptionHelpers.ThrowIfFailed(status, "GetULongParam failed."); Debug.Assert(valueLen == sizeof(ulong)); return(value); }
internal static unsafe void SetSecurityConfig(MsQuicApi api, IntPtr nativeObject, uint level, uint param, IntPtr value) { QuicBuffer buffer = new QuicBuffer() { Length = (uint)sizeof(void *), Buffer = (byte *)&value }; QuicExceptionHelpers.ThrowIfFailed( api.UnsafeSetParam(nativeObject, level, param, buffer), "Could not set security configuration."); }
internal static unsafe void SetUshortParam(MsQuicApi api, IntPtr nativeObject, uint level, uint param, ushort value) { QuicBuffer buffer = new QuicBuffer() { Length = sizeof(ushort), Buffer = (byte *)&value }; QuicExceptionHelpers.ThrowIfFailed( api.UnsafeSetParam(nativeObject, level, param, buffer), "Could not set ushort."); }
internal static unsafe ushort GetUShortParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param) { ushort value; uint valueLen = (uint)sizeof(ushort); uint status = api.GetParamDelegate(nativeObject, level, param, ref valueLen, (byte *)&value); QuicExceptionHelpers.ThrowIfFailed(status, "GetUShortParam failed."); Debug.Assert(valueLen == sizeof(ushort)); return(value); }
internal static unsafe SOCKADDR_INET GetINetParam(MsQuicApi api, IntPtr nativeObject, uint level, uint param) { byte * ptr = stackalloc byte[sizeof(SOCKADDR_INET)]; QuicBuffer buffer = new QuicBuffer { Length = (uint)sizeof(SOCKADDR_INET), Buffer = ptr }; MsQuicStatusException.ThrowIfFailed(api.UnsafeGetParam(nativeObject, level, param, ref buffer)); return(*(SOCKADDR_INET *)ptr); }
internal static unsafe ulong GetULongParam(MsQuicApi api, MsQuicSafeHandle nativeObject, uint param) { ulong value; uint valueLen = (uint)sizeof(ulong); ThrowIfFailure(api.ApiTable->GetParam( nativeObject.QuicHandle, param, &valueLen, (byte *)&value), "GetULongParam failed"); Debug.Assert(valueLen == sizeof(ulong)); return(value); }
internal static unsafe ushort GetUShortParam(MsQuicApi api, IntPtr nativeObject, uint level, uint param) { byte * ptr = stackalloc byte[sizeof(ushort)]; QuicBuffer buffer = new QuicBuffer() { Length = sizeof(ushort), Buffer = ptr }; QuicExceptionHelpers.ThrowIfFailed( api.UnsafeGetParam(nativeObject, level, param, ref buffer), "Could not get ushort."); return(*(ushort *)ptr); }
static MsQuicApi() { if (!IsHttp3Enabled()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"HTTP/3 and QUIC is not enabled, see 'System.Net.SocketsHttpHandler.Http3Support' AppContext switch."); } return; } if (OperatingSystem.IsWindows() && !IsWindowsVersionSupported()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); } return; } if (NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out IntPtr msQuicHandle)) { try { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) { delegate * unmanaged[Cdecl] < uint, out NativeApi *, uint > msQuicOpenVersion = (delegate * unmanaged[Cdecl] < uint, out NativeApi *, uint >)msQuicOpenVersionAddress; uint status = msQuicOpenVersion(MsQuicVersion, out NativeApi * vtable); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { IsQuicSupported = true; Api = new MsQuicApi(vtable); } } } finally { if (!IsQuicSupported) { NativeLibrary.Free(msQuicHandle); } } } }
static MsQuicApi() { if (OperatingSystem.IsWindows()) { if (!IsWindowsVersionSupported()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); } return; } Tls13MayBeDisabled = IsTls13Disabled(); } IntPtr msQuicHandle; if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) || NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle)) { try { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) { NativeApi *vtable; delegate * unmanaged[Cdecl] < uint, NativeApi **, uint > msQuicOpenVersion = (delegate * unmanaged[Cdecl] < uint, NativeApi **, uint >)msQuicOpenVersionAddress; uint status = msQuicOpenVersion(MsQuicVersion, &vtable); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { IsQuicSupported = true; Api = new MsQuicApi(vtable); } } } finally { if (!IsQuicSupported) { NativeLibrary.Free(msQuicHandle); } } } }
internal static unsafe void SetIPEndPointParam(MsQuicApi api, SafeHandle nativeObject, uint param, IPEndPoint value) { Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(value); // MsQuic always reads same amount of memory as if IPv6 was used, so we can't pass pointer to socketAddress.Buffer directly Span <byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize]; socketAddress.Buffer.AsSpan(0, socketAddress.Size).CopyTo(address); address.Slice(socketAddress.Size).Clear(); fixed(byte *paddress = &MemoryMarshal.GetReference(address)) { QuicExceptionHelpers.ThrowIfFailed( api.SetParamDelegate(nativeObject, param, (uint)address.Length, paddress), "Could not set IPEndPoint"); } }
internal static unsafe IPEndPoint GetIPEndPointParam(MsQuicApi api, SafeHandle nativeObject, uint param) { // MsQuic always uses storage size as if IPv6 was used uint valueLen = (uint)Internals.SocketAddress.IPv6AddressSize; Span <byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize]; fixed(byte *paddress = &MemoryMarshal.GetReference(address)) { uint status = api.GetParamDelegate(nativeObject, param, ref valueLen, paddress); QuicExceptionHelpers.ThrowIfFailed(status, "GetIPEndPointParam failed."); } address = address.Slice(0, (int)valueLen); return(new Internals.SocketAddress(SocketAddressPal.GetAddressFamily(address), address) .GetIPEndPoint()); }
internal static unsafe IPEndPoint GetIPEndPointParam(MsQuicApi api, MsQuicSafeHandle nativeObject, uint param) { // MsQuic always uses storage size as if IPv6 was used uint valueLen = (uint)Internals.SocketAddress.IPv6AddressSize; Span <byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize]; fixed(byte *paddress = &MemoryMarshal.GetReference(address)) { ThrowIfFailure(api.ApiTable->GetParam( nativeObject.QuicHandle, param, &valueLen, paddress), "GetIPEndPointParam failed."); } address = address.Slice(0, (int)valueLen); return(new Internals.SocketAddress(SocketAddressPal.GetAddressFamily(address), address).GetIPEndPoint()); }
static unsafe MsQuicApi() { // MsQuicOpen will succeed even if the platform will not support it. It will then fail with unspecified // platform-specific errors in subsequent callbacks. For now, check for the minimum build we've tested it on. // TODO: // - Hopefully, MsQuicOpen will perform this check for us and give us a consistent error code. // - Otherwise, dial this in to reflect actual minimum requirements and add some sort of platform // error code mapping when creating exceptions. // TODO: try to initialize TLS 1.3 in SslStream. // TODO: Consider updating all of these delegates to instead use function pointers. if (NativeLibrary.TryLoad(Interop.Libraries.MsQuic, out IntPtr msQuicHandle)) { try { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpen", out IntPtr msQuicOpenAddress)) { MsQuicNativeMethods.MsQuicOpenDelegate msQuicOpen = Marshal.GetDelegateForFunctionPointer <MsQuicNativeMethods.MsQuicOpenDelegate>(msQuicOpenAddress); uint status = msQuicOpen(out MsQuicNativeMethods.NativeApi * registration); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { IsQuicSupported = true; Api = new MsQuicApi(registration); } } } finally { if (!IsQuicSupported) { NativeLibrary.Free(msQuicHandle); } } } }
internal static unsafe void SetULongParam(MsQuicApi api, SafeHandle nativeObject, uint param, ulong value) { QuicExceptionHelpers.ThrowIfFailed( api.SetParamDelegate(nativeObject, param, sizeof(ulong), (byte *)&value), "Could not set ulong."); }
static MsQuicApi() { if (OperatingSystem.IsWindows()) { if (!IsWindowsVersionSupported()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); } return; } Tls13MayBeDisabled = IsTls13Disabled(); } 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)) { try { if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) { QUIC_API_TABLE *apiTable; delegate * unmanaged[Cdecl] < uint, QUIC_API_TABLE **, int > msQuicOpenVersion = (delegate * unmanaged[Cdecl] < uint, QUIC_API_TABLE **, int >)msQuicOpenVersionAddress; if (StatusSucceeded(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable))) { int arraySize = 4; uint *libVersion = stackalloc uint[arraySize]; uint size = (uint)arraySize * sizeof(uint); if (StatusSucceeded(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion))) { var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]); if (version >= MsQuicVersion) { Api = new MsQuicApi(apiTable); IsQuicSupported = true; } else { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'"); } } } } } } finally { if (!IsQuicSupported) { NativeLibrary.Free(msQuicHandle); } } } }
internal static unsafe void SetUShortParam(MsQuicApi api, SafeHandle nativeObject, QUIC_PARAM_LEVEL level, uint param, ushort value) { QuicExceptionHelpers.ThrowIfFailed( api.SetParamDelegate(nativeObject, level, param, sizeof(ushort), (byte *)&value), "Could not set ushort."); }