Sync shared code from runtime (#25435)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
github-actions[bot] 2020-08-31 10:19:44 -07:00 committed by GitHub
parent 50f739a4bc
commit 2ea674021f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 156 additions and 48 deletions

View File

@ -14,7 +14,7 @@ namespace System.Net.Quic.Implementations.Mock
{
private readonly bool _isClient;
private bool _disposed;
private IPEndPoint? _remoteEndPoint;
private EndPoint? _remoteEndPoint;
private IPEndPoint? _localEndPoint;
private object _syncObject = new object();
private Socket? _socket;
@ -24,7 +24,7 @@ namespace System.Net.Quic.Implementations.Mock
private long _nextOutboundUnidirectionalStream;
// Constructor for outbound connections
internal MockConnection(IPEndPoint? remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
internal MockConnection(EndPoint? remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
{
_remoteEndPoint = remoteEndPoint;
_localEndPoint = localEndPoint;
@ -59,7 +59,7 @@ namespace System.Net.Quic.Implementations.Mock
internal override IPEndPoint LocalEndPoint => new IPEndPoint(_localEndPoint!.Address, _localEndPoint.Port);
internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint!.Address, _remoteEndPoint.Port);
internal override EndPoint RemoteEndPoint => _remoteEndPoint!;
internal override SslApplicationProtocol NegotiatedApplicationProtocol => throw new NotImplementedException();

View File

@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Runtime.InteropServices;
@ -318,26 +320,72 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
return secConfig;
}
public unsafe IntPtr SessionOpen(byte[] alpn)
public unsafe IntPtr SessionOpen(List<SslApplicationProtocol> alpnProtocols)
{
if (alpnProtocols.Count == 1)
{
return SessionOpen(alpnProtocols[0]);
}
var memoryHandles = ArrayPool<MemoryHandle>.Shared.Rent(alpnProtocols.Count);
var quicBuffers = ArrayPool<MsQuicNativeMethods.QuicBuffer>.Shared.Rent(alpnProtocols.Count);
try
{
for (int i = 0; i < alpnProtocols.Count; ++i)
{
ReadOnlyMemory<byte> alpnProtocol = alpnProtocols[i].Protocol;
MemoryHandle h = alpnProtocol.Pin();
memoryHandles[i] = h;
quicBuffers[i].Buffer = (byte*)h.Pointer;
quicBuffers[i].Length = (uint)alpnProtocol.Length;
}
IntPtr session;
fixed (MsQuicNativeMethods.QuicBuffer* pQuicBuffers = quicBuffers)
{
session = SessionOpen(pQuicBuffers, (uint)alpnProtocols.Count);
}
ArrayPool<MsQuicNativeMethods.QuicBuffer>.Shared.Return(quicBuffers);
ArrayPool<MemoryHandle>.Shared.Return(memoryHandles);
return session;
}
finally
{
foreach (MemoryHandle handle in memoryHandles)
{
handle.Dispose();
}
}
}
private unsafe IntPtr SessionOpen(SslApplicationProtocol alpnProtocol)
{
ReadOnlyMemory<byte> memory = alpnProtocol.Protocol;
using MemoryHandle h = memory.Pin();
var quicBuffer = new MsQuicNativeMethods.QuicBuffer()
{
Buffer = (byte*)h.Pointer,
Length = (uint)memory.Length
};
return SessionOpen(&quicBuffer, 1);
}
private unsafe IntPtr SessionOpen(MsQuicNativeMethods.QuicBuffer *alpnBuffers, uint bufferCount)
{
IntPtr sessionPtr = IntPtr.Zero;
uint status;
fixed (byte* pAlpn = alpn)
{
var alpnBuffer = new MsQuicNativeMethods.QuicBuffer
{
Length = (uint)alpn.Length,
Buffer = pAlpn
};
status = SessionOpenDelegate(
_registrationContext,
&alpnBuffer,
1,
IntPtr.Zero,
ref sessionPtr);
}
uint status = SessionOpenDelegate(
_registrationContext,
alpnBuffers,
bufferCount,
IntPtr.Zero,
ref sessionPtr);
QuicExceptionHelpers.ThrowIfFailed(status, "Could not open session.");

View File

@ -1,5 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Net.Security;
namespace System.Net.Quic.Implementations.MsQuic.Internal
{
@ -21,7 +23,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
{
if (!_opened)
{
OpenSession(options.ClientAuthenticationOptions!.ApplicationProtocols![0].Protocol.ToArray(),
OpenSession(options.ClientAuthenticationOptions!.ApplicationProtocols!,
(ushort)options.MaxBidirectionalStreams,
(ushort)options.MaxUnidirectionalStreams);
}
@ -36,7 +38,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
return connectionPtr;
}
private void OpenSession(byte[] alpn, ushort bidirectionalStreamCount, ushort undirectionalStreamCount)
private void OpenSession(List<SslApplicationProtocol> alpn, ushort bidirectionalStreamCount, ushort undirectionalStreamCount)
{
_opened = true;
_nativeObjPtr = MsQuicApi.Api.SessionOpen(alpn);
@ -49,7 +51,7 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
{
if (!_opened)
{
OpenSession(options.ServerAuthenticationOptions!.ApplicationProtocols![0].Protocol.ToArray(),
OpenSession(options.ServerAuthenticationOptions!.ApplicationProtocols!,
(ushort)options.MaxBidirectionalStreams,
(ushort)options.MaxUnidirectionalStreams);
}

View File

@ -10,8 +10,13 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
{
if (!MsQuicStatusHelper.SuccessfulStatusCode(status))
{
throw new QuicException($"{message} Error Code: {MsQuicStatusCodes.GetError(status)}");
throw CreateExceptionForHResult(status, message, innerException);
}
}
internal static Exception CreateExceptionForHResult(uint status, string? message = null, Exception? innerException = null)
{
return new QuicException($"{message} Error Code: {MsQuicStatusCodes.GetError(status)}", innerException);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.IO;
using System.Net.Quic.Implementations.MsQuic.Internal;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
@ -32,7 +33,7 @@ namespace System.Net.Quic.Implementations.MsQuic
// Endpoint to either connect to or the endpoint already accepted.
private IPEndPoint? _localEndPoint;
private readonly IPEndPoint _remoteEndPoint;
private readonly EndPoint _remoteEndPoint;
private SslApplicationProtocol _negotiatedAlpnProtocol;
@ -92,7 +93,7 @@ namespace System.Net.Quic.Implementations.MsQuic
MsQuicParameterHelpers.SetSecurityConfig(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.SEC_CONFIG, _securityConfig!.NativeObjPtr);
}
internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint.Address, _remoteEndPoint.Port);
internal override EndPoint RemoteEndPoint => _remoteEndPoint;
internal override SslApplicationProtocol NegotiatedApplicationProtocol => _negotiatedAlpnProtocol;
@ -155,7 +156,9 @@ namespace System.Net.Quic.Implementations.MsQuic
{
if (!_connected)
{
_connectTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException("Connection has been shutdown.")));
uint hresult = connectionEvent.Data.ShutdownInitiatedByTransport.Status;
Exception ex = QuicExceptionHelpers.CreateExceptionForHResult(hresult, "Connection has been shutdown by transport.");
_connectTcs.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(ex));
}
_acceptQueue.Writer.Complete();
@ -243,12 +246,28 @@ namespace System.Net.Quic.Implementations.MsQuic
{
ThrowIfDisposed();
(string address, int port) = _remoteEndPoint switch
{
DnsEndPoint dnsEp => (dnsEp.Host, dnsEp.Port),
IPEndPoint ipEp => (ipEp.Address.ToString(), ipEp.Port),
_ => throw new Exception($"Unsupported remote endpoint type '{_remoteEndPoint.GetType()}'.")
};
// values taken from https://github.com/microsoft/msquic/blob/main/docs/api/ConnectionStart.md
int af = _remoteEndPoint.AddressFamily switch
{
AddressFamily.Unspecified => 0,
AddressFamily.InterNetwork => 2,
AddressFamily.InterNetworkV6 => 23,
_ => throw new Exception($"Unsupported address family of '{_remoteEndPoint.AddressFamily}' for remote endpoint.")
};
QuicExceptionHelpers.ThrowIfFailed(
MsQuicApi.Api.ConnectionStartDelegate(
_ptr,
(ushort)_remoteEndPoint.AddressFamily,
_remoteEndPoint.Address.ToString(),
(ushort)_remoteEndPoint.Port),
(ushort)af,
address,
(ushort)port),
"Failed to connect to peer.");
return new ValueTask(_connectTcs.Task);

View File

@ -225,6 +225,11 @@ namespace System.Net.Quic.Implementations.MsQuic
throw new InvalidOperationException("Reading is not allowed on stream.");
}
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(this, $"[{GetHashCode()}] reading into Memory of '{destination.Length}' bytes.");
}
lock (_sync)
{
if (_readState == ReadState.ReadsCompleted)
@ -474,6 +479,11 @@ namespace System.Net.Quic.Implementations.MsQuic
private uint HandleEvent(ref StreamEvent evt)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(this, $"[{GetHashCode()}] handling event '{evt.Type}'.");
}
uint status = MsQuicStatusCodes.Success;
try

View File

@ -12,7 +12,7 @@ namespace System.Net.Quic.Implementations
internal abstract IPEndPoint LocalEndPoint { get; }
internal abstract IPEndPoint RemoteEndPoint { get; }
internal abstract EndPoint RemoteEndPoint { get; }
internal abstract ValueTask ConnectAsync(CancellationToken cancellationToken = default);

View File

@ -26,13 +26,16 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
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 ConnectionTimeout = 0x80410006;
internal const uint ConnectionIdle = 0x80410005;
internal const uint HostUnreachable = 0x800704D0;
internal const uint InternalError = 0x80410003;
internal const uint ConnectionRefused = 0x800704C9;
internal const uint ProtocolError = 0x80410004;
internal const uint VerNegError = 0x80410001;
internal const uint TlsError = 0x80072B18;
internal const uint UserCanceled = 0x80410002;
internal const uint AlpnNegotiationFailure = 0x80410007;
// TODO return better error messages here.
public static string GetError(uint status)
@ -53,11 +56,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
AddressInUse => "ADDRESS_IN_USE",
ConnectionTimeout => "CONNECTION_TIMEOUT",
ConnectionIdle => "CONNECTION_IDLE",
HostUnreachable => "UNREACHABLE",
InternalError => "INTERNAL_ERROR",
ServerBusy => "SERVER_BUSY",
ConnectionRefused => "CONNECTION_REFUSED",
ProtocolError => "PROTOCOL_ERROR",
VerNegError => "VER_NEG_ERROR",
_ => status.ToString()
TlsError => "TLS_ERROR",
UserCanceled => "USER_CANCELED",
AlpnNegotiationFailure => "ALPN_NEG_FAILURE",
_ => $"0x{status:X8}"
};
}
}
@ -79,9 +86,15 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
internal const uint ConnectionTimeout = 110;
internal const uint ConnectionIdle = 200000011;
internal const uint InternalError = 200000012;
internal const uint ServerBusy = 200000007;
internal const uint ConnectionRefused = 200000007;
internal const uint ProtocolError = 200000013;
internal const uint VerNegError = 200000014;
internal const uint EpollError = 200000015;
internal const uint DnsResolutionError = 200000016;
internal const uint SocketError = 200000017;
internal const uint TlsError = 200000018;
internal const uint UserCanceled = 200000019;
internal const uint AlpnNegotiationFailure = 200000020;
// TODO return better error messages here.
public static string GetError(uint status)
@ -103,10 +116,16 @@ namespace System.Net.Quic.Implementations.MsQuic.Internal
ConnectionTimeout => "CONNECTION_TIMEOUT",
ConnectionIdle => "CONNECTION_IDLE",
InternalError => "INTERNAL_ERROR",
ServerBusy => "SERVER_BUSY",
ConnectionRefused => "CONNECTION_REFUSED",
ProtocolError => "PROTOCOL_ERROR",
VerNegError => "VER_NEG_ERROR",
_ => status.ToString()
EpollError => "EPOLL_ERROR",
DnsResolutionError => "DNS_RESOLUTION_ERROR",
SocketError => "SOCKET_ERROR",
TlsError => "TLS_ERROR",
UserCanceled => "USER_CANCELED",
AlpnNegotiationFailure => "ALPN_NEG_FAILURE",
_ => $"0x{status:X8}"
};
}
}

View File

@ -24,7 +24,7 @@ namespace System.Net.Quic
/// <summary>
/// The endpoint to connect to.
/// </summary>
public IPEndPoint? RemoteEndPoint { get; set; }
public EndPoint? RemoteEndPoint { get; set; }
/// <summary>
/// Limit on the number of bidirectional streams the peer connection can create

View File

@ -22,13 +22,13 @@ namespace System.Net.Quic
/// <param name="remoteEndPoint">The remote endpoint to connect to.</param>
/// <param name="sslClientAuthenticationOptions">TLS options</param>
/// <param name="localEndPoint">The local endpoint to connect from.</param>
public QuicConnection(IPEndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
public QuicConnection(EndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
: this(QuicImplementationProviders.Default, remoteEndPoint, sslClientAuthenticationOptions, localEndPoint)
{
}
// !!! TEMPORARY: Remove "implementationProvider" before shipping
public QuicConnection(QuicImplementationProvider implementationProvider, IPEndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
public QuicConnection(QuicImplementationProvider implementationProvider, EndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null)
: this(implementationProvider, new QuicClientConnectionOptions() { RemoteEndPoint = remoteEndPoint, ClientAuthenticationOptions = sslClientAuthenticationOptions, LocalEndPoint = localEndPoint })
{
}
@ -50,7 +50,7 @@ namespace System.Net.Quic
public IPEndPoint LocalEndPoint => _provider.LocalEndPoint;
public IPEndPoint RemoteEndPoint => _provider.RemoteEndPoint;
public EndPoint RemoteEndPoint => _provider.RemoteEndPoint;
public SslApplicationProtocol NegotiatedApplicationProtocol => _provider.NegotiatedApplicationProtocol;

View File

@ -1,12 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable
namespace System.Net.Quic
{
internal class QuicException : Exception
{
public QuicException(string message)
: base (message)
public QuicException(string? message)
: base(message)
{
}
public QuicException(string? message, Exception? innerException)
: base(message, innerException)
{
}
}