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 IPv6 = 23;
|
||||
|
||||
internal static unsafe IPEndPoint INetToIPEndPoint(SOCKADDR_INET inetAddress)
|
||||
internal static unsafe IPEndPoint INetToIPEndPoint(ref SOCKADDR_INET inetAddress)
|
||||
{
|
||||
if (inetAddress.si_family == IPv4)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
|
||||
try
|
||||
{
|
||||
uint status = Interop.MsQuic.MsQuicOpen(version: 1, out registration);
|
||||
uint status = Interop.MsQuic.MsQuicOpen(out registration);
|
||||
if (!MsQuicStatusHelper.SuccessfulStatusCode(status))
|
||||
{
|
||||
throw new NotSupportedException(SR.net_quic_notsupported);
|
||||
|
|
@ -123,7 +123,13 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
Marshal.GetDelegateForFunctionPointer<MsQuicNativeMethods.GetParamDelegate>(
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -312,15 +318,26 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
return secConfig;
|
||||
}
|
||||
|
||||
public IntPtr SessionOpen(byte[] alpn)
|
||||
public unsafe IntPtr SessionOpen(byte[] alpn)
|
||||
{
|
||||
IntPtr sessionPtr = IntPtr.Zero;
|
||||
uint status;
|
||||
|
||||
uint status = SessionOpenDelegate(
|
||||
_registrationContext,
|
||||
alpn,
|
||||
IntPtr.Zero,
|
||||
ref sessionPtr);
|
||||
fixed (byte* pAlpn = alpn)
|
||||
{
|
||||
var alpnBuffer = new MsQuicNativeMethods.QuicBuffer
|
||||
{
|
||||
Length = (uint)alpn.Length,
|
||||
Buffer = pAlpn
|
||||
};
|
||||
|
||||
status = SessionOpenDelegate(
|
||||
_registrationContext,
|
||||
&alpnBuffer,
|
||||
1,
|
||||
IntPtr.Zero,
|
||||
ref sessionPtr);
|
||||
}
|
||||
|
||||
QuicExceptionHelpers.ThrowIfFailed(status, "Could not open session.");
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
|
||||
QuicExceptionHelpers.ThrowIfFailed(MsQuicApi.Api.ConnectionOpenDelegate(
|
||||
_nativeObjPtr,
|
||||
MsQuicConnection.NativeCallbackHandler,
|
||||
MsQuicConnection.s_connectionDelegate,
|
||||
IntPtr.Zero,
|
||||
out IntPtr connectionPtr),
|
||||
"Could not open the connection.");
|
||||
|
|
@ -83,15 +83,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Quic.Implementations.MsQuic.Internal;
|
||||
using System.Net.Security;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
|
|
@ -16,7 +18,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
{
|
||||
internal sealed class MsQuicConnection : QuicConnectionProvider
|
||||
{
|
||||
private MsQuicSession? _session;
|
||||
private readonly MsQuicSession? _session;
|
||||
|
||||
// Pointer to the underlying connection
|
||||
// TODO replace all IntPtr with SafeHandles
|
||||
|
|
@ -26,15 +28,17 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
private GCHandle _handle;
|
||||
|
||||
// Delegate that wraps the static function that will be called when receiving an event.
|
||||
// TODO investigate if the delegate can be static instead.
|
||||
private ConnectionCallbackDelegate? _connectionDelegate;
|
||||
internal static readonly ConnectionCallbackDelegate s_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler);
|
||||
|
||||
// Endpoint to either connect to or the endpoint already accepted.
|
||||
private IPEndPoint? _localEndPoint;
|
||||
private readonly IPEndPoint _remoteEndPoint;
|
||||
|
||||
private readonly ResettableCompletionSource<uint> _connectTcs = new ResettableCompletionSource<uint>();
|
||||
private readonly ResettableCompletionSource<uint> _shutdownTcs = new ResettableCompletionSource<uint>();
|
||||
private SslApplicationProtocol _negotiatedAlpnProtocol;
|
||||
|
||||
// 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 _connected;
|
||||
|
|
@ -54,6 +58,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
_localEndPoint = localEndPoint;
|
||||
_remoteEndPoint = remoteEndPoint;
|
||||
_ptr = nativeObjPtr;
|
||||
_connected = true;
|
||||
|
||||
SetCallbackHandler();
|
||||
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 SslApplicationProtocol NegotiatedApplicationProtocol => throw new NotImplementedException();
|
||||
internal override SslApplicationProtocol NegotiatedApplicationProtocol => _negotiatedAlpnProtocol;
|
||||
|
||||
internal override bool Connected => _connected;
|
||||
|
||||
internal uint HandleEvent(ref ConnectionEvent connectionEvent)
|
||||
{
|
||||
uint status = MsQuicStatusCodes.Success;
|
||||
try
|
||||
{
|
||||
switch (connectionEvent.Type)
|
||||
{
|
||||
// Connection is connected, can start to create streams.
|
||||
case QUIC_CONNECTION_EVENT.CONNECTED:
|
||||
{
|
||||
status = HandleEventConnected(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
// Connection is being closed by the transport
|
||||
return HandleEventConnected(ref connectionEvent);
|
||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_TRANSPORT:
|
||||
{
|
||||
status = HandleEventShutdownInitiatedByTransport(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
// Connection is being closed by the peer
|
||||
return HandleEventShutdownInitiatedByTransport(ref connectionEvent);
|
||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_INITIATED_BY_PEER:
|
||||
{
|
||||
status = HandleEventShutdownInitiatedByPeer(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
// Connection has been shutdown
|
||||
return HandleEventShutdownInitiatedByPeer(ref connectionEvent);
|
||||
case QUIC_CONNECTION_EVENT.SHUTDOWN_COMPLETE:
|
||||
{
|
||||
status = HandleEventShutdownComplete(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
return HandleEventShutdownComplete(ref connectionEvent);
|
||||
case QUIC_CONNECTION_EVENT.PEER_STREAM_STARTED:
|
||||
{
|
||||
status = HandleEventNewStream(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
return HandleEventNewStream(ref connectionEvent);
|
||||
case QUIC_CONNECTION_EVENT.STREAMS_AVAILABLE:
|
||||
{
|
||||
status = HandleEventStreamsAvailable(
|
||||
connectionEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
return HandleEventStreamsAvailable(ref connectionEvent);
|
||||
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
|
||||
// based on the exception caught.
|
||||
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 status;
|
||||
}
|
||||
|
||||
private uint HandleEventConnected(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)
|
||||
private uint HandleEventConnected(ref ConnectionEvent connectionEvent)
|
||||
{
|
||||
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();
|
||||
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return MsQuicStatusCodes.Success;
|
||||
}
|
||||
|
||||
private uint HandleEventStreamsAvailable(ConnectionEvent connectionEvent)
|
||||
private uint HandleEventStreamsAvailable(ref ConnectionEvent connectionEvent)
|
||||
{
|
||||
return MsQuicStatusCodes.Success;
|
||||
}
|
||||
|
|
@ -275,7 +251,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
(ushort)_remoteEndPoint.Port),
|
||||
"Failed to connect to peer.");
|
||||
|
||||
return _connectTcs.GetTypelessValueTask();
|
||||
return new ValueTask(_connectTcs.Task);
|
||||
}
|
||||
|
||||
private MsQuicStream StreamOpen(
|
||||
|
|
@ -286,7 +262,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
MsQuicApi.Api.StreamOpenDelegate(
|
||||
_ptr,
|
||||
(uint)flags,
|
||||
MsQuicStream.NativeCallbackHandler,
|
||||
MsQuicStream.s_streamDelegate,
|
||||
IntPtr.Zero,
|
||||
out streamPtr),
|
||||
"Failed to open stream to peer.");
|
||||
|
|
@ -296,11 +272,12 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
|
||||
private void SetCallbackHandler()
|
||||
{
|
||||
Debug.Assert(!_handle.IsAllocated);
|
||||
_handle = GCHandle.Alloc(this);
|
||||
_connectionDelegate = new ConnectionCallbackDelegate(NativeCallbackHandler);
|
||||
|
||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||
_ptr,
|
||||
_connectionDelegate,
|
||||
s_connectionDelegate,
|
||||
GCHandle.ToIntPtr(_handle));
|
||||
}
|
||||
|
||||
|
|
@ -314,10 +291,20 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
ErrorCode);
|
||||
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 context,
|
||||
ref ConnectionEvent connectionEventStruct)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Net.Quic.Implementations.MsQuic.Internal;
|
||||
using System.Net.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
@ -15,7 +16,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
internal sealed class MsQuicListener : QuicListenerProvider, IDisposable
|
||||
{
|
||||
// Security configuration for MsQuic
|
||||
private MsQuicSession _session;
|
||||
private readonly MsQuicSession _session;
|
||||
|
||||
// Pointer to the underlying listener
|
||||
// TODO replace all IntPtr with SafeHandles
|
||||
|
|
@ -25,10 +26,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
private GCHandle _handle;
|
||||
|
||||
// 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)
|
||||
private SslServerAuthenticationOptions _sslOptions;
|
||||
private readonly SslServerAuthenticationOptions _sslOptions;
|
||||
|
||||
private QuicListenerOptions _options;
|
||||
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);
|
||||
|
||||
_listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(inetAddress);
|
||||
_listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress);
|
||||
}
|
||||
|
||||
internal unsafe uint ListenerCallbackHandler(
|
||||
ref ListenerEvent evt)
|
||||
internal unsafe uint ListenerCallbackHandler(ref ListenerEvent evt)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -154,10 +154,14 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
{
|
||||
case QUIC_LISTENER_EVENT.NEW_CONNECTION:
|
||||
{
|
||||
NewConnectionInfo connectionInfo = *(NewConnectionInfo*)evt.Data.NewConnection.Info;
|
||||
IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET*)connectionInfo.LocalAddress);
|
||||
IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET*)connectionInfo.RemoteAddress);
|
||||
ref NewConnectionInfo connectionInfo = ref *(NewConnectionInfo*)evt.Data.NewConnection.Info;
|
||||
|
||||
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.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength);
|
||||
|
||||
_acceptConnectionQueue.Writer.TryWrite(msQuicConnection);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -191,11 +202,12 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
|
||||
internal void SetCallbackHandler()
|
||||
{
|
||||
Debug.Assert(!_handle.IsAllocated);
|
||||
_handle = GCHandle.Alloc(this);
|
||||
_listenerDelegate = new ListenerCallbackDelegate(NativeCallbackHandler);
|
||||
|
||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||
_ptr,
|
||||
_listenerDelegate,
|
||||
s_listenerDelegate,
|
||||
GCHandle.ToIntPtr(_handle));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
private GCHandle _handle;
|
||||
|
||||
// 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
|
||||
private long _streamId = -1;
|
||||
|
|
@ -62,10 +62,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
|
||||
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.
|
||||
private object _sync = new object();
|
||||
private readonly object _sync = new object();
|
||||
|
||||
// Creates a new MsQuicStream
|
||||
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>();
|
||||
SetCallbackHandler();
|
||||
|
||||
bool isBidirectional = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
||||
|
||||
if (inbound)
|
||||
{
|
||||
_started = true;
|
||||
_canWrite = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
||||
_canRead = true;
|
||||
_canWrite = isBidirectional;
|
||||
_started = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_canRead = isBidirectional;
|
||||
_canWrite = true;
|
||||
_canRead = !flags.HasFlag(QUIC_STREAM_OPEN_FLAG.UNIDIRECTIONAL);
|
||||
StartWrites();
|
||||
StartLocalStream();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -715,7 +717,6 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
CleanupSendState();
|
||||
|
||||
// TODO throw if a write was canceled.
|
||||
uint errorCode = evt.Data.SendComplete.Canceled;
|
||||
|
||||
bool shouldComplete = false;
|
||||
lock (_sync)
|
||||
|
|
@ -753,10 +754,9 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
{
|
||||
_handle = GCHandle.Alloc(this);
|
||||
|
||||
_callback = new StreamCallbackDelegate(NativeCallbackHandler);
|
||||
MsQuicApi.Api.SetCallbackHandlerDelegate(
|
||||
_ptr,
|
||||
_callback,
|
||||
s_streamDelegate,
|
||||
GCHandle.ToIntPtr(_handle));
|
||||
}
|
||||
|
||||
|
|
@ -921,7 +921,10 @@ namespace System.Net.Quic.Implementations.MsQuic
|
|||
return _sendResettableCompletionSource.GetTypelessValueTask();
|
||||
}
|
||||
|
||||
private void StartWrites()
|
||||
/// <summary>
|
||||
/// Assigns a stream ID and begins process the stream.
|
||||
/// </summary>
|
||||
private void StartLocalStream()
|
||||
{
|
||||
Debug.Assert(!_started);
|
||||
uint status = MsQuicApi.Api.StreamStartDelegate(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ internal static partial class Interop
|
|||
{
|
||||
internal static class MsQuic
|
||||
{
|
||||
[DllImport(Libraries.MsQuic)]
|
||||
internal static unsafe extern uint MsQuicOpen(int version, out MsQuicNativeMethods.NativeApi* registration);
|
||||
[DllImport(Libraries.MsQuic, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern uint MsQuicOpen(out MsQuicNativeMethods.NativeApi* registration);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,26 @@
|
|||
|
||||
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>
|
||||
/// 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,
|
||||
CERT_NULL = 0xF0000000 // TODO: only valid for stub TLS.
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
|
@ -67,22 +74,30 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
NONE = 0,
|
||||
ALLOW_0_RTT = 0x00000001,
|
||||
FIN = 0x00000002,
|
||||
DGRAM_PRIORITY = 0x00000004
|
||||
}
|
||||
|
||||
internal enum QUIC_PARAM_LEVEL : uint
|
||||
{
|
||||
REGISTRATION = 0,
|
||||
SESSION = 1,
|
||||
LISTENER = 2,
|
||||
CONNECTION = 3,
|
||||
TLS = 4,
|
||||
STREAM = 5,
|
||||
GLOBAL,
|
||||
REGISTRATION,
|
||||
SESSION,
|
||||
LISTENER,
|
||||
CONNECTION,
|
||||
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
|
||||
{
|
||||
RETRY_MEMORY_PERCENT = 0,
|
||||
CID_PREFIX = 1
|
||||
CID_PREFIX = 0
|
||||
}
|
||||
|
||||
internal enum QUIC_PARAM_SESSION : uint
|
||||
|
|
@ -92,7 +107,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
PEER_UNIDI_STREAM_COUNT = 2,
|
||||
IDLE_TIMEOUT = 3,
|
||||
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
|
||||
|
|
@ -122,7 +140,11 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
SEND_PACING = 16,
|
||||
SHARE_UDP_BINDING = 17,
|
||||
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
|
||||
|
|
@ -149,6 +171,11 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
STREAMS_AVAILABLE = 7,
|
||||
PEER_NEEDS_STREAMS = 8,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct NativeApi
|
||||
{
|
||||
internal uint Version;
|
||||
|
||||
internal IntPtr SetContext;
|
||||
internal IntPtr GetContext;
|
||||
internal IntPtr SetCallbackHandler;
|
||||
|
|
@ -44,6 +42,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal IntPtr ConnectionClose;
|
||||
internal IntPtr ConnectionShutdown;
|
||||
internal IntPtr ConnectionStart;
|
||||
internal IntPtr ConnectionSendResumptionTicket;
|
||||
|
||||
internal IntPtr StreamOpen;
|
||||
internal IntPtr StreamClose;
|
||||
|
|
@ -52,20 +51,26 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal IntPtr StreamSend;
|
||||
internal IntPtr StreamReceiveComplete;
|
||||
internal IntPtr StreamReceiveSetEnabled;
|
||||
|
||||
internal IntPtr DatagramSend;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint SetContextDelegate(
|
||||
IntPtr handle,
|
||||
IntPtr context);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr GetContextDelegate(
|
||||
IntPtr handle);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void SetCallbackHandlerDelegate(
|
||||
IntPtr handle,
|
||||
Delegate del,
|
||||
IntPtr context);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint SetParamDelegate(
|
||||
IntPtr handle,
|
||||
uint level,
|
||||
|
|
@ -73,6 +78,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
uint bufferLength,
|
||||
byte* buffer);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint GetParamDelegate(
|
||||
IntPtr handle,
|
||||
uint level,
|
||||
|
|
@ -80,36 +86,53 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
uint* bufferLength,
|
||||
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);
|
||||
|
||||
[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);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint SecConfigCreateDelegate(
|
||||
IntPtr registrationContext,
|
||||
uint flags,
|
||||
IntPtr certificate,
|
||||
[MarshalAs(UnmanagedType.LPStr)]string? principal,
|
||||
[MarshalAs(UnmanagedType.LPUTF8Str)]string? principal,
|
||||
IntPtr context,
|
||||
SecConfigCreateCompleteDelegate completionHandler);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void SecConfigDeleteDelegate(
|
||||
IntPtr securityConfig);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint SessionOpenDelegate(
|
||||
IntPtr registrationContext,
|
||||
byte[] utf8String,
|
||||
QuicBuffer *alpnBuffers,
|
||||
uint alpnBufferCount,
|
||||
IntPtr context,
|
||||
ref IntPtr session);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void SessionCloseDelegate(
|
||||
IntPtr session);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void SessionShutdownDelegate(
|
||||
IntPtr session,
|
||||
uint flags,
|
||||
ushort errorCode);
|
||||
ulong errorCode);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ListenerEvent
|
||||
|
|
@ -139,49 +162,58 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal uint QuicVersion;
|
||||
internal IntPtr LocalAddress;
|
||||
internal IntPtr RemoteAddress;
|
||||
internal ushort CryptoBufferLength;
|
||||
internal uint CryptoBufferLength;
|
||||
internal ushort AlpnListLength;
|
||||
internal ushort ServerNameLength;
|
||||
internal byte NegotiatedAlpnLength;
|
||||
internal IntPtr CryptoBuffer;
|
||||
internal IntPtr AlpnList;
|
||||
internal IntPtr ClientAlpnList;
|
||||
internal IntPtr NegotiatedAlpn;
|
||||
internal IntPtr ServerName;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ListenerCallbackDelegate(
|
||||
IntPtr listener,
|
||||
IntPtr context,
|
||||
ref ListenerEvent evt);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ListenerOpenDelegate(
|
||||
IntPtr session,
|
||||
ListenerCallbackDelegate handler,
|
||||
IntPtr context,
|
||||
out IntPtr listener);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ListenerCloseDelegate(
|
||||
IntPtr listener);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ListenerStartDelegate(
|
||||
IntPtr listener,
|
||||
ref SOCKADDR_INET localAddress);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ListenerStopDelegate(
|
||||
IntPtr listener);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ConnectionEventDataConnected
|
||||
{
|
||||
internal bool EarlyDataAccepted;
|
||||
internal bool SessionResumed;
|
||||
internal byte NegotiatedAlpnLength;
|
||||
internal IntPtr NegotiatedAlpn;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ConnectionEventDataShutdownBegin
|
||||
internal struct ConnectionEventDataShutdownInitiatedByTransport
|
||||
{
|
||||
internal uint Status;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ConnectionEventDataShutdownBeginPeer
|
||||
internal struct ConnectionEventDataShutdownInitiatedByPeer
|
||||
{
|
||||
internal long ErrorCode;
|
||||
}
|
||||
|
|
@ -205,7 +237,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ConnectionEventDataNewStream
|
||||
internal struct ConnectionEventDataStreamStarted
|
||||
{
|
||||
internal IntPtr Stream;
|
||||
internal QUIC_STREAM_OPEN_FLAG Flags;
|
||||
|
|
@ -218,12 +250,6 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal ushort UniDirectionalCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ConnectionEventDataIdealSendBuffer
|
||||
{
|
||||
internal ulong NumBytes;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct ConnectionEventDataUnion
|
||||
{
|
||||
|
|
@ -231,10 +257,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal ConnectionEventDataConnected Connected;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataShutdownBegin ShutdownBegin;
|
||||
internal ConnectionEventDataShutdownInitiatedByTransport ShutdownInitiatedByTransport;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataShutdownBeginPeer ShutdownBeginPeer;
|
||||
internal ConnectionEventDataShutdownInitiatedByPeer ShutdownInitiatedByPeer;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataShutdownComplete ShutdownComplete;
|
||||
|
|
@ -246,13 +272,10 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal ConnectionEventDataPeerAddrChanged PeerAddrChanged;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataNewStream NewStream;
|
||||
internal ConnectionEventDataStreamStarted StreamStarted;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataStreamsAvailable StreamsAvailable;
|
||||
|
||||
[FieldOffset(0)]
|
||||
internal ConnectionEventDataIdealSendBuffer IdealSendBuffer;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
|
@ -261,37 +284,42 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal QUIC_CONNECTION_EVENT Type;
|
||||
internal ConnectionEventDataUnion Data;
|
||||
|
||||
internal bool EarlyDataAccepted => Data.Connected.EarlyDataAccepted;
|
||||
internal ulong NumBytes => Data.IdealSendBuffer.NumBytes;
|
||||
internal uint ShutdownBeginStatus => Data.ShutdownBegin.Status;
|
||||
internal long ShutdownBeginPeerStatus => Data.ShutdownBeginPeer.ErrorCode;
|
||||
internal bool EarlyDataAccepted => Data.Connected.SessionResumed;
|
||||
//internal ulong NumBytes => Data.IdealSendBuffer.NumBytes;
|
||||
internal uint ShutdownBeginStatus => Data.ShutdownInitiatedByTransport.Status;
|
||||
internal long ShutdownBeginPeerStatus => Data.ShutdownInitiatedByPeer.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 QUIC_STREAM_OPEN_FLAG StreamFlags => Data.StreamStarted.Flags;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ConnectionCallbackDelegate(
|
||||
IntPtr connection,
|
||||
IntPtr context,
|
||||
ref ConnectionEvent connectionEvent);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ConnectionOpenDelegate(
|
||||
IntPtr session,
|
||||
ConnectionCallbackDelegate handler,
|
||||
IntPtr context,
|
||||
out IntPtr connection);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ConnectionCloseDelegate(
|
||||
IntPtr connection);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ConnectionStartDelegate(
|
||||
IntPtr connection,
|
||||
ushort family,
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
[MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
string serverName,
|
||||
ushort serverPort);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint ConnectionShutdownDelegate(
|
||||
IntPtr connection,
|
||||
uint flags,
|
||||
|
|
@ -304,21 +332,14 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal ulong TotalBufferLength;
|
||||
internal QuicBuffer* Buffers;
|
||||
internal uint BufferCount;
|
||||
internal uint Flags;
|
||||
internal QUIC_RECEIVE_FLAG Flags;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct StreamEventDataSendComplete
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
internal byte Canceled;
|
||||
[FieldOffset(1)]
|
||||
internal bool Canceled;
|
||||
internal IntPtr ClientContext;
|
||||
|
||||
internal bool IsCanceled()
|
||||
{
|
||||
return Canceled != 0;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
|
@ -432,11 +453,13 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
internal ushort si_family;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamCallbackDelegate(
|
||||
IntPtr stream,
|
||||
IntPtr context,
|
||||
ref StreamEvent streamEvent);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamOpenDelegate(
|
||||
IntPtr connection,
|
||||
uint flags,
|
||||
|
|
@ -444,18 +467,22 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
IntPtr context,
|
||||
out IntPtr stream);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamStartDelegate(
|
||||
IntPtr stream,
|
||||
uint flags);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamCloseDelegate(
|
||||
IntPtr stream);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamShutdownDelegate(
|
||||
IntPtr stream,
|
||||
uint flags,
|
||||
long errorCode);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamSendDelegate(
|
||||
IntPtr stream,
|
||||
QuicBuffer* buffers,
|
||||
|
|
@ -463,12 +490,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
|
|||
uint flags,
|
||||
IntPtr clientSendContext);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamReceiveCompleteDelegate(
|
||||
IntPtr stream,
|
||||
ulong bufferLength);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate uint StreamReceiveSetEnabledDelegate(
|
||||
IntPtr stream,
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
bool enabled);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue