Sync shared code from runtime (#24630)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
6c35e2e84d
commit
973a97fc4b
|
|
@ -11,7 +11,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal const ushort IPv4 = 2;
|
internal const ushort IPv4 = 2;
|
||||||
internal const ushort IPv6 = 23;
|
internal const ushort IPv6 = 23;
|
||||||
|
|
||||||
internal static unsafe IPEndPoint INetToIPEndPoint(SOCKADDR_INET inetAddress)
|
internal static unsafe IPEndPoint INetToIPEndPoint(ref SOCKADDR_INET inetAddress)
|
||||||
{
|
{
|
||||||
if (inetAddress.si_family == IPv4)
|
if (inetAddress.si_family == IPv4)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
uint status = Interop.MsQuic.MsQuicOpen(version: 1, out registration);
|
uint status = Interop.MsQuic.MsQuicOpen(out registration);
|
||||||
if (!MsQuicStatusHelper.SuccessfulStatusCode(status))
|
if (!MsQuicStatusHelper.SuccessfulStatusCode(status))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException(SR.net_quic_notsupported);
|
throw new NotSupportedException(SR.net_quic_notsupported);
|
||||||
|
|
@ -123,7 +123,13 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.GetParamDelegate>(
|
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.GetParamDelegate>(
|
||||||
nativeRegistration.GetParam);
|
nativeRegistration.GetParam);
|
||||||
|
|
||||||
RegistrationOpenDelegate(Encoding.UTF8.GetBytes("SystemNetQuic"), out IntPtr ctx);
|
var registrationConfig = new MsQuicNativeMethods.RegistrationConfig
|
||||||
|
{
|
||||||
|
AppName = "SystemNetQuic",
|
||||||
|
ExecutionProfile = QUIC_EXECUTION_PROFILE.QUIC_EXECUTION_PROFILE_LOW_LATENCY
|
||||||
|
};
|
||||||
|
|
||||||
|
RegistrationOpenDelegate(ref registrationConfig, out IntPtr ctx);
|
||||||
_registrationContext = ctx;
|
_registrationContext = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,15 +318,26 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
return secConfig;
|
return secConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntPtr SessionOpen(byte[] alpn)
|
public unsafe IntPtr SessionOpen(byte[] alpn)
|
||||||
{
|
{
|
||||||
IntPtr sessionPtr = IntPtr.Zero;
|
IntPtr sessionPtr = IntPtr.Zero;
|
||||||
|
uint status;
|
||||||
|
|
||||||
uint status = SessionOpenDelegate(
|
fixed (byte* pAlpn = alpn)
|
||||||
_registrationContext,
|
{
|
||||||
alpn,
|
var alpnBuffer = new MsQuicNativeMethods.QuicBuffer
|
||||||
IntPtr.Zero,
|
{
|
||||||
ref sessionPtr);
|
Length = (uint)alpn.Length,
|
||||||
|
Buffer = pAlpn
|
||||||
|
};
|
||||||
|
|
||||||
|
status = SessionOpenDelegate(
|
||||||
|
_registrationContext,
|
||||||
|
&alpnBuffer,
|
||||||
|
1,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref sessionPtr);
|
||||||
|
}
|
||||||
|
|
||||||
QuicExceptionHelpers.ThrowIfFailed(status, "Could not open session.");
|
QuicExceptionHelpers.ThrowIfFailed(status, "Could not open session.");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
|
|
||||||
QuicExceptionHelpers.ThrowIfFailed(MsQuicApi.Api.ConnectionOpenDelegate(
|
QuicExceptionHelpers.ThrowIfFailed(MsQuicApi.Api.ConnectionOpenDelegate(
|
||||||
_nativeObjPtr,
|
_nativeObjPtr,
|
||||||
MsQuicConnection.NativeCallbackHandler,
|
MsQuicConnection.s_connectionDelegate,
|
||||||
IntPtr.Zero,
|
IntPtr.Zero,
|
||||||
out IntPtr connectionPtr),
|
out IntPtr connectionPtr),
|
||||||
"Could not open the connection.");
|
"Could not open the connection.");
|
||||||
|
|
@ -83,15 +83,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
|
|
||||||
public void SetPeerBiDirectionalStreamCount(ushort count)
|
public void SetPeerBiDirectionalStreamCount(ushort count)
|
||||||
{
|
{
|
||||||
SetUshortParamter(QUIC_PARAM_SESSION.PEER_BIDI_STREAM_COUNT, count);
|
SetUshortParameter(QUIC_PARAM_SESSION.PEER_BIDI_STREAM_COUNT, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPeerUnidirectionalStreamCount(ushort count)
|
public void SetPeerUnidirectionalStreamCount(ushort count)
|
||||||
{
|
{
|
||||||
SetUshortParamter(QUIC_PARAM_SESSION.PEER_UNIDI_STREAM_COUNT, count);
|
SetUshortParameter(QUIC_PARAM_SESSION.PEER_UNIDI_STREAM_COUNT, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void SetUshortParamter(QUIC_PARAM_SESSION param, ushort count)
|
private unsafe void SetUshortParameter(QUIC_PARAM_SESSION param, ushort count)
|
||||||
{
|
{
|
||||||
var buffer = new MsQuicNativeMethods.QuicBuffer()
|
var buffer = new MsQuicNativeMethods.QuicBuffer()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Quic.Implementations.MsQuic.Internal;
|
using System.Net.Quic.Implementations.MsQuic.Internal;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -16,7 +18,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
{
|
{
|
||||||
internal sealed class MsQuicConnection : QuicConnectionProvider
|
internal sealed class MsQuicConnection : QuicConnectionProvider
|
||||||
{
|
{
|
||||||
private MsQuicSession? _session;
|
private readonly MsQuicSession? _session;
|
||||||
|
|
||||||
// Pointer to the underlying connection
|
// Pointer to the underlying connection
|
||||||
// TODO replace all IntPtr with SafeHandles
|
// TODO replace all IntPtr with SafeHandles
|
||||||
|
|
@ -26,15 +28,17 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
private GCHandle _handle;
|
private GCHandle _handle;
|
||||||
|
|
||||||
// Delegate that wraps the static function that will be called when receiving an event.
|
// Delegate that wraps the static function that will be called when receiving an event.
|
||||||
// TODO investigate if the delegate can be static instead.
|
internal static readonly ConnectionCallbackDelegate s_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler);
|
||||||
private ConnectionCallbackDelegate? _connectionDelegate;
|
|
||||||
|
|
||||||
// Endpoint to either connect to or the endpoint already accepted.
|
// Endpoint to either connect to or the endpoint already accepted.
|
||||||
private IPEndPoint? _localEndPoint;
|
private IPEndPoint? _localEndPoint;
|
||||||
private readonly IPEndPoint _remoteEndPoint;
|
private readonly IPEndPoint _remoteEndPoint;
|
||||||
|
|
||||||
private readonly ResettableCompletionSource<uint> _connectTcs = new ResettableCompletionSource<uint>();
|
private SslApplicationProtocol _negotiatedAlpnProtocol;
|
||||||
private readonly ResettableCompletionSource<uint> _shutdownTcs = new ResettableCompletionSource<uint>();
|
|
||||||
|
// TODO: only allocate these when there is an outstanding connect/shutdown.
|
||||||
|
private readonly TaskCompletionSource<uint> _connectTcs = new TaskCompletionSource<uint>();
|
||||||
|
private readonly TaskCompletionSource<uint> _shutdownTcs = new TaskCompletionSource<uint>();
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _connected;
|
private bool _connected;
|
||||||
|
|
@ -54,6 +58,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
_localEndPoint = localEndPoint;
|
_localEndPoint = localEndPoint;
|
||||||
_remoteEndPoint = remoteEndPoint;
|
_remoteEndPoint = remoteEndPoint;
|
||||||
_ptr = nativeObjPtr;
|
_ptr = nativeObjPtr;
|
||||||
|
_connected = true;
|
||||||
|
|
||||||
SetCallbackHandler();
|
SetCallbackHandler();
|
||||||
SetIdleTimeout(TimeSpan.FromSeconds(120));
|
SetIdleTimeout(TimeSpan.FromSeconds(120));
|
||||||
|
|
@ -89,125 +94,96 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
|
|
||||||
internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint.Address, _remoteEndPoint.Port);
|
internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint.Address, _remoteEndPoint.Port);
|
||||||
|
|
||||||
internal override SslApplicationProtocol NegotiatedApplicationProtocol => throw new NotImplementedException();
|
internal override SslApplicationProtocol NegotiatedApplicationProtocol => _negotiatedAlpnProtocol;
|
||||||
|
|
||||||
internal override bool Connected => _connected;
|
internal override bool Connected => _connected;
|
||||||
|
|
||||||
internal uint HandleEvent(ref ConnectionEvent connectionEvent)
|
internal uint HandleEvent(ref ConnectionEvent connectionEvent)
|
||||||
{
|
{
|
||||||
uint status = MsQuicStatusCodes.Success;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (connectionEvent.Type)
|
switch (connectionEvent.Type)
|
||||||
{
|
{
|
||||||
// Connection is connected, can start to create streams.
|
|
||||||
case QUIC_CONNECTION_EVENT.CONNECTED:
|
case QUIC_CONNECTION_EVENT.CONNECTED:
|
||||||
{
|
return HandleEventConnected(ref connectionEvent);
|
||||||
status = HandleEventConnected(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Connection is being closed by the transport
|
|
||||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_TRANSPORT:
|
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_TRANSPORT:
|
||||||
{
|
return HandleEventShutdownInitiatedByTransport(ref connectionEvent);
|
||||||
status = HandleEventShutdownInitiatedByTransport(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Connection is being closed by the peer
|
|
||||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_PEER:
|
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_PEER:
|
||||||
{
|
return HandleEventShutdownInitiatedByPeer(ref connectionEvent);
|
||||||
status = HandleEventShutdownInitiatedByPeer(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Connection has been shutdown
|
|
||||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_COMPLETE:
|
case QUIC_CONNECTION_EVENT.SHUTDOWN_COMPLETE:
|
||||||
{
|
return HandleEventShutdownComplete(ref connectionEvent);
|
||||||
status = HandleEventShutdownComplete(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QUIC_CONNECTION_EVENT.PEER_STREAM_STARTED:
|
case QUIC_CONNECTION_EVENT.PEER_STREAM_STARTED:
|
||||||
{
|
return HandleEventNewStream(ref connectionEvent);
|
||||||
status = HandleEventNewStream(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QUIC_CONNECTION_EVENT.STREAMS_AVAILABLE:
|
case QUIC_CONNECTION_EVENT.STREAMS_AVAILABLE:
|
||||||
{
|
return HandleEventStreamsAvailable(ref connectionEvent);
|
||||||
status = HandleEventStreamsAvailable(
|
|
||||||
connectionEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// TODO we may want to either add a debug assert here or return specific error codes
|
if (NetEventSource.Log.IsEnabled())
|
||||||
// based on the exception caught.
|
{
|
||||||
|
NetEventSource.Error(this, $"Exception occurred during connection callback: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: trigger an exception on any outstanding async calls.
|
||||||
|
|
||||||
return MsQuicStatusCodes.InternalError;
|
return MsQuicStatusCodes.InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint HandleEventConnected(ConnectionEvent connectionEvent)
|
private uint HandleEventConnected(ref ConnectionEvent connectionEvent)
|
||||||
{
|
|
||||||
SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS);
|
|
||||||
_localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(inetAddress);
|
|
||||||
|
|
||||||
_connected = true;
|
|
||||||
// I don't believe we need to lock here because
|
|
||||||
// handle event connected will not be called at the same time as
|
|
||||||
// handle event shutdown initiated by transport
|
|
||||||
_connectTcs.Complete(MsQuicStatusCodes.Success);
|
|
||||||
|
|
||||||
return MsQuicStatusCodes.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint HandleEventShutdownInitiatedByTransport(ConnectionEvent connectionEvent)
|
|
||||||
{
|
{
|
||||||
if (!_connected)
|
if (!_connected)
|
||||||
{
|
{
|
||||||
_connectTcs.CompleteException(new IOException("Connection has been shutdown."));
|
// _connected will already be true for connections accepted from a listener.
|
||||||
|
|
||||||
|
SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS);
|
||||||
|
_localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress);
|
||||||
|
|
||||||
|
SetNegotiatedAlpn(connectionEvent.Data.Connected.NegotiatedAlpn, connectionEvent.Data.Connected.NegotiatedAlpnLength);
|
||||||
|
|
||||||
|
_connected = true;
|
||||||
|
_connectTcs.SetResult(MsQuicStatusCodes.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MsQuicStatusCodes.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint HandleEventShutdownInitiatedByTransport(ref ConnectionEvent connectionEvent)
|
||||||
|
{
|
||||||
|
if (!_connected)
|
||||||
|
{
|
||||||
|
_connectTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException("Connection has been shutdown.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
_acceptQueue.Writer.Complete();
|
_acceptQueue.Writer.Complete();
|
||||||
|
|
||||||
|
|
||||||
return MsQuicStatusCodes.Success;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint HandleEventShutdownInitiatedByPeer(ConnectionEvent connectionEvent)
|
private uint HandleEventShutdownInitiatedByPeer(ref ConnectionEvent connectionEvent)
|
||||||
{
|
{
|
||||||
_abortErrorCode = connectionEvent.Data.ShutdownBeginPeer.ErrorCode;
|
_abortErrorCode = connectionEvent.Data.ShutdownInitiatedByPeer.ErrorCode;
|
||||||
_acceptQueue.Writer.Complete();
|
_acceptQueue.Writer.Complete();
|
||||||
return MsQuicStatusCodes.Success;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint HandleEventShutdownComplete(ConnectionEvent connectionEvent)
|
private uint HandleEventShutdownComplete(ref ConnectionEvent connectionEvent)
|
||||||
{
|
{
|
||||||
_shutdownTcs.Complete(MsQuicStatusCodes.Success);
|
_shutdownTcs.SetResult(MsQuicStatusCodes.Success);
|
||||||
return MsQuicStatusCodes.Success;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint HandleEventNewStream(ConnectionEvent connectionEvent)
|
private uint HandleEventNewStream(ref ConnectionEvent connectionEvent)
|
||||||
{
|
{
|
||||||
MsQuicStream msQuicStream = new MsQuicStream(this, connectionEvent.StreamFlags, connectionEvent.Data.NewStream.Stream, inbound: true);
|
MsQuicStream msQuicStream = new MsQuicStream(this, connectionEvent.StreamFlags, connectionEvent.Data.StreamStarted.Stream, inbound: true);
|
||||||
_acceptQueue.Writer.TryWrite(msQuicStream);
|
_acceptQueue.Writer.TryWrite(msQuicStream);
|
||||||
return MsQuicStatusCodes.Success;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint HandleEventStreamsAvailable(ConnectionEvent connectionEvent)
|
private uint HandleEventStreamsAvailable(ref ConnectionEvent connectionEvent)
|
||||||
{
|
{
|
||||||
return MsQuicStatusCodes.Success;
|
return MsQuicStatusCodes.Success;
|
||||||
}
|
}
|
||||||
|
|
@ -275,7 +251,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
(ushort)_remoteEndPoint.Port),
|
(ushort)_remoteEndPoint.Port),
|
||||||
"Failed to connect to peer.");
|
"Failed to connect to peer.");
|
||||||
|
|
||||||
return _connectTcs.GetTypelessValueTask();
|
return new ValueTask(_connectTcs.Task);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MsQuicStream StreamOpen(
|
private MsQuicStream StreamOpen(
|
||||||
|
|
@ -286,7 +262,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
MsQuicApi.Api.StreamOpenDelegate(
|
MsQuicApi.Api.StreamOpenDelegate(
|
||||||
_ptr,
|
_ptr,
|
||||||
(uint)flags,
|
(uint)flags,
|
||||||
MsQuicStream.NativeCallbackHandler,
|
MsQuicStream.s_streamDelegate,
|
||||||
IntPtr.Zero,
|
IntPtr.Zero,
|
||||||
out streamPtr),
|
out streamPtr),
|
||||||
"Failed to open stream to peer.");
|
"Failed to open stream to peer.");
|
||||||
|
|
@ -296,11 +272,12 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
|
|
||||||
private void SetCallbackHandler()
|
private void SetCallbackHandler()
|
||||||
{
|
{
|
||||||
|
Debug.Assert(!_handle.IsAllocated);
|
||||||
_handle = GCHandle.Alloc(this);
|
_handle = GCHandle.Alloc(this);
|
||||||
_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler);
|
|
||||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||||
_ptr,
|
_ptr,
|
||||||
_connectionDelegate,
|
s_connectionDelegate,
|
||||||
GCHandle.ToIntPtr(_handle));
|
GCHandle.ToIntPtr(_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,10 +291,20 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
ErrorCode);
|
ErrorCode);
|
||||||
QuicExceptionHelpers.ThrowIfFailed(status, "Failed to shutdown connection.");
|
QuicExceptionHelpers.ThrowIfFailed(status, "Failed to shutdown connection.");
|
||||||
|
|
||||||
return _shutdownTcs.GetTypelessValueTask();
|
return new ValueTask(_shutdownTcs.Task);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static uint NativeCallbackHandler(
|
internal void SetNegotiatedAlpn(IntPtr alpn, int alpnLength)
|
||||||
|
{
|
||||||
|
if (alpn != IntPtr.Zero && alpnLength != 0)
|
||||||
|
{
|
||||||
|
var buffer = new byte[alpnLength];
|
||||||
|
Marshal.Copy(alpn, buffer, 0, alpnLength);
|
||||||
|
_negotiatedAlpnProtocol = new SslApplicationProtocol(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint NativeCallbackHandler(
|
||||||
IntPtr connection,
|
IntPtr connection,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
ref ConnectionEvent connectionEventStruct)
|
ref ConnectionEvent connectionEventStruct)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net.Quic.Implementations.MsQuic.Internal;
|
using System.Net.Quic.Implementations.MsQuic.Internal;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
@ -15,7 +16,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
internal sealed class MsQuicListener : QuicListenerProvider, IDisposable
|
internal sealed class MsQuicListener : QuicListenerProvider, IDisposable
|
||||||
{
|
{
|
||||||
// Security configuration for MsQuic
|
// Security configuration for MsQuic
|
||||||
private MsQuicSession _session;
|
private readonly MsQuicSession _session;
|
||||||
|
|
||||||
// Pointer to the underlying listener
|
// Pointer to the underlying listener
|
||||||
// TODO replace all IntPtr with SafeHandles
|
// TODO replace all IntPtr with SafeHandles
|
||||||
|
|
@ -25,10 +26,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
private GCHandle _handle;
|
private GCHandle _handle;
|
||||||
|
|
||||||
// Delegate that wraps the static function that will be called when receiving an event.
|
// Delegate that wraps the static function that will be called when receiving an event.
|
||||||
private ListenerCallbackDelegate? _listenerDelegate;
|
private static readonly ListenerCallbackDelegate s_listenerDelegate = new ListenerCallbackDelegate(NativeCallbackHandler);
|
||||||
|
|
||||||
// Ssl listening options (ALPN, cert, etc)
|
// Ssl listening options (ALPN, cert, etc)
|
||||||
private SslServerAuthenticationOptions _sslOptions;
|
private readonly SslServerAuthenticationOptions _sslOptions;
|
||||||
|
|
||||||
private QuicListenerOptions _options;
|
private QuicListenerOptions _options;
|
||||||
private volatile bool _disposed;
|
private volatile bool _disposed;
|
||||||
|
|
@ -142,11 +143,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
{
|
{
|
||||||
SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS);
|
SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS);
|
||||||
|
|
||||||
_listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(inetAddress);
|
_listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal unsafe uint ListenerCallbackHandler(
|
internal unsafe uint ListenerCallbackHandler(ref ListenerEvent evt)
|
||||||
ref ListenerEvent evt)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -154,10 +154,14 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
{
|
{
|
||||||
case QUIC_LISTENER_EVENT.NEW_CONNECTION:
|
case QUIC_LISTENER_EVENT.NEW_CONNECTION:
|
||||||
{
|
{
|
||||||
NewConnectionInfo connectionInfo = *(NewConnectionInfo*)evt.Data.NewConnection.Info;
|
ref NewConnectionInfo connectionInfo = ref *(NewConnectionInfo*)evt.Data.NewConnection.Info;
|
||||||
IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET*)connectionInfo.LocalAddress);
|
|
||||||
IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET*)connectionInfo.RemoteAddress);
|
IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.LocalAddress);
|
||||||
|
IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET*)connectionInfo.RemoteAddress);
|
||||||
|
|
||||||
MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection);
|
MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection);
|
||||||
|
msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength);
|
||||||
|
|
||||||
_acceptConnectionQueue.Writer.TryWrite(msQuicConnection);
|
_acceptConnectionQueue.Writer.TryWrite(msQuicConnection);
|
||||||
}
|
}
|
||||||
// Always pend the new connection to wait for the security config to be resolved
|
// Always pend the new connection to wait for the security config to be resolved
|
||||||
|
|
@ -167,8 +171,15 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
return MsQuicStatusCodes.InternalError;
|
return MsQuicStatusCodes.InternalError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
if (NetEventSource.Log.IsEnabled())
|
||||||
|
{
|
||||||
|
NetEventSource.Error(this, $"Exception occurred during connection callback: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: trigger an exception on any outstanding async calls.
|
||||||
|
|
||||||
return MsQuicStatusCodes.InternalError;
|
return MsQuicStatusCodes.InternalError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,11 +202,12 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
|
|
||||||
internal void SetCallbackHandler()
|
internal void SetCallbackHandler()
|
||||||
{
|
{
|
||||||
|
Debug.Assert(!_handle.IsAllocated);
|
||||||
_handle = GCHandle.Alloc(this);
|
_handle = GCHandle.Alloc(this);
|
||||||
_listenerDelegate = new ListenerCallbackDelegate(NativeCallbackHandler);
|
|
||||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||||
_ptr,
|
_ptr,
|
||||||
_listenerDelegate,
|
s_listenerDelegate,
|
||||||
GCHandle.ToIntPtr(_handle));
|
GCHandle.ToIntPtr(_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
private GCHandle _handle;
|
private GCHandle _handle;
|
||||||
|
|
||||||
// Delegate that wraps the static function that will be called when receiving an event.
|
// Delegate that wraps the static function that will be called when receiving an event.
|
||||||
private StreamCallbackDelegate? _callback;
|
internal static readonly StreamCallbackDelegate s_streamDelegate = new StreamCallbackDelegate(NativeCallbackHandler);
|
||||||
|
|
||||||
// Backing for StreamId
|
// Backing for StreamId
|
||||||
private long _streamId = -1;
|
private long _streamId = -1;
|
||||||
|
|
@ -62,10 +62,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
|
|
||||||
private volatile bool _disposed;
|
private volatile bool _disposed;
|
||||||
|
|
||||||
private List<QuicBuffer> _receiveQuicBuffers = new List<QuicBuffer>();
|
private readonly List<QuicBuffer> _receiveQuicBuffers = new List<QuicBuffer>();
|
||||||
|
|
||||||
// TODO consider using Interlocked.Exchange instead of a sync if we can avoid it.
|
// TODO consider using Interlocked.Exchange instead of a sync if we can avoid it.
|
||||||
private object _sync = new object();
|
private readonly object _sync = new object();
|
||||||
|
|
||||||
// Creates a new MsQuicStream
|
// Creates a new MsQuicStream
|
||||||
internal MsQuicStream(MsQuicConnection connection, QUIC_STREAM_OPEN_FLAG flags, IntPtr nativeObjPtr, bool inbound)
|
internal MsQuicStream(MsQuicConnection connection, QUIC_STREAM_OPEN_FLAG flags, IntPtr nativeObjPtr, bool inbound)
|
||||||
|
|
@ -79,17 +79,19 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
_shutdownWriteResettableCompletionSource = new ResettableCompletionSource<uint>();
|
_shutdownWriteResettableCompletionSource = new ResettableCompletionSource<uint>();
|
||||||
SetCallbackHandler();
|
SetCallbackHandler();
|
||||||
|
|
||||||
|
bool isBidirectional = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
||||||
|
|
||||||
if (inbound)
|
if (inbound)
|
||||||
{
|
{
|
||||||
_started = true;
|
|
||||||
_canWrite = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
|
||||||
_canRead = true;
|
_canRead = true;
|
||||||
|
_canWrite = isBidirectional;
|
||||||
|
_started = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_canRead = isBidirectional;
|
||||||
_canWrite = true;
|
_canWrite = true;
|
||||||
_canRead = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
StartLocalStream();
|
||||||
StartWrites();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -715,7 +717,6 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
CleanupSendState();
|
CleanupSendState();
|
||||||
|
|
||||||
// TODO throw if a write was canceled.
|
// TODO throw if a write was canceled.
|
||||||
uint errorCode = evt.Data.SendComplete.Canceled;
|
|
||||||
|
|
||||||
bool shouldComplete = false;
|
bool shouldComplete = false;
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
|
|
@ -753,10 +754,9 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
{
|
{
|
||||||
_handle = GCHandle.Alloc(this);
|
_handle = GCHandle.Alloc(this);
|
||||||
|
|
||||||
_callback = new StreamCallbackDelegate(NativeCallbackHandler);
|
|
||||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||||
_ptr,
|
_ptr,
|
||||||
_callback,
|
s_streamDelegate,
|
||||||
GCHandle.ToIntPtr(_handle));
|
GCHandle.ToIntPtr(_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -921,7 +921,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
||||||
return _sendResettableCompletionSource.GetTypelessValueTask();
|
return _sendResettableCompletionSource.GetTypelessValueTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartWrites()
|
/// <summary>
|
||||||
|
/// Assigns a stream ID and begins process the stream.
|
||||||
|
/// </summary>
|
||||||
|
private void StartLocalStream()
|
||||||
{
|
{
|
||||||
Debug.Assert(!_started);
|
Debug.Assert(!_started);
|
||||||
uint status = MsQuicApi.Api.StreamStartDelegate(
|
uint status = MsQuicApi.Api.StreamStartDelegate(
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ internal static partial class Interop
|
||||||
{
|
{
|
||||||
internal static class MsQuic
|
internal static class MsQuic
|
||||||
{
|
{
|
||||||
[DllImport(Libraries.MsQuic)]
|
[DllImport(Libraries.MsQuic, CallingConvention = CallingConvention.Cdecl)]
|
||||||
internal static unsafe extern uint MsQuicOpen(int version, out MsQuicNativeMethods.NativeApi* registration);
|
internal static unsafe extern uint MsQuicOpen(out MsQuicNativeMethods.NativeApi* registration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,26 @@
|
||||||
|
|
||||||
namespace System.Net.Quic.Implementations.MsQuic.Internal
|
namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
{
|
{
|
||||||
|
internal enum QUIC_EXECUTION_PROFILE : uint
|
||||||
|
{
|
||||||
|
QUIC_EXECUTION_PROFILE_LOW_LATENCY, // Default
|
||||||
|
QUIC_EXECUTION_PROFILE_TYPE_MAX_THROUGHPUT,
|
||||||
|
QUIC_EXECUTION_PROFILE_TYPE_SCAVENGER,
|
||||||
|
QUIC_EXECUTION_PROFILE_TYPE_REAL_TIME
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flags to pass when creating a security config.
|
/// Flags to pass when creating a security config.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum QUIC_SEC_CONFIG_FLAG : uint
|
internal enum QUIC_SEC_CONFIG_FLAG : uint
|
||||||
{
|
{
|
||||||
NONE = 0,
|
|
||||||
CERT_HASH = 0x00000001,
|
CERT_HASH = 0x00000001,
|
||||||
CERT_HASH_STORE = 0x00000002,
|
CERT_HASH_STORE = 0x00000002,
|
||||||
CERT_CONTEXT = 0x00000004,
|
CERT_CONTEXT = 0x00000004,
|
||||||
CERT_FILE = 0x00000008,
|
CERT_FILE = 0x00000008,
|
||||||
ENABL_OCSP = 0x00000010,
|
ENABL_OCSP = 0x00000010,
|
||||||
CERT_NULL = 0xF0000000,
|
CERT_NULL = 0xF0000000 // TODO: only valid for stub TLS.
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|
@ -67,22 +74,30 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
ALLOW_0_RTT = 0x00000001,
|
ALLOW_0_RTT = 0x00000001,
|
||||||
FIN = 0x00000002,
|
FIN = 0x00000002,
|
||||||
|
DGRAM_PRIORITY = 0x00000004
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_PARAM_LEVEL : uint
|
internal enum QUIC_PARAM_LEVEL : uint
|
||||||
{
|
{
|
||||||
REGISTRATION = 0,
|
GLOBAL,
|
||||||
SESSION = 1,
|
REGISTRATION,
|
||||||
LISTENER = 2,
|
SESSION,
|
||||||
CONNECTION = 3,
|
LISTENER,
|
||||||
TLS = 4,
|
CONNECTION,
|
||||||
STREAM = 5,
|
TLS,
|
||||||
|
STREAM
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum QUIC_PARAM_GLOBAL : uint
|
||||||
|
{
|
||||||
|
RETRY_MEMORY_PERCENT = 0,
|
||||||
|
SUPPORTED_VERSIONS = 1,
|
||||||
|
LOAD_BALANCING_MODE = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_PARAM_REGISTRATION : uint
|
internal enum QUIC_PARAM_REGISTRATION : uint
|
||||||
{
|
{
|
||||||
RETRY_MEMORY_PERCENT = 0,
|
CID_PREFIX = 0
|
||||||
CID_PREFIX = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_PARAM_SESSION : uint
|
internal enum QUIC_PARAM_SESSION : uint
|
||||||
|
|
@ -92,7 +107,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
PEER_UNIDI_STREAM_COUNT = 2,
|
PEER_UNIDI_STREAM_COUNT = 2,
|
||||||
IDLE_TIMEOUT = 3,
|
IDLE_TIMEOUT = 3,
|
||||||
DISCONNECT_TIMEOUT = 4,
|
DISCONNECT_TIMEOUT = 4,
|
||||||
MAX_BYTES_PER_KEY = 5
|
MAX_BYTES_PER_KEY = 5,
|
||||||
|
MIGRATION_ENABLED = 6,
|
||||||
|
DATAGRAM_RECEIVE_ENABLED = 7,
|
||||||
|
SERVER_RESUMPTION_LEVEL = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_PARAM_LISTENER : uint
|
internal enum QUIC_PARAM_LISTENER : uint
|
||||||
|
|
@ -122,7 +140,11 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
SEND_PACING = 16,
|
SEND_PACING = 16,
|
||||||
SHARE_UDP_BINDING = 17,
|
SHARE_UDP_BINDING = 17,
|
||||||
IDEAL_PROCESSOR = 18,
|
IDEAL_PROCESSOR = 18,
|
||||||
MAX_STREAM_IDS = 19
|
MAX_STREAM_IDS = 19,
|
||||||
|
STREAM_SCHEDULING_SCHEME = 20,
|
||||||
|
DATAGRAM_RECEIVE_ENABLED = 21,
|
||||||
|
DATAGRAM_SEND_ENABLED = 22,
|
||||||
|
DISABLE_1RTT_ENCRYPTION = 23
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_PARAM_STREAM : uint
|
internal enum QUIC_PARAM_STREAM : uint
|
||||||
|
|
@ -149,6 +171,11 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
STREAMS_AVAILABLE = 7,
|
STREAMS_AVAILABLE = 7,
|
||||||
PEER_NEEDS_STREAMS = 8,
|
PEER_NEEDS_STREAMS = 8,
|
||||||
IDEAL_PROCESSOR_CHANGED = 9,
|
IDEAL_PROCESSOR_CHANGED = 9,
|
||||||
|
DATAGRAM_STATE_CHANGED = 10,
|
||||||
|
DATAGRAM_RECEIVED = 11,
|
||||||
|
DATAGRAM_SEND_STATE_CHANGED = 12,
|
||||||
|
RESUMED = 13,
|
||||||
|
RESUMPTION_TICKET_RECEIVED = 14
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum QUIC_STREAM_EVENT : uint
|
internal enum QUIC_STREAM_EVENT : uint
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct NativeApi
|
internal struct NativeApi
|
||||||
{
|
{
|
||||||
internal uint Version;
|
|
||||||
|
|
||||||
internal IntPtr SetContext;
|
internal IntPtr SetContext;
|
||||||
internal IntPtr GetContext;
|
internal IntPtr GetContext;
|
||||||
internal IntPtr SetCallbackHandler;
|
internal IntPtr SetCallbackHandler;
|
||||||
|
|
@ -44,6 +42,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal IntPtr ConnectionClose;
|
internal IntPtr ConnectionClose;
|
||||||
internal IntPtr ConnectionShutdown;
|
internal IntPtr ConnectionShutdown;
|
||||||
internal IntPtr ConnectionStart;
|
internal IntPtr ConnectionStart;
|
||||||
|
internal IntPtr ConnectionSendResumptionTicket;
|
||||||
|
|
||||||
internal IntPtr StreamOpen;
|
internal IntPtr StreamOpen;
|
||||||
internal IntPtr StreamClose;
|
internal IntPtr StreamClose;
|
||||||
|
|
@ -52,20 +51,26 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal IntPtr StreamSend;
|
internal IntPtr StreamSend;
|
||||||
internal IntPtr StreamReceiveComplete;
|
internal IntPtr StreamReceiveComplete;
|
||||||
internal IntPtr StreamReceiveSetEnabled;
|
internal IntPtr StreamReceiveSetEnabled;
|
||||||
|
|
||||||
|
internal IntPtr DatagramSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint SetContextDelegate(
|
internal delegate uint SetContextDelegate(
|
||||||
IntPtr handle,
|
IntPtr handle,
|
||||||
IntPtr context);
|
IntPtr context);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate IntPtr GetContextDelegate(
|
internal delegate IntPtr GetContextDelegate(
|
||||||
IntPtr handle);
|
IntPtr handle);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void SetCallbackHandlerDelegate(
|
internal delegate void SetCallbackHandlerDelegate(
|
||||||
IntPtr handle,
|
IntPtr handle,
|
||||||
Delegate del,
|
Delegate del,
|
||||||
IntPtr context);
|
IntPtr context);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint SetParamDelegate(
|
internal delegate uint SetParamDelegate(
|
||||||
IntPtr handle,
|
IntPtr handle,
|
||||||
uint level,
|
uint level,
|
||||||
|
|
@ -73,6 +78,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
uint bufferLength,
|
uint bufferLength,
|
||||||
byte* buffer);
|
byte* buffer);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint GetParamDelegate(
|
internal delegate uint GetParamDelegate(
|
||||||
IntPtr handle,
|
IntPtr handle,
|
||||||
uint level,
|
uint level,
|
||||||
|
|
@ -80,36 +86,53 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
uint* bufferLength,
|
uint* bufferLength,
|
||||||
byte* buffer);
|
byte* buffer);
|
||||||
|
|
||||||
internal delegate uint RegistrationOpenDelegate(byte[] appName, out IntPtr registrationContext);
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
internal delegate uint RegistrationOpenDelegate(ref RegistrationConfig config, out IntPtr registrationContext);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void RegistrationCloseDelegate(IntPtr registrationContext);
|
internal delegate void RegistrationCloseDelegate(IntPtr registrationContext);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct RegistrationConfig
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||||
|
internal string AppName;
|
||||||
|
internal QUIC_EXECUTION_PROFILE ExecutionProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void SecConfigCreateCompleteDelegate(IntPtr context, uint status, IntPtr securityConfig);
|
internal delegate void SecConfigCreateCompleteDelegate(IntPtr context, uint status, IntPtr securityConfig);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint SecConfigCreateDelegate(
|
internal delegate uint SecConfigCreateDelegate(
|
||||||
IntPtr registrationContext,
|
IntPtr registrationContext,
|
||||||
uint flags,
|
uint flags,
|
||||||
IntPtr certificate,
|
IntPtr certificate,
|
||||||
[MarshalAs(UnmanagedType.LPStr)]string? principal,
|
[MarshalAs(UnmanagedType.LPUTF8Str)]string? principal,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
SecConfigCreateCompleteDelegate completionHandler);
|
SecConfigCreateCompleteDelegate completionHandler);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void SecConfigDeleteDelegate(
|
internal delegate void SecConfigDeleteDelegate(
|
||||||
IntPtr securityConfig);
|
IntPtr securityConfig);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint SessionOpenDelegate(
|
internal delegate uint SessionOpenDelegate(
|
||||||
IntPtr registrationContext,
|
IntPtr registrationContext,
|
||||||
byte[] utf8String,
|
QuicBuffer *alpnBuffers,
|
||||||
|
uint alpnBufferCount,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
ref IntPtr session);
|
ref IntPtr session);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void SessionCloseDelegate(
|
internal delegate void SessionCloseDelegate(
|
||||||
IntPtr session);
|
IntPtr session);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void SessionShutdownDelegate(
|
internal delegate void SessionShutdownDelegate(
|
||||||
IntPtr session,
|
IntPtr session,
|
||||||
uint flags,
|
uint flags,
|
||||||
ushort errorCode);
|
ulong errorCode);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct ListenerEvent
|
internal struct ListenerEvent
|
||||||
|
|
@ -139,49 +162,58 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal uint QuicVersion;
|
internal uint QuicVersion;
|
||||||
internal IntPtr LocalAddress;
|
internal IntPtr LocalAddress;
|
||||||
internal IntPtr RemoteAddress;
|
internal IntPtr RemoteAddress;
|
||||||
internal ushort CryptoBufferLength;
|
internal uint CryptoBufferLength;
|
||||||
internal ushort AlpnListLength;
|
internal ushort AlpnListLength;
|
||||||
internal ushort ServerNameLength;
|
internal ushort ServerNameLength;
|
||||||
|
internal byte NegotiatedAlpnLength;
|
||||||
internal IntPtr CryptoBuffer;
|
internal IntPtr CryptoBuffer;
|
||||||
internal IntPtr AlpnList;
|
internal IntPtr ClientAlpnList;
|
||||||
|
internal IntPtr NegotiatedAlpn;
|
||||||
internal IntPtr ServerName;
|
internal IntPtr ServerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ListenerCallbackDelegate(
|
internal delegate uint ListenerCallbackDelegate(
|
||||||
IntPtr listener,
|
IntPtr listener,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
ref ListenerEvent evt);
|
ref ListenerEvent evt);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ListenerOpenDelegate(
|
internal delegate uint ListenerOpenDelegate(
|
||||||
IntPtr session,
|
IntPtr session,
|
||||||
ListenerCallbackDelegate handler,
|
ListenerCallbackDelegate handler,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
out IntPtr listener);
|
out IntPtr listener);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ListenerCloseDelegate(
|
internal delegate uint ListenerCloseDelegate(
|
||||||
IntPtr listener);
|
IntPtr listener);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ListenerStartDelegate(
|
internal delegate uint ListenerStartDelegate(
|
||||||
IntPtr listener,
|
IntPtr listener,
|
||||||
ref SOCKADDR_INET localAddress);
|
ref SOCKADDR_INET localAddress);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ListenerStopDelegate(
|
internal delegate uint ListenerStopDelegate(
|
||||||
IntPtr listener);
|
IntPtr listener);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct ConnectionEventDataConnected
|
internal struct ConnectionEventDataConnected
|
||||||
{
|
{
|
||||||
internal bool EarlyDataAccepted;
|
internal bool SessionResumed;
|
||||||
|
internal byte NegotiatedAlpnLength;
|
||||||
|
internal IntPtr NegotiatedAlpn;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct ConnectionEventDataShutdownBegin
|
internal struct ConnectionEventDataShutdownInitiatedByTransport
|
||||||
{
|
{
|
||||||
internal uint Status;
|
internal uint Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct ConnectionEventDataShutdownBeginPeer
|
internal struct ConnectionEventDataShutdownInitiatedByPeer
|
||||||
{
|
{
|
||||||
internal long ErrorCode;
|
internal long ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
@ -205,7 +237,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct ConnectionEventDataNewStream
|
internal struct ConnectionEventDataStreamStarted
|
||||||
{
|
{
|
||||||
internal IntPtr Stream;
|
internal IntPtr Stream;
|
||||||
internal QUIC_STREAM_OPEN_FLAG Flags;
|
internal QUIC_STREAM_OPEN_FLAG Flags;
|
||||||
|
|
@ -218,12 +250,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal ushort UniDirectionalCount;
|
internal ushort UniDirectionalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal struct ConnectionEventDataIdealSendBuffer
|
|
||||||
{
|
|
||||||
internal ulong NumBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
internal struct ConnectionEventDataUnion
|
internal struct ConnectionEventDataUnion
|
||||||
{
|
{
|
||||||
|
|
@ -231,10 +257,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal ConnectionEventDataConnected Connected;
|
internal ConnectionEventDataConnected Connected;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
internal ConnectionEventDataShutdownBegin ShutdownBegin;
|
internal ConnectionEventDataShutdownInitiatedByTransport ShutdownInitiatedByTransport;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
internal ConnectionEventDataShutdownBeginPeer ShutdownBeginPeer;
|
internal ConnectionEventDataShutdownInitiatedByPeer ShutdownInitiatedByPeer;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
internal ConnectionEventDataShutdownComplete ShutdownComplete;
|
internal ConnectionEventDataShutdownComplete ShutdownComplete;
|
||||||
|
|
@ -246,13 +272,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal ConnectionEventDataPeerAddrChanged PeerAddrChanged;
|
internal ConnectionEventDataPeerAddrChanged PeerAddrChanged;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
internal ConnectionEventDataNewStream NewStream;
|
internal ConnectionEventDataStreamStarted StreamStarted;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
internal ConnectionEventDataStreamsAvailable StreamsAvailable;
|
internal ConnectionEventDataStreamsAvailable StreamsAvailable;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
|
||||||
internal ConnectionEventDataIdealSendBuffer IdealSendBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
@ -261,37 +284,42 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal QUIC_CONNECTION_EVENT Type;
|
internal QUIC_CONNECTION_EVENT Type;
|
||||||
internal ConnectionEventDataUnion Data;
|
internal ConnectionEventDataUnion Data;
|
||||||
|
|
||||||
internal bool EarlyDataAccepted => Data.Connected.EarlyDataAccepted;
|
internal bool EarlyDataAccepted => Data.Connected.SessionResumed;
|
||||||
internal ulong NumBytes => Data.IdealSendBuffer.NumBytes;
|
//internal ulong NumBytes => Data.IdealSendBuffer.NumBytes;
|
||||||
internal uint ShutdownBeginStatus => Data.ShutdownBegin.Status;
|
internal uint ShutdownBeginStatus => Data.ShutdownInitiatedByTransport.Status;
|
||||||
internal long ShutdownBeginPeerStatus => Data.ShutdownBeginPeer.ErrorCode;
|
internal long ShutdownBeginPeerStatus => Data.ShutdownInitiatedByPeer.ErrorCode;
|
||||||
internal bool ShutdownTimedOut => Data.ShutdownComplete.TimedOut;
|
internal bool ShutdownTimedOut => Data.ShutdownComplete.TimedOut;
|
||||||
internal ushort BiDirectionalCount => Data.StreamsAvailable.BiDirectionalCount;
|
internal ushort BiDirectionalCount => Data.StreamsAvailable.BiDirectionalCount;
|
||||||
internal ushort UniDirectionalCount => Data.StreamsAvailable.UniDirectionalCount;
|
internal ushort UniDirectionalCount => Data.StreamsAvailable.UniDirectionalCount;
|
||||||
internal QUIC_STREAM_OPEN_FLAG StreamFlags => Data.NewStream.Flags;
|
internal QUIC_STREAM_OPEN_FLAG StreamFlags => Data.StreamStarted.Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ConnectionCallbackDelegate(
|
internal delegate uint ConnectionCallbackDelegate(
|
||||||
IntPtr connection,
|
IntPtr connection,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
ref ConnectionEvent connectionEvent);
|
ref ConnectionEvent connectionEvent);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ConnectionOpenDelegate(
|
internal delegate uint ConnectionOpenDelegate(
|
||||||
IntPtr session,
|
IntPtr session,
|
||||||
ConnectionCallbackDelegate handler,
|
ConnectionCallbackDelegate handler,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
out IntPtr connection);
|
out IntPtr connection);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ConnectionCloseDelegate(
|
internal delegate uint ConnectionCloseDelegate(
|
||||||
IntPtr connection);
|
IntPtr connection);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ConnectionStartDelegate(
|
internal delegate uint ConnectionStartDelegate(
|
||||||
IntPtr connection,
|
IntPtr connection,
|
||||||
ushort family,
|
ushort family,
|
||||||
[MarshalAs(UnmanagedType.LPStr)]
|
[MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||||
string serverName,
|
string serverName,
|
||||||
ushort serverPort);
|
ushort serverPort);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint ConnectionShutdownDelegate(
|
internal delegate uint ConnectionShutdownDelegate(
|
||||||
IntPtr connection,
|
IntPtr connection,
|
||||||
uint flags,
|
uint flags,
|
||||||
|
|
@ -304,21 +332,14 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal ulong TotalBufferLength;
|
internal ulong TotalBufferLength;
|
||||||
internal QuicBuffer* Buffers;
|
internal QuicBuffer* Buffers;
|
||||||
internal uint BufferCount;
|
internal uint BufferCount;
|
||||||
internal uint Flags;
|
internal QUIC_RECEIVE_FLAG Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct StreamEventDataSendComplete
|
internal struct StreamEventDataSendComplete
|
||||||
{
|
{
|
||||||
[FieldOffset(0)]
|
internal bool Canceled;
|
||||||
internal byte Canceled;
|
|
||||||
[FieldOffset(1)]
|
|
||||||
internal IntPtr ClientContext;
|
internal IntPtr ClientContext;
|
||||||
|
|
||||||
internal bool IsCanceled()
|
|
||||||
{
|
|
||||||
return Canceled != 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
@ -432,11 +453,13 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
internal ushort si_family;
|
internal ushort si_family;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamCallbackDelegate(
|
internal delegate uint StreamCallbackDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
ref StreamEvent streamEvent);
|
ref StreamEvent streamEvent);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamOpenDelegate(
|
internal delegate uint StreamOpenDelegate(
|
||||||
IntPtr connection,
|
IntPtr connection,
|
||||||
uint flags,
|
uint flags,
|
||||||
|
|
@ -444,18 +467,22 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
IntPtr context,
|
IntPtr context,
|
||||||
out IntPtr stream);
|
out IntPtr stream);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamStartDelegate(
|
internal delegate uint StreamStartDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
uint flags);
|
uint flags);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamCloseDelegate(
|
internal delegate uint StreamCloseDelegate(
|
||||||
IntPtr stream);
|
IntPtr stream);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamShutdownDelegate(
|
internal delegate uint StreamShutdownDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
uint flags,
|
uint flags,
|
||||||
long errorCode);
|
long errorCode);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamSendDelegate(
|
internal delegate uint StreamSendDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
QuicBuffer* buffers,
|
QuicBuffer* buffers,
|
||||||
|
|
@ -463,12 +490,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
||||||
uint flags,
|
uint flags,
|
||||||
IntPtr clientSendContext);
|
IntPtr clientSendContext);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamReceiveCompleteDelegate(
|
internal delegate uint StreamReceiveCompleteDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
ulong bufferLength);
|
ulong bufferLength);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate uint StreamReceiveSetEnabledDelegate(
|
internal delegate uint StreamReceiveSetEnabledDelegate(
|
||||||
IntPtr stream,
|
IntPtr stream,
|
||||||
|
[MarshalAs(UnmanagedType.U1)]
|
||||||
bool enabled);
|
bool enabled);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue