Initial port of MsQuic transport (#15375)
This commit is contained in:
parent
fece4705ee
commit
0e8fea6fee
|
|
@ -60,6 +60,7 @@
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Core" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Core\ref\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Core" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Core\ref\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Kestrel\ref\Microsoft.AspNetCore.Server.Kestrel.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Kestrel\ref\Microsoft.AspNetCore.Server.Kestrel.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Libuv\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" />
|
||||||
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.MsQuic\src\Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.MsQuic\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" ProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" RefProjectPath="$(RepoRoot)src\Servers\Kestrel\Transport.Sockets\ref\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Certificate" ProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\src\Microsoft.AspNetCore.Authentication.Certificate.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\ref\Microsoft.AspNetCore.Authentication.Certificate.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Certificate" ProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\src\Microsoft.AspNetCore.Authentication.Certificate.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Certificate\ref\Microsoft.AspNetCore.Authentication.Certificate.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Cookies" ProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\src\Microsoft.AspNetCore.Authentication.Cookies.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\ref\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Cookies" ProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\src\Microsoft.AspNetCore.Authentication.Cookies.csproj" RefProjectPath="$(RepoRoot)src\Security\Authentication\Cookies\ref\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebUti
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "samples\http2cat\http2cat.csproj", "{3D6821F5-F242-4828-8DDE-89488E85512D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "samples\http2cat\http2cat.csproj", "{3D6821F5-F242-4828-8DDE-89488E85512D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic", "Transport.MsQuic\src\Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.csproj", "{1BC94F37-AF61-4641-A80A-EC32A15C5344}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -466,6 +468,18 @@ Global
|
||||||
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x64.Build.0 = Release|Any CPU
|
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x86.ActiveCfg = Release|Any CPU
|
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x86.Build.0 = Release|Any CPU
|
{3D6821F5-F242-4828-8DDE-89488E85512D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -503,6 +517,7 @@ Global
|
||||||
{E0AD50A3-2518-4060-8BB9-5649B04B3A6D} = {F0A1281A-B512-49D2-8362-21EE32B3674F}
|
{E0AD50A3-2518-4060-8BB9-5649B04B3A6D} = {F0A1281A-B512-49D2-8362-21EE32B3674F}
|
||||||
{EE45763C-753D-4228-8E5D-A71F8BDB3D89} = {F0A1281A-B512-49D2-8362-21EE32B3674F}
|
{EE45763C-753D-4228-8E5D-A71F8BDB3D89} = {F0A1281A-B512-49D2-8362-21EE32B3674F}
|
||||||
{3D6821F5-F242-4828-8DDE-89488E85512D} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
|
{3D6821F5-F242-4828-8DDE-89488E85512D} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
|
||||||
|
{1BC94F37-AF61-4641-A80A-EC32A15C5344} = {2B456D08-F72B-4EB8-B663-B6D78FC04BF8}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {48207B50-7D05-4B10-B585-890FE0F4FCE1}
|
SolutionGuid = {48207B50-7D05-4B10-B585-890FE0F4FCE1}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
## Using MsQuic on Windows
|
||||||
|
|
||||||
|
### Setup pre-requisites
|
||||||
|
|
||||||
|
1. Update machine to the latest Windows Insiders build (build number 19010 or later). This is required for TLS 1.3 support.
|
||||||
|
2. Copy msquic.dll and msquic.pdb to this directory and uncomment the copy task in Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.csproj. This will copy the msquic.dll into any built project.
|
||||||
|
|
||||||
|
For external contributors, msquic.dll isn't available publicly yet. See https://github.com/aspnet/Announcements/issues/393.
|
||||||
|
|
||||||
|
Credit to Diwakar Mantha and the Kaizala team for the MsQuic interop code.
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- This file is automatically generated. -->
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
|
||||||
|
<Compile Include="Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.netcoreapp.cs" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Options" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
internal class MsQuicApi : IDisposable
|
||||||
|
{
|
||||||
|
private bool _disposed = false;
|
||||||
|
|
||||||
|
private IntPtr _registrationContext;
|
||||||
|
|
||||||
|
internal unsafe MsQuicApi()
|
||||||
|
{
|
||||||
|
var status = (uint)MsQuicNativeMethods.MsQuicOpen(version: 1, out var registration);
|
||||||
|
MsQuicStatusException.ThrowIfFailed(status);
|
||||||
|
|
||||||
|
NativeRegistration = *registration;
|
||||||
|
|
||||||
|
RegistrationOpenDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.RegistrationOpenDelegate>(
|
||||||
|
NativeRegistration.RegistrationOpen);
|
||||||
|
RegistrationCloseDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.RegistrationCloseDelegate>(
|
||||||
|
NativeRegistration.RegistrationClose);
|
||||||
|
|
||||||
|
SecConfigCreateDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SecConfigCreateDelegate>(
|
||||||
|
NativeRegistration.SecConfigCreate);
|
||||||
|
SecConfigDeleteDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SecConfigDeleteDelegate>(
|
||||||
|
NativeRegistration.SecConfigDelete);
|
||||||
|
|
||||||
|
SessionOpenDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SessionOpenDelegate>(
|
||||||
|
NativeRegistration.SessionOpen);
|
||||||
|
SessionCloseDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SessionCloseDelegate>(
|
||||||
|
NativeRegistration.SessionClose);
|
||||||
|
SessionShutdownDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SessionShutdownDelegate>(
|
||||||
|
NativeRegistration.SessionShutdown);
|
||||||
|
|
||||||
|
ListenerOpenDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ListenerOpenDelegate>(
|
||||||
|
NativeRegistration.ListenerOpen);
|
||||||
|
ListenerCloseDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ListenerCloseDelegate>(
|
||||||
|
NativeRegistration.ListenerClose);
|
||||||
|
ListenerStartDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ListenerStartDelegate>(
|
||||||
|
NativeRegistration.ListenerStart);
|
||||||
|
ListenerStopDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ListenerStopDelegate>(
|
||||||
|
NativeRegistration.ListenerStop);
|
||||||
|
|
||||||
|
ConnectionOpenDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ConnectionOpenDelegate>(
|
||||||
|
NativeRegistration.ConnectionOpen);
|
||||||
|
ConnectionCloseDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ConnectionCloseDelegate>(
|
||||||
|
NativeRegistration.ConnectionClose);
|
||||||
|
ConnectionShutdownDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ConnectionShutdownDelegate>(
|
||||||
|
NativeRegistration.ConnectionShutdown);
|
||||||
|
ConnectionStartDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.ConnectionStartDelegate>(
|
||||||
|
NativeRegistration.ConnectionStart);
|
||||||
|
|
||||||
|
StreamOpenDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.StreamOpenDelegate>(
|
||||||
|
NativeRegistration.StreamOpen);
|
||||||
|
StreamCloseDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.StreamCloseDelegate>(
|
||||||
|
NativeRegistration.StreamClose);
|
||||||
|
StreamStartDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.StreamStartDelegate>(
|
||||||
|
NativeRegistration.StreamStart);
|
||||||
|
StreamShutdownDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.StreamShutdownDelegate>(
|
||||||
|
NativeRegistration.StreamShutdown);
|
||||||
|
StreamSendDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.StreamSendDelegate>(
|
||||||
|
NativeRegistration.StreamSend);
|
||||||
|
|
||||||
|
SetContextDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SetContextDelegate>(
|
||||||
|
NativeRegistration.SetContext);
|
||||||
|
GetContextDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.GetContextDelegate>(
|
||||||
|
NativeRegistration.GetContext);
|
||||||
|
SetCallbackHandlerDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SetCallbackHandlerDelegate>(
|
||||||
|
NativeRegistration.SetCallbackHandler);
|
||||||
|
|
||||||
|
SetParamDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.SetParamDelegate>(
|
||||||
|
NativeRegistration.SetParam);
|
||||||
|
GetParamDelegate =
|
||||||
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.GetParamDelegate>(
|
||||||
|
NativeRegistration.GetParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.NativeApi NativeRegistration { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.RegistrationOpenDelegate RegistrationOpenDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.RegistrationCloseDelegate RegistrationCloseDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.SecConfigCreateDelegate SecConfigCreateDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.SecConfigCreateCompleteDelegate SecConfigCreateCompleteDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.SecConfigDeleteDelegate SecConfigDeleteDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.SessionOpenDelegate SessionOpenDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.SessionCloseDelegate SessionCloseDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.SessionShutdownDelegate SessionShutdownDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.ListenerOpenDelegate ListenerOpenDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ListenerCloseDelegate ListenerCloseDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ListenerStartDelegate ListenerStartDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ListenerStopDelegate ListenerStopDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.ConnectionOpenDelegate ConnectionOpenDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ConnectionCloseDelegate ConnectionCloseDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ConnectionShutdownDelegate ConnectionShutdownDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.ConnectionStartDelegate ConnectionStartDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.StreamOpenDelegate StreamOpenDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.StreamCloseDelegate StreamCloseDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.StreamStartDelegate StreamStartDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.StreamShutdownDelegate StreamShutdownDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.StreamSendDelegate StreamSendDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.StreamReceiveCompleteDelegate StreamReceiveComplete { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.SetContextDelegate SetContextDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.GetContextDelegate GetContextDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.SetCallbackHandlerDelegate SetCallbackHandlerDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal MsQuicNativeMethods.SetParamDelegate SetParamDelegate { get; private set; }
|
||||||
|
internal MsQuicNativeMethods.GetParamDelegate GetParamDelegate { get; private set; }
|
||||||
|
|
||||||
|
internal void RegistrationOpen(byte[] name)
|
||||||
|
{
|
||||||
|
MsQuicStatusException.ThrowIfFailed(RegistrationOpenDelegate(name, out var ctx));
|
||||||
|
_registrationContext = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe uint UnsafeSetParam(
|
||||||
|
IntPtr Handle,
|
||||||
|
uint Level,
|
||||||
|
uint Param,
|
||||||
|
MsQuicNativeMethods.QuicBuffer Buffer)
|
||||||
|
{
|
||||||
|
return SetParamDelegate(
|
||||||
|
Handle,
|
||||||
|
Level,
|
||||||
|
Param,
|
||||||
|
Buffer.Length,
|
||||||
|
Buffer.Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~MsQuicApi()
|
||||||
|
{
|
||||||
|
Dispose(disposing: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegistrationCloseDelegate?.Invoke(_registrationContext);
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
internal static class MsQuicConstants
|
||||||
|
{
|
||||||
|
private const uint Success = 0;
|
||||||
|
|
||||||
|
internal static Func<uint, string> ErrorTypeFromErrorCode = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Windows.GetError : (Func<uint, string>)Linux.GetError;
|
||||||
|
|
||||||
|
internal static class Windows
|
||||||
|
{
|
||||||
|
internal const uint Pending = 0x703E5;
|
||||||
|
internal const uint Continue = 0x704DE;
|
||||||
|
internal const uint OutOfMemory = 0x8007000E;
|
||||||
|
internal const uint InvalidParameter = 0x80070057;
|
||||||
|
internal const uint InvalidState = 0x8007139F;
|
||||||
|
internal const uint NotSupported = 0x80004002;
|
||||||
|
internal const uint NotFound = 0x80070490;
|
||||||
|
internal const uint BufferTooSmall = 0x8007007A;
|
||||||
|
internal const uint HandshakeFailure = 0x80410000;
|
||||||
|
internal const uint Aborted = 0x80004004;
|
||||||
|
internal const uint AddressInUse = 0x80072740;
|
||||||
|
internal const uint ConnectionTimeout = 0x800704CF;
|
||||||
|
internal const uint ConnectionIdle = 0x800704D4;
|
||||||
|
internal const uint InternalError = 0x80004005;
|
||||||
|
internal const uint ServerBusy = 0x800704C9;
|
||||||
|
internal const uint ProtocolError = 0x800704CD;
|
||||||
|
internal const uint VerNegError = 0x80410001;
|
||||||
|
|
||||||
|
// TODO return better error messages here.
|
||||||
|
public static string GetError(uint status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case Success:
|
||||||
|
return "SUCCESS";
|
||||||
|
case Pending:
|
||||||
|
return "PENDING";
|
||||||
|
case Continue:
|
||||||
|
return "CONTINUE";
|
||||||
|
case OutOfMemory:
|
||||||
|
return "OUT_OF_MEMORY";
|
||||||
|
case InvalidParameter:
|
||||||
|
return "INVALID_PARAMETER";
|
||||||
|
case InvalidState:
|
||||||
|
return "INVALID_STATE";
|
||||||
|
case NotSupported:
|
||||||
|
return "NOT_SUPPORTED";
|
||||||
|
case NotFound:
|
||||||
|
return "NOT_FOUND";
|
||||||
|
case BufferTooSmall:
|
||||||
|
return "BUFFER_TOO_SMALL";
|
||||||
|
case HandshakeFailure:
|
||||||
|
return "HANDSHAKE_FAILURE";
|
||||||
|
case Aborted:
|
||||||
|
return "ABORTED";
|
||||||
|
case AddressInUse:
|
||||||
|
return "ADDRESS_IN_USE";
|
||||||
|
case ConnectionTimeout:
|
||||||
|
return "CONNECTION_TIMEOUT";
|
||||||
|
case ConnectionIdle:
|
||||||
|
return "CONNECTION_IDLE";
|
||||||
|
case InternalError:
|
||||||
|
return "INTERNAL_ERROR";
|
||||||
|
case ServerBusy:
|
||||||
|
return "SERVER_BUSY";
|
||||||
|
case ProtocolError:
|
||||||
|
return "PROTOCOL_ERROR";
|
||||||
|
case VerNegError:
|
||||||
|
return "VER_NEG_ERROR";
|
||||||
|
}
|
||||||
|
return status.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class Linux
|
||||||
|
{
|
||||||
|
internal const uint Pending = unchecked((uint)-2);
|
||||||
|
internal const uint Continue = unchecked((uint)-1);
|
||||||
|
internal const uint OutOfMemory = 12;
|
||||||
|
internal const uint InvalidParameter = 22;
|
||||||
|
internal const uint InvalidState = 200000002;
|
||||||
|
internal const uint NotSupported = 95;
|
||||||
|
internal const uint NotFound = 2;
|
||||||
|
internal const uint BufferTooSmall = 75;
|
||||||
|
internal const uint HandshakeFailure = 200000009;
|
||||||
|
internal const uint Aborted = 200000008;
|
||||||
|
internal const uint AddressInUse = 98;
|
||||||
|
internal const uint ConnectionTimeout = 110;
|
||||||
|
internal const uint ConnectionIdle = 200000011;
|
||||||
|
internal const uint InternalError = 200000012;
|
||||||
|
internal const uint ServerBusy = 200000007;
|
||||||
|
internal const uint ProtocolError = 200000013;
|
||||||
|
internal const uint VerNegError = 200000014;
|
||||||
|
|
||||||
|
|
||||||
|
public static string GetError(uint status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case Success:
|
||||||
|
return "SUCCESS";
|
||||||
|
case Pending:
|
||||||
|
return "PENDING";
|
||||||
|
case Continue:
|
||||||
|
return "CONTINUE";
|
||||||
|
case OutOfMemory:
|
||||||
|
return "OUT_OF_MEMORY";
|
||||||
|
case InvalidParameter:
|
||||||
|
return "INVALID_PARAMETER";
|
||||||
|
case InvalidState:
|
||||||
|
return "INVALID_STATE";
|
||||||
|
case NotSupported:
|
||||||
|
return "NOT_SUPPORTED";
|
||||||
|
case NotFound:
|
||||||
|
return "NOT_FOUND";
|
||||||
|
case BufferTooSmall:
|
||||||
|
return "BUFFER_TOO_SMALL";
|
||||||
|
case HandshakeFailure:
|
||||||
|
return "HANDSHAKE_FAILURE";
|
||||||
|
case Aborted:
|
||||||
|
return "ABORTED";
|
||||||
|
case AddressInUse:
|
||||||
|
return "ADDRESS_IN_USE";
|
||||||
|
case ConnectionTimeout:
|
||||||
|
return "CONNECTION_TIMEOUT";
|
||||||
|
case ConnectionIdle:
|
||||||
|
return "CONNECTION_IDLE";
|
||||||
|
case InternalError:
|
||||||
|
return "INTERNAL_ERROR";
|
||||||
|
case ServerBusy:
|
||||||
|
return "SERVER_BUSY";
|
||||||
|
case ProtocolError:
|
||||||
|
return "PROTOCOL_ERROR";
|
||||||
|
case VerNegError:
|
||||||
|
return "VER_NEG_ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
return status.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Flags to pass when creating a certificate hash store.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_CERT_HASH_STORE_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
MACHINE_CERT = 0x0001,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flags to pass when creating a security config.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_SEC_CONFIG_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
CERT_HASH = 0x00000001,
|
||||||
|
CERT_HASH_STORE = 0x00000002,
|
||||||
|
CERT_CONTEXT = 0x00000004,
|
||||||
|
CERT_FILE = 0x00000008,
|
||||||
|
ENABL_OCSP = 0x00000010,
|
||||||
|
CERT_NULL = 0xF0000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_LISTENER_EVENT : byte
|
||||||
|
{
|
||||||
|
NEW_CONNECTION = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_CONNECTION_EVENT : byte
|
||||||
|
{
|
||||||
|
CONNECTED = 0,
|
||||||
|
SHUTDOWN_BEGIN = 1,
|
||||||
|
SHUTDOWN_BEGIN_PEER = 2,
|
||||||
|
SHUTDOWN_COMPLETE = 3,
|
||||||
|
LOCAL_ADDR_CHANGED = 4,
|
||||||
|
PEER_ADDR_CHANGED = 5,
|
||||||
|
NEW_STREAM = 6,
|
||||||
|
STREAMS_AVAILABLE = 7,
|
||||||
|
PEER_NEEDS_STREAMS = 8,
|
||||||
|
IDEAL_SEND_BUFFER = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_CONNECTION_SHUTDOWN_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0x0,
|
||||||
|
SILENT = 0x1
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_LEVEL : uint
|
||||||
|
{
|
||||||
|
REGISTRATION = 0,
|
||||||
|
SESSION = 1,
|
||||||
|
LISTENER = 2,
|
||||||
|
CONNECTION = 3,
|
||||||
|
TLS = 4,
|
||||||
|
STREAM = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_REGISTRATION : uint
|
||||||
|
{
|
||||||
|
RETRY_MEMORY_PERCENT = 0,
|
||||||
|
CID_PREFIX = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_SESSION : uint
|
||||||
|
{
|
||||||
|
TLS_TICKET_KEY = 0,
|
||||||
|
PEER_BIDI_STREAM_COUNT = 1,
|
||||||
|
PEER_UNIDI_STREAM_COUNT = 2,
|
||||||
|
IDLE_TIMEOUT = 3,
|
||||||
|
DISCONNECT_TIMEOUT = 4,
|
||||||
|
MAX_BYTES_PER_KEY = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_LISTENER : uint
|
||||||
|
{
|
||||||
|
LOCAL_ADDRESS = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_CONN : uint
|
||||||
|
{
|
||||||
|
QUIC_VERSION = 0,
|
||||||
|
LOCAL_ADDRESS = 1,
|
||||||
|
REMOTE_ADDRESS = 2,
|
||||||
|
IDLE_TIMEOUT = 3,
|
||||||
|
PEER_BIDI_STREAM_COUNT = 4,
|
||||||
|
PEER_UNIDI_STREAM_COUNT = 5,
|
||||||
|
LOCAL_BIDI_STREAM_COUNT = 6,
|
||||||
|
LOCAL_UNIDI_STREAM_COUNT = 7,
|
||||||
|
CLOSE_REASON_PHRASE = 8,
|
||||||
|
STATISTICS = 9,
|
||||||
|
STATISTICS_PLAT = 10,
|
||||||
|
CERT_VALIDATION_FLAGS = 11,
|
||||||
|
KEEP_ALIVE_ENABLED = 12,
|
||||||
|
DISCONNECT_TIMEOUT = 13,
|
||||||
|
SEC_CONFIG = 14,
|
||||||
|
USE_SEND_BUFFER = 15,
|
||||||
|
USE_PACING = 16,
|
||||||
|
SHARE_UDP_BINDING = 17,
|
||||||
|
IDEAL_PROCESSOR = 18,
|
||||||
|
MAX_STREAM_IDS = 19
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_STREAM : uint
|
||||||
|
{
|
||||||
|
ID = 0,
|
||||||
|
RECEIVE_ENABLED = 1,
|
||||||
|
ZERORTT_LENGTH = 2,
|
||||||
|
IDEAL_SEND_BUFFER = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_STREAM_EVENT : byte
|
||||||
|
{
|
||||||
|
START_COMPLETE = 0,
|
||||||
|
RECV = 1,
|
||||||
|
SEND_COMPLETE = 2,
|
||||||
|
PEER_SEND_CLOSE = 3,
|
||||||
|
PEER_SEND_ABORT = 4,
|
||||||
|
PEER_RECV_ABORT = 5,
|
||||||
|
SEND_SHUTDOWN_COMPLETE = 6,
|
||||||
|
SHUTDOWN_COMPLETE = 7,
|
||||||
|
IDEAL_SEND_BUFFER_SIZE = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_STREAM_OPEN_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
UNIDIRECTIONAL = 0x1,
|
||||||
|
ZERO_RTT = 0x2,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_STREAM_START_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
FAIL_BLOCKED = 0x1,
|
||||||
|
IMMEDIATE = 0x2,
|
||||||
|
ASYNC = 0x4,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_STREAM_SHUTDOWN_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
GRACEFUL = 0x1,
|
||||||
|
ABORT_SEND = 0x2,
|
||||||
|
ABORT_RECV = 0x4,
|
||||||
|
ABORT = 0x6,
|
||||||
|
IMMEDIATE = 0x8
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_SEND_FLAG : uint
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
ALLOW_0_RTT = 0x00000001,
|
||||||
|
FIN = 0x00000002,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum QUIC_RECV_FLAG : byte
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
ZERO_RTT = 0x1,
|
||||||
|
FIN = 0x02
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,540 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains all native delegates and structs that are used with MsQuic.
|
||||||
|
/// </summary>
|
||||||
|
internal unsafe static class MsQuicNativeMethods
|
||||||
|
{
|
||||||
|
internal const string dllName = "msquic.dll";
|
||||||
|
|
||||||
|
[DllImport(dllName)]
|
||||||
|
internal static extern int MsQuicOpen(int version, out NativeApi* registration);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct NativeApi
|
||||||
|
{
|
||||||
|
internal uint Version;
|
||||||
|
|
||||||
|
internal IntPtr SetContext;
|
||||||
|
internal IntPtr GetContext;
|
||||||
|
internal IntPtr SetCallbackHandler;
|
||||||
|
|
||||||
|
internal IntPtr SetParam;
|
||||||
|
internal IntPtr GetParam;
|
||||||
|
|
||||||
|
internal IntPtr RegistrationOpen;
|
||||||
|
internal IntPtr RegistrationClose;
|
||||||
|
|
||||||
|
internal IntPtr SecConfigCreate;
|
||||||
|
internal IntPtr SecConfigDelete;
|
||||||
|
|
||||||
|
internal IntPtr SessionOpen;
|
||||||
|
internal IntPtr SessionClose;
|
||||||
|
internal IntPtr SessionShutdown;
|
||||||
|
|
||||||
|
internal IntPtr ListenerOpen;
|
||||||
|
internal IntPtr ListenerClose;
|
||||||
|
internal IntPtr ListenerStart;
|
||||||
|
internal IntPtr ListenerStop;
|
||||||
|
|
||||||
|
internal IntPtr ConnectionOpen;
|
||||||
|
internal IntPtr ConnectionClose;
|
||||||
|
internal IntPtr ConnectionShutdown;
|
||||||
|
internal IntPtr ConnectionStart;
|
||||||
|
|
||||||
|
internal IntPtr StreamOpen;
|
||||||
|
internal IntPtr StreamClose;
|
||||||
|
internal IntPtr StreamStart;
|
||||||
|
internal IntPtr StreamShutdown;
|
||||||
|
internal IntPtr StreamSend;
|
||||||
|
internal IntPtr StreamReceiveComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate uint SetContextDelegate(
|
||||||
|
IntPtr Handle,
|
||||||
|
IntPtr Context);
|
||||||
|
|
||||||
|
internal delegate IntPtr GetContextDelegate(
|
||||||
|
IntPtr Handle);
|
||||||
|
|
||||||
|
internal delegate void SetCallbackHandlerDelegate(
|
||||||
|
IntPtr Handle,
|
||||||
|
IntPtr Handler,
|
||||||
|
IntPtr Context);
|
||||||
|
|
||||||
|
internal delegate uint SetParamDelegate(
|
||||||
|
IntPtr Handle,
|
||||||
|
uint Level,
|
||||||
|
uint Param,
|
||||||
|
uint BufferLength,
|
||||||
|
byte* Buffer);
|
||||||
|
|
||||||
|
internal delegate uint GetParamDelegate(
|
||||||
|
IntPtr Handle,
|
||||||
|
uint Level,
|
||||||
|
uint Param,
|
||||||
|
IntPtr BufferLength,
|
||||||
|
IntPtr Buffer);
|
||||||
|
|
||||||
|
internal delegate uint RegistrationOpenDelegate(byte[] appName, out IntPtr RegistrationContext);
|
||||||
|
|
||||||
|
internal delegate void RegistrationCloseDelegate(IntPtr RegistrationContext);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct CertHash
|
||||||
|
{
|
||||||
|
internal const int ShaHashLength = 20;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = ShaHashLength)]
|
||||||
|
internal byte[] ShaHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct CertHashStore
|
||||||
|
{
|
||||||
|
internal const int ShaHashLength = 20;
|
||||||
|
internal const int StoreNameLength = 128;
|
||||||
|
|
||||||
|
internal uint Flags;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = ShaHashLength)]
|
||||||
|
internal byte[] ShaHash;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = StoreNameLength)]
|
||||||
|
internal byte[] StoreName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct CertFile
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray)]
|
||||||
|
internal byte[] ShaHashUtf8;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray)]
|
||||||
|
internal byte[] StoreNameUtf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate void SecConfigCreateCompleteDelegate(IntPtr Context, uint Status, IntPtr SecurityConfig);
|
||||||
|
|
||||||
|
internal delegate uint SecConfigCreateDelegate(
|
||||||
|
IntPtr RegistrationContext,
|
||||||
|
uint Flags,
|
||||||
|
IntPtr Certificate,
|
||||||
|
[MarshalAs(UnmanagedType.LPStr)]string Principal,
|
||||||
|
IntPtr Context,
|
||||||
|
SecConfigCreateCompleteDelegate CompletionHandler);
|
||||||
|
|
||||||
|
internal delegate void SecConfigDeleteDelegate(
|
||||||
|
IntPtr SecurityConfig);
|
||||||
|
|
||||||
|
internal delegate uint SessionOpenDelegate(
|
||||||
|
IntPtr RegistrationContext,
|
||||||
|
byte[] utf8String,
|
||||||
|
IntPtr Context,
|
||||||
|
ref IntPtr Session);
|
||||||
|
|
||||||
|
internal delegate void SessionCloseDelegate(
|
||||||
|
IntPtr Session);
|
||||||
|
|
||||||
|
internal delegate void SessionShutdownDelegate(
|
||||||
|
IntPtr Session,
|
||||||
|
uint Flags,
|
||||||
|
ushort ErrorCode);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ListenerEvent
|
||||||
|
{
|
||||||
|
internal QUIC_LISTENER_EVENT Type;
|
||||||
|
internal ListenerEventDataUnion Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
internal struct ListenerEventDataUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ListenerEventDataNewConnection NewConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ListenerEventDataNewConnection
|
||||||
|
{
|
||||||
|
internal IntPtr Info;
|
||||||
|
internal IntPtr Connection;
|
||||||
|
internal IntPtr SecurityConfig;
|
||||||
|
|
||||||
|
internal static string BufferToString(IntPtr buffer, ushort bufferLength)
|
||||||
|
{
|
||||||
|
if (bufferLength == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var utf8Bytes = new byte[bufferLength]; // TODO: Avoid extra alloc and copy.
|
||||||
|
Marshal.Copy(buffer, utf8Bytes, 0, bufferLength);
|
||||||
|
var str = Encoding.UTF8.GetString(utf8Bytes);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct NewConnectionInfo
|
||||||
|
{
|
||||||
|
internal uint QuicVersion;
|
||||||
|
internal IntPtr LocalAddress;
|
||||||
|
internal IntPtr RemoteAddress;
|
||||||
|
internal ushort CryptoBufferLength;
|
||||||
|
internal ushort AlpnListLength;
|
||||||
|
internal ushort ServerNameLength;
|
||||||
|
internal IntPtr CryptoBuffer;
|
||||||
|
internal IntPtr AlpnList;
|
||||||
|
internal IntPtr ServerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate uint ListenerCallbackDelegate(
|
||||||
|
IntPtr listener,
|
||||||
|
IntPtr context,
|
||||||
|
ref ListenerEvent evt);
|
||||||
|
|
||||||
|
internal delegate uint ListenerOpenDelegate(
|
||||||
|
IntPtr session,
|
||||||
|
ListenerCallbackDelegate handler,
|
||||||
|
IntPtr context,
|
||||||
|
out IntPtr listener);
|
||||||
|
|
||||||
|
internal delegate uint ListenerCloseDelegate(
|
||||||
|
IntPtr listener);
|
||||||
|
|
||||||
|
internal delegate uint ListenerStartDelegate(
|
||||||
|
IntPtr listener,
|
||||||
|
ref SOCKADDR_INET localAddress);
|
||||||
|
|
||||||
|
internal delegate uint ListenerStopDelegate(
|
||||||
|
IntPtr listener);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataConnected
|
||||||
|
{
|
||||||
|
internal bool EarlyDataAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataShutdownBegin
|
||||||
|
{
|
||||||
|
internal uint Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataShutdownBeginPeer
|
||||||
|
{
|
||||||
|
internal ushort ErrorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataShutdownComplete
|
||||||
|
{
|
||||||
|
internal bool TimedOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataLocalAddrChanged
|
||||||
|
{
|
||||||
|
internal IntPtr Address; // TODO this needs to be IPV4 and IPV6
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataPeerAddrChanged
|
||||||
|
{
|
||||||
|
internal IntPtr Address; // TODO this needs to be IPV4 and IPV6
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataNewStream
|
||||||
|
{
|
||||||
|
internal IntPtr Stream;
|
||||||
|
internal QUIC_STREAM_OPEN_FLAG Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataStreamsAvailable
|
||||||
|
{
|
||||||
|
internal ushort BiDirectionalCount;
|
||||||
|
internal ushort UniDirectionalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEventDataIdealSendBuffer
|
||||||
|
{
|
||||||
|
internal ulong NumBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
internal struct ConnectionEventDataUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataConnected Connected;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataShutdownBegin ShutdownBegin;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataShutdownBeginPeer ShutdownBeginPeer;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataShutdownComplete ShutdownComplete;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataLocalAddrChanged LocalAddrChanged;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataPeerAddrChanged PeerAddrChanged;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataNewStream NewStream;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataStreamsAvailable StreamsAvailable;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ConnectionEventDataIdealSendBuffer IdealSendBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct ConnectionEvent
|
||||||
|
{
|
||||||
|
internal QUIC_CONNECTION_EVENT Type;
|
||||||
|
internal ConnectionEventDataUnion Data;
|
||||||
|
|
||||||
|
internal bool EarlyDataAccepted => Data.Connected.EarlyDataAccepted;
|
||||||
|
internal ulong NumBytes => Data.IdealSendBuffer.NumBytes;
|
||||||
|
internal IPEndPoint LocalAddress => null; // TODO
|
||||||
|
internal IPEndPoint PeerAddress => null; // TODO
|
||||||
|
internal uint ShutdownBeginStatus => Data.ShutdownBegin.Status;
|
||||||
|
internal ushort ShutdownBeginPeerStatus => Data.ShutdownBeginPeer.ErrorCode;
|
||||||
|
internal bool ShutdownTimedOut => Data.ShutdownComplete.TimedOut;
|
||||||
|
internal ushort BiDirectionalCount => Data.StreamsAvailable.BiDirectionalCount;
|
||||||
|
internal ushort UniDirectionalCount => Data.StreamsAvailable.UniDirectionalCount;
|
||||||
|
internal QUIC_STREAM_OPEN_FLAG StreamFlags => Data.NewStream.Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate uint ConnectionCallbackDelegate(
|
||||||
|
IntPtr Connection,
|
||||||
|
IntPtr Context,
|
||||||
|
ref ConnectionEvent Event);
|
||||||
|
|
||||||
|
internal delegate uint ConnectionOpenDelegate(
|
||||||
|
IntPtr Session,
|
||||||
|
ConnectionCallbackDelegate Handler,
|
||||||
|
IntPtr Context,
|
||||||
|
out IntPtr Connection);
|
||||||
|
|
||||||
|
internal delegate uint ConnectionCloseDelegate(
|
||||||
|
IntPtr Connection);
|
||||||
|
|
||||||
|
internal delegate uint ConnectionStartDelegate(
|
||||||
|
IntPtr Connection,
|
||||||
|
ushort Family,
|
||||||
|
[MarshalAs(UnmanagedType.LPStr)]
|
||||||
|
string ServerName,
|
||||||
|
ushort ServerPort);
|
||||||
|
|
||||||
|
internal delegate uint ConnectionShutdownDelegate(
|
||||||
|
IntPtr Connection,
|
||||||
|
uint Flags,
|
||||||
|
ushort ErrorCode);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct StreamEventDataRecv
|
||||||
|
{
|
||||||
|
internal ulong AbsoluteOffset;
|
||||||
|
internal ulong TotalBufferLength;
|
||||||
|
internal QuicBuffer* Buffers;
|
||||||
|
internal uint BufferCount;
|
||||||
|
internal byte Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
internal struct StreamEventDataSendComplete
|
||||||
|
{
|
||||||
|
[FieldOffset(7)]
|
||||||
|
internal byte Canceled;
|
||||||
|
[FieldOffset(8)]
|
||||||
|
internal IntPtr ClientContext;
|
||||||
|
|
||||||
|
internal bool IsCanceled()
|
||||||
|
{
|
||||||
|
return Canceled != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct StreamEventDataPeerSendAbort
|
||||||
|
{
|
||||||
|
internal ushort ErrorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct StreamEventDataPeerRecvAbort
|
||||||
|
{
|
||||||
|
internal ushort ErrorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct StreamEventDataSendShutdownComplete
|
||||||
|
{
|
||||||
|
internal bool Graceful;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
internal struct StreamEventDataUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal StreamEventDataRecv Recv;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal StreamEventDataSendComplete SendComplete;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal StreamEventDataPeerSendAbort PeerSendAbort;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal StreamEventDataPeerRecvAbort PeerRecvAbort;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal StreamEventDataSendShutdownComplete SendShutdownComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct StreamEvent
|
||||||
|
{
|
||||||
|
internal QUIC_STREAM_EVENT Type;
|
||||||
|
internal StreamEventDataUnion Data;
|
||||||
|
internal uint ReceiveAbortError => Data.PeerRecvAbort.ErrorCode;
|
||||||
|
internal uint SendAbortError => Data.PeerSendAbort.ErrorCode;
|
||||||
|
internal ulong AbsoluteOffset => Data.Recv.AbsoluteOffset;
|
||||||
|
internal ulong TotalBufferLength => Data.Recv.TotalBufferLength;
|
||||||
|
internal void CopyToBuffer(Span<byte> buffer)
|
||||||
|
{
|
||||||
|
var length = (int)Data.Recv.Buffers[0].Length;
|
||||||
|
new Span<byte>(Data.Recv.Buffers[0].Buffer, length).CopyTo(buffer);
|
||||||
|
}
|
||||||
|
internal bool Canceled => Data.SendComplete.IsCanceled();
|
||||||
|
internal IntPtr ClientContext => Data.SendComplete.ClientContext;
|
||||||
|
internal bool GracefulShutdown => Data.SendShutdownComplete.Graceful;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal delegate uint StreamCallbackDelegate(
|
||||||
|
IntPtr Stream,
|
||||||
|
IntPtr Context,
|
||||||
|
ref StreamEvent Event);
|
||||||
|
|
||||||
|
internal delegate uint StreamOpenDelegate(
|
||||||
|
IntPtr Connection,
|
||||||
|
uint Flags,
|
||||||
|
StreamCallbackDelegate Handler,
|
||||||
|
IntPtr Context,
|
||||||
|
out IntPtr Stream);
|
||||||
|
|
||||||
|
internal delegate uint StreamStartDelegate(
|
||||||
|
IntPtr Stream,
|
||||||
|
uint Flags
|
||||||
|
);
|
||||||
|
|
||||||
|
internal delegate uint StreamCloseDelegate(
|
||||||
|
IntPtr Stream);
|
||||||
|
|
||||||
|
internal delegate uint StreamShutdownDelegate(
|
||||||
|
IntPtr Stream,
|
||||||
|
uint Flags,
|
||||||
|
ushort ErrorCode);
|
||||||
|
|
||||||
|
internal delegate uint StreamSendDelegate(
|
||||||
|
IntPtr Stream,
|
||||||
|
QuicBuffer* Buffers,
|
||||||
|
uint BufferCount,
|
||||||
|
uint Flags,
|
||||||
|
IntPtr ClientSendContext);
|
||||||
|
|
||||||
|
internal delegate uint StreamReceiveCompleteDelegate(
|
||||||
|
IntPtr Stream,
|
||||||
|
ulong BufferLength);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal unsafe struct QuicBuffer
|
||||||
|
{
|
||||||
|
internal uint Length;
|
||||||
|
internal byte* Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct SOCKADDR_IN
|
||||||
|
{
|
||||||
|
internal ushort sin_family;
|
||||||
|
internal ushort sin_port;
|
||||||
|
internal byte sin_addr0;
|
||||||
|
internal byte sin_addr1;
|
||||||
|
internal byte sin_addr2;
|
||||||
|
internal byte sin_addr3;
|
||||||
|
|
||||||
|
internal byte[] Address
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new byte[] { sin_addr0, sin_addr1, sin_addr2, sin_addr3 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct SOCKADDR_IN6
|
||||||
|
{
|
||||||
|
internal ushort sin6_family;
|
||||||
|
internal ushort sin6_port;
|
||||||
|
internal uint sin6_flowinfo;
|
||||||
|
internal byte sin6_addr0;
|
||||||
|
internal byte sin6_addr1;
|
||||||
|
internal byte sin6_addr2;
|
||||||
|
internal byte sin6_addr3;
|
||||||
|
internal byte sin6_addr4;
|
||||||
|
internal byte sin6_addr5;
|
||||||
|
internal byte sin6_addr6;
|
||||||
|
internal byte sin6_addr7;
|
||||||
|
internal byte sin6_addr8;
|
||||||
|
internal byte sin6_addr9;
|
||||||
|
internal byte sin6_addr10;
|
||||||
|
internal byte sin6_addr11;
|
||||||
|
internal byte sin6_addr12;
|
||||||
|
internal byte sin6_addr13;
|
||||||
|
internal byte sin6_addr14;
|
||||||
|
internal byte sin6_addr15;
|
||||||
|
internal uint sin6_scope_id;
|
||||||
|
|
||||||
|
internal byte[] Address
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new byte[] {
|
||||||
|
sin6_addr0, sin6_addr1, sin6_addr2, sin6_addr3 ,
|
||||||
|
sin6_addr4, sin6_addr5, sin6_addr6, sin6_addr7 ,
|
||||||
|
sin6_addr8, sin6_addr9, sin6_addr10, sin6_addr11 ,
|
||||||
|
sin6_addr12, sin6_addr13, sin6_addr14, sin6_addr15 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
|
||||||
|
internal struct SOCKADDR_INET
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal SOCKADDR_IN Ipv4;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal SOCKADDR_IN6 Ipv6;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
internal ushort si_family;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
internal class MsQuicStatusException : Exception
|
||||||
|
{
|
||||||
|
internal MsQuicStatusException(uint status)
|
||||||
|
: this(status, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MsQuicStatusException(uint status, string message)
|
||||||
|
: this(status, message, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MsQuicStatusException(uint status, string message, Exception innerException)
|
||||||
|
: base(GetMessage(status, message), innerException)
|
||||||
|
{
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint Status { get; }
|
||||||
|
|
||||||
|
private static string GetMessage(uint status, string message)
|
||||||
|
{
|
||||||
|
var errorCode = MsQuicConstants.ErrorTypeFromErrorCode(status);
|
||||||
|
return $"Quic Error: {errorCode}. " + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ThrowIfFailed(uint status, string message = null, Exception innerException = null)
|
||||||
|
{
|
||||||
|
if (!MsQuicStatusHelper.Succeeded(status))
|
||||||
|
{
|
||||||
|
throw new MsQuicStatusException(status, message, innerException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.MsQuic.Internal
|
||||||
|
{
|
||||||
|
internal static class MsQuicStatusHelper
|
||||||
|
{
|
||||||
|
internal static bool Succeeded(uint status)
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
return status < 0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
return (int)status <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>Libuv transport for the ASP.NET Core Kestrel cross-platform web server.</Description>
|
||||||
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>aspnetcore;kestrel</PackageTags>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<NoWarn>CS1591;$(NoWarn)</NoWarn>
|
||||||
|
<IsShippingPackage>false</IsShippingPackage>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||||
|
<Reference Include="Microsoft.Extensions.Options" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Loading…
Reference in New Issue