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" 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.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.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" />
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebUti
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "samples\http2cat\http2cat.csproj", "{3D6821F5-F242-4828-8DDE-89488E85512D}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -503,6 +517,7 @@ Global
|
|||
{E0AD50A3-2518-4060-8BB9-5649B04B3A6D} = {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}
|
||||
{1BC94F37-AF61-4641-A80A-EC32A15C5344} = {2B456D08-F72B-4EB8-B663-B6D78FC04BF8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
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