From 4e740d051101e74aacf485209087a020b44a3783 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 24 Jun 2024 22:28:38 +0200 Subject: [PATCH 01/37] Activities for Http Connection, Dns, Sockets and Tls --- .../tests/System/Net/ActivityRecorder.cs | 74 ++++++++++ .../src/System/Net/Http/DiagnosticsHandler.cs | 16 +-- .../Http/DiagnosticsHandlerLoggingStrings.cs | 17 ++- .../Http/SocketsHttpHandler/ConnectHelper.cs | 3 +- .../HttpConnectionPool.Http1.cs | 8 +- .../HttpConnectionPool.Http2.cs | 16 +-- .../ConnectionPool/HttpConnectionPool.cs | 35 +++-- .../SocketsHttpHandler/Http2Connection.cs | 6 +- .../SocketsHttpHandler/Http3Connection.cs | 2 +- .../Http/SocketsHttpHandler/HttpConnection.cs | 5 +- .../SocketsHttpHandler/HttpConnectionBase.cs | 20 ++- .../tests/FunctionalTests/DiagnosticsTests.cs | 133 +++++++++++++++++- .../System.Net.Http.Functional.Tests.csproj | 2 + .../src/System/Net/Dns.cs | 96 +++++++------ .../src/System/Net/NameResolutionTelemetry.cs | 53 +++++-- .../tests/FunctionalTests/ActivityTest.cs | 79 +++++++++++ ...Net.NameResolution.Functional.Tests.csproj | 3 + .../src/System.Net.Security.csproj | 1 + .../src/System/Net/Security/SslStream.IO.cs | 25 +++- .../System.Net.Security.Tests.csproj | 2 + .../tests/FunctionalTests/TelemetryTest.cs | 33 +++++ .../src/System.Net.Sockets.csproj | 1 + .../src/System/Net/Sockets/Socket.cs | 16 ++- .../Net/Sockets/SocketAsyncEventArgs.cs | 4 +- .../System/Net/Sockets/SocketsTelemetry.cs | 24 +++- .../System.Net.Sockets.Tests.csproj | 2 + .../tests/FunctionalTests/TelemetryTest.cs | 62 ++++++++ 27 files changed, 617 insertions(+), 121 deletions(-) create mode 100644 src/libraries/Common/tests/System/Net/ActivityRecorder.cs create mode 100644 src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs new file mode 100644 index 0000000000000..d2a155985be5e --- /dev/null +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -0,0 +1,74 @@ +// 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.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Xunit; + +namespace System.Net.Test.Common +{ + internal class ActivityRecorder : IDisposable + { + private string _activitySourceName; + private string _activityName; + + private readonly ActivityListener _listener; + + public Predicate Filter { get; set; } = _ => true; + public bool VerifyParent { get; set; } = true; + public Activity ExpectedParent { get; set; } + + public int Started { get; private set; } + public int Stopped { get; private set; } + public Activity LastStartedActivity { get; private set; } + public Activity LastFinishedActivity { get; private set; } + + public ActivityRecorder(string activitySourceName, string activityName) + { + _activitySourceName = activitySourceName; + _activityName = activityName; + _listener = new ActivityListener + { + ShouldListenTo = (activitySource) => activitySource.Name == _activitySourceName, + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllData, + ActivityStarted = (activity) => { + if (activity.OperationName == _activityName && Filter(activity)) + { + if (VerifyParent) + { + Assert.Same(ExpectedParent, activity.Parent); + } + + Started++; + LastStartedActivity = activity; + } + }, + ActivityStopped = (activity) => { + if (activity.OperationName == _activityName && Filter(activity)) + { + if (VerifyParent) + { + Assert.Same(ExpectedParent, activity.Parent); + } + + Stopped++; + LastFinishedActivity = activity; + } + } + }; + + ActivitySource.AddActivityListener(_listener); + } + + public void Dispose() => _listener.Dispose(); + + public void VerifyActivityRecorded(int times) + { + Assert.Equal(times, Started); + Assert.Equal(times, Stopped); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs index 6436c1595b46e..dbfcf3974d4c2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs @@ -16,7 +16,7 @@ namespace System.Net.Http internal sealed class DiagnosticsHandler : HttpMessageHandlerStage { private static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(DiagnosticsHandlerLoggingStrings.DiagnosticListenerName); - private static readonly ActivitySource s_activitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.Namespace); + private static readonly ActivitySource s_activitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.RequestNamespace); private readonly HttpMessageHandler _innerHandler; private readonly DistributedContextPropagator _propagator; @@ -58,14 +58,14 @@ private static bool IsEnabled() Activity? activity = null; if (s_activitySource.HasListeners()) { - activity = s_activitySource.CreateActivity(DiagnosticsHandlerLoggingStrings.ActivityName, ActivityKind.Client); + activity = s_activitySource.CreateActivity(DiagnosticsHandlerLoggingStrings.RequestActivityName, ActivityKind.Client); } if (activity is null) { - if (Activity.Current is not null || s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityName, requestMessage)) + if (Activity.Current is not null || s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityName, requestMessage)) { - activity = new Activity(DiagnosticsHandlerLoggingStrings.ActivityName); + activity = new Activity(DiagnosticsHandlerLoggingStrings.RequestActivityName); } } @@ -117,9 +117,9 @@ private async ValueTask SendAsyncCore(HttpRequestMessage re activity.Start(); // Only send start event to users who subscribed for it. - if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityStartName)) + if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityStartName)) { - Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.ActivityStartName, new ActivityStartData(request)); + Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.RequestActivityStartName, new ActivityStartData(request)); } } @@ -177,9 +177,9 @@ await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false) activity.SetEndTime(DateTime.UtcNow); // Only send stop event to users who subscribed for it. - if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityStopName)) + if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityStopName)) { - Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.ActivityStopName, new ActivityStopData(response, request, taskStatus)); + Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.RequestActivityStopName, new ActivityStopData(response, request, taskStatus)); } activity.Stop(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs index 030310f4fdc81..5a8a013fbcd9d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs @@ -9,12 +9,15 @@ namespace System.Net.Http internal static class DiagnosticsHandlerLoggingStrings { public const string DiagnosticListenerName = "HttpHandlerDiagnosticListener"; - public const string Namespace = "System.Net.Http"; - public const string RequestWriteNameDeprecated = Namespace + ".Request"; - public const string ResponseWriteNameDeprecated = Namespace + ".Response"; - public const string ExceptionEventName = Namespace + ".Exception"; - public const string ActivityName = Namespace + ".HttpRequestOut"; - public const string ActivityStartName = ActivityName + ".Start"; - public const string ActivityStopName = ActivityName + ".Stop"; + public const string RequestNamespace = "System.Net.Http"; + public const string RequestWriteNameDeprecated = RequestNamespace + ".Request"; + public const string ResponseWriteNameDeprecated = RequestNamespace + ".Response"; + public const string ExceptionEventName = RequestNamespace + ".Exception"; + public const string RequestActivityName = RequestNamespace + ".HttpRequestOut"; + public const string RequestActivityStartName = RequestActivityName + ".Start"; + public const string RequestActivityStopName = RequestActivityName + ".Stop"; + + public const string ConnectionNamespace = "System.Net.Http.Connections"; + public const string ConnectionActivityName = ConnectionNamespace + ".HttpConnection"; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index d8d43a4d250ea..96c228c4874a2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -55,7 +55,7 @@ private static SslClientAuthenticationOptions SetUpRemoteCertificateValidationCa return sslOptions; } - public static async ValueTask EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken) + public static async ValueTask EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, Activity? activity, CancellationToken cancellationToken) { sslOptions = SetUpRemoteCertificateValidationCallback(sslOptions, request); @@ -78,6 +78,7 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu catch (Exception e) { sslStream.Dispose(); + activity?.Stop(); if (e is OperationCanceledException) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs index 319e119978a85..d65e1b6486de2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs @@ -294,14 +294,14 @@ private async Task InjectNewHttp11ConnectionAsync(RequestQueue.Q internal async ValueTask CreateHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { - (Stream stream, TransportContext? transportContext, IPEndPoint? remoteEndPoint) = await ConnectAsync(request, async, cancellationToken).ConfigureAwait(false); - return await ConstructHttp11ConnectionAsync(async, stream, transportContext, request, remoteEndPoint, cancellationToken).ConfigureAwait(false); + (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(request, async, cancellationToken).ConfigureAwait(false); + return await ConstructHttp11ConnectionAsync(async, stream, transportContext, request, activity, remoteEndPoint, cancellationToken).ConfigureAwait(false); } - private async ValueTask ConstructHttp11ConnectionAsync(bool async, Stream stream, TransportContext? transportContext, HttpRequestMessage request, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) + private async ValueTask ConstructHttp11ConnectionAsync(bool async, Stream stream, TransportContext? transportContext, HttpRequestMessage request, Activity? activity, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) { Stream newStream = await ApplyPlaintextFilterAsync(async, stream, HttpVersion.Version11, request, cancellationToken).ConfigureAwait(false); - return new HttpConnection(this, newStream, transportContext, remoteEndPoint); + return new HttpConnection(this, newStream, transportContext, activity, remoteEndPoint); } private void HandleHttp11ConnectionFailure(HttpConnectionWaiter? requestWaiter, Exception e) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs index fb1054165cac1..c3999c520f0f2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs @@ -185,7 +185,7 @@ private async Task InjectNewHttp2ConnectionAsync(RequestQueue. waiter.ConnectionCancellationTokenSource = cts; try { - (Stream stream, TransportContext? transportContext, IPEndPoint? remoteEndPoint) = await ConnectAsync(queueItem.Request, true, cts.Token).ConfigureAwait(false); + (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(queueItem.Request, true, cts.Token).ConfigureAwait(false); if (IsSecure) { @@ -202,19 +202,19 @@ private async Task InjectNewHttp2ConnectionAsync(RequestQueue. } else { - connection = await ConstructHttp2ConnectionAsync(stream, queueItem.Request, remoteEndPoint, cts.Token).ConfigureAwait(false); + connection = await ConstructHttp2ConnectionAsync(stream, queueItem.Request, activity, remoteEndPoint, cts.Token).ConfigureAwait(false); } } else { // We established an SSL connection, but the server denied our request for HTTP2. - await HandleHttp11Downgrade(queueItem.Request, stream, transportContext, remoteEndPoint, cts.Token).ConfigureAwait(false); + await HandleHttp11Downgrade(queueItem.Request, stream, transportContext, activity, remoteEndPoint, cts.Token).ConfigureAwait(false); return; } } else { - connection = await ConstructHttp2ConnectionAsync(stream, queueItem.Request, remoteEndPoint, cts.Token).ConfigureAwait(false); + connection = await ConstructHttp2ConnectionAsync(stream, queueItem.Request, activity, remoteEndPoint, cts.Token).ConfigureAwait(false); } } catch (Exception e) @@ -244,11 +244,11 @@ private async Task InjectNewHttp2ConnectionAsync(RequestQueue. } } - private async ValueTask ConstructHttp2ConnectionAsync(Stream stream, HttpRequestMessage request, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) + private async ValueTask ConstructHttp2ConnectionAsync(Stream stream, HttpRequestMessage request, Activity? activity, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) { stream = await ApplyPlaintextFilterAsync(async: true, stream, HttpVersion.Version20, request, cancellationToken).ConfigureAwait(false); - Http2Connection http2Connection = new Http2Connection(this, stream, remoteEndPoint); + Http2Connection http2Connection = new Http2Connection(this, stream, activity, remoteEndPoint); try { await http2Connection.SetupAsync(cancellationToken).ConfigureAwait(false); @@ -287,7 +287,7 @@ private void HandleHttp2ConnectionFailure(HttpConnectionWaiter } } - private async Task HandleHttp11Downgrade(HttpRequestMessage request, Stream stream, TransportContext? transportContext, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) + private async Task HandleHttp11Downgrade(HttpRequestMessage request, Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint, CancellationToken cancellationToken) { if (NetEventSource.Log.IsEnabled()) Trace("Server does not support HTTP2; disabling HTTP2 use and proceeding with HTTP/1.1 connection"); @@ -345,7 +345,7 @@ private async Task HandleHttp11Downgrade(HttpRequestMessage request, Stream stre try { // Note, the same CancellationToken from the original HTTP2 connection establishment still applies here. - http11Connection = await ConstructHttp11ConnectionAsync(true, stream, transportContext, request, remoteEndPoint, cancellationToken).ConfigureAwait(false); + http11Connection = await ConstructHttp11ConnectionAsync(true, stream, transportContext, request, activity, remoteEndPoint, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException oce) when (oce.CancellationToken == cancellationToken) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index 3fc2f43b01a8c..8df77b18e3246 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -32,6 +32,7 @@ internal sealed partial class HttpConnectionPool : IDisposable private static readonly List s_http3ApplicationProtocols = new List() { SslApplicationProtocol.Http3 }; private static readonly List s_http2ApplicationProtocols = new List() { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }; private static readonly List s_http2OnlyApplicationProtocols = new List() { SslApplicationProtocol.Http2 }; + private static readonly ActivitySource s_connectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); private readonly HttpConnectionPoolManager _poolManager; private readonly HttpConnectionKind _kind; @@ -561,31 +562,37 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn } } - private async ValueTask<(Stream, TransportContext?, IPEndPoint?)> ConnectAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) + private async ValueTask<(Stream, TransportContext?, Activity?, IPEndPoint?)> ConnectAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { Stream? stream = null; IPEndPoint? remoteEndPoint = null; + + // Connection activities should be new roots and not parented under whatever + // request happens to be in progress when the connection is started. + Activity.Current = null; + Activity? activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionActivityName); + switch (_kind) { case HttpConnectionKind.Http: case HttpConnectionKind.Https: case HttpConnectionKind.ProxyConnect: - stream = await ConnectToTcpHostAsync(_originAuthority.IdnHost, _originAuthority.Port, request, async, cancellationToken).ConfigureAwait(false); + stream = await ConnectToTcpHostAsync(_originAuthority.IdnHost, _originAuthority.Port, request, async, activity, cancellationToken).ConfigureAwait(false); // remoteEndPoint is returned for diagnostic purposes. remoteEndPoint = GetRemoteEndPoint(stream); if (_kind == HttpConnectionKind.ProxyConnect && _sslOptionsProxy != null) { - stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, cancellationToken).ConfigureAwait(false); + stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, activity, cancellationToken).ConfigureAwait(false); } break; case HttpConnectionKind.Proxy: - stream = await ConnectToTcpHostAsync(_proxyUri!.IdnHost, _proxyUri.Port, request, async, cancellationToken).ConfigureAwait(false); + stream = await ConnectToTcpHostAsync(_proxyUri!.IdnHost, _proxyUri.Port, request, async, activity, cancellationToken).ConfigureAwait(false); // remoteEndPoint is returned for diagnostic purposes. remoteEndPoint = GetRemoteEndPoint(stream); if (_sslOptionsProxy != null) { - stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, cancellationToken).ConfigureAwait(false); + stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, activity, cancellationToken).ConfigureAwait(false); } break; @@ -602,7 +609,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn case HttpConnectionKind.SocksTunnel: case HttpConnectionKind.SslSocksTunnel: - stream = await EstablishSocksTunnel(request, async, cancellationToken).ConfigureAwait(false); + stream = await EstablishSocksTunnel(request, async, activity, cancellationToken).ConfigureAwait(false); // remoteEndPoint is returned for diagnostic purposes. remoteEndPoint = GetRemoteEndPoint(stream); break; @@ -616,7 +623,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn SslStream? sslStream = stream as SslStream; if (sslStream == null) { - sslStream = await ConnectHelper.EstablishSslConnectionAsync(GetSslOptionsForRequest(request), request, async, stream, cancellationToken).ConfigureAwait(false); + sslStream = await ConnectHelper.EstablishSslConnectionAsync(GetSslOptionsForRequest(request), request, async, stream, activity, cancellationToken).ConfigureAwait(false); } else { @@ -631,10 +638,10 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn static IPEndPoint? GetRemoteEndPoint(Stream stream) => (stream as NetworkStream)?.Socket?.RemoteEndPoint as IPEndPoint; - return (stream, transportContext, remoteEndPoint); + return (stream, transportContext, activity, remoteEndPoint); } - private async ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, CancellationToken cancellationToken) + private async ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, Activity? activity, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -670,9 +677,10 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt } else { + IPAddress[] addresses = Dns.GetHostAddresses(host); using (cancellationToken.UnsafeRegister(static s => ((Socket)s!).Dispose(), socket)) { - socket.Connect(endPoint); + socket.Connect(addresses, port); } } @@ -689,9 +697,10 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt } catch (Exception ex) { + activity?.Stop(); throw ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken) : - ConnectHelper.CreateWrappedException(ex, endPoint.Host, endPoint.Port, cancellationToken); + ConnectHelper.CreateWrappedException(ex, host, port, cancellationToken); } } @@ -785,11 +794,11 @@ private async ValueTask EstablishProxyTunnelAsync(bool async, Cancellati } } - private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, bool async, CancellationToken cancellationToken) + private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, bool async, Activity? activity, CancellationToken cancellationToken) { Debug.Assert(_proxyUri != null); - Stream stream = await ConnectToTcpHostAsync(_proxyUri.IdnHost, _proxyUri.Port, request, async, cancellationToken).ConfigureAwait(false); + Stream stream = await ConnectToTcpHostAsync(_proxyUri.IdnHost, _proxyUri.Port, request, async, activity, cancellationToken).ConfigureAwait(false); try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index aec467cf2c740..3b6fdda63efaa 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -129,8 +129,8 @@ internal enum KeepAliveState private long _keepAlivePingTimeoutTimestamp; private volatile KeepAliveState _keepAliveState; - public Http2Connection(HttpConnectionPool pool, Stream stream, IPEndPoint? remoteEndPoint) - : base(pool, remoteEndPoint) + public Http2Connection(HttpConnectionPool pool, Stream stream, Activity? activity, IPEndPoint? remoteEndPoint) + : base(pool, activity, remoteEndPoint) { _pool = pool; _stream = stream; @@ -1851,6 +1851,7 @@ private void FinalTeardown() GC.SuppressFinalize(this); + _activity?.Stop(); _stream.Dispose(); _connectionWindow.Dispose(); @@ -1994,6 +1995,7 @@ public async Task SendAsync(HttpRequestMessage request, boo Debug.Assert(async); Debug.Assert(!_pool.HasSyncObjLock); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); + LinkRequestActivity(); try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 75b9d9b1f8a96..e05de14a86c0e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -67,7 +67,7 @@ private bool ShuttingDown } public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader) - : base(pool, connection.RemoteEndPoint) + : base(pool, null, connection.RemoteEndPoint) { _pool = pool; _authority = authority; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index 38c0b274aa403..841dcc08d7e08 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -75,8 +75,9 @@ public HttpConnection( HttpConnectionPool pool, Stream stream, TransportContext? transportContext, + Activity? activity, IPEndPoint? remoteEndPoint) - : base(pool, remoteEndPoint) + : base(pool, activity, remoteEndPoint) { Debug.Assert(pool != null); Debug.Assert(stream != null); @@ -114,6 +115,7 @@ private void Dispose(bool disposing) if (disposing) { GC.SuppressFinalize(this); + _activity?.Stop(); _stream.Dispose(); } } @@ -532,6 +534,7 @@ public async Task SendAsync(HttpRequestMessage request, boo "The caller should have called PrepareForReuse or TryOwnScavengingTaskCompletion if the connection was idle on the pool."); MarkConnectionAsNotIdle(); + LinkRequestActivity(); TaskCompletionSource? allowExpect100ToContinue = null; Task? sendRequestContentTask = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index d1a48491674ed..e549b4dfef9e2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -1,6 +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.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -21,6 +22,8 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace // May be null if none of the counters were enabled when the connection was established. private readonly ConnectionMetrics? _connectionMetrics; + protected readonly Activity? _activity; + // Indicates whether we've counted this connection as established, so that we can // avoid decrementing the counter once it's closed in case telemetry was enabled in between. private readonly bool _httpTelemetryMarkedConnectionAsOpened; @@ -35,11 +38,12 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace public long Id { get; } = Interlocked.Increment(ref s_connectionCounter); - public HttpConnectionBase(HttpConnectionPool pool, IPEndPoint? remoteEndPoint) + public HttpConnectionBase(HttpConnectionPool pool, Activity? activity, IPEndPoint? remoteEndPoint) { Debug.Assert(this is HttpConnection or Http2Connection or Http3Connection); Debug.Assert(pool.Settings._metrics is not null); + _activity = activity; SocketsHttpHandlerMetrics metrics = pool.Settings._metrics; if (metrics.OpenConnections.Enabled || metrics.ConnectionDuration.Enabled) @@ -104,6 +108,20 @@ public void MarkConnectionAsNotIdle() _connectionMetrics?.IdleStateChanged(idle: false); } + public void LinkRequestActivity() + { + if (_activity is null) + { + return; + } + + Activity? requestActivity = Activity.Current; + if (requestActivity?.OperationName is DiagnosticsHandlerLoggingStrings.RequestActivityName) + { + requestActivity.AddLink(new ActivityLink(_activity.Context)); + } + } + /// Uses , but first special-cases several known headers for which we can use caching. public string GetResponseHeaderValueWithCaching(HeaderDescriptor descriptor, ReadOnlySpan value, Encoding? valueEncoding) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 9059a05d49f6b..71422a53b1a1b 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -379,6 +379,128 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( }, UseVersion.ToString(), TestAsync.ToString(), idFormat.ToString()).DisposeAsync(); } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public async Task SendAsync_Success_ConnectionActivityRecordedWithChildren(bool useTls) + { + await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); + static async Task RunTest(string useVersion, string testAsync, string useTlsString) + { + bool useTls = bool.Parse(useTlsString); + + Activity parentActivity = new Activity("parent").Start(); + + using ActivityRecorder requestRecorder = new("System.Net.Http", "System.Net.Http.HttpRequestOut") + { + ExpectedParent = parentActivity + }; + + using ActivityRecorder connectionRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.HttpConnection"); + using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DsnLookup") { VerifyParent = false }; + using ActivityRecorder socketRecorder = new("System.Net.Sockets", "System.Net.Sockets.Connect") { VerifyParent = false }; + using ActivityRecorder tlsRecorder = new("System.Net.Security", "System.Net.Security.TlsHandshake") + { + VerifyParent = false, + Filter = a => a.Kind == ActivityKind.Client // do not capture the server handshake + }; + + await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( + async uri => + { + uri = new Uri($"{uri.Scheme}://localhost:{uri.Port}"); + using HttpClient client = new HttpClient(CreateHttpClientHandler(allowAllCertificates: true)); + + await client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); + + requestRecorder.VerifyActivityRecorded(1); + VerifySingleConnectionStarted(); + + await client.SendAsync(CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); + VerifySingleConnectionStarted(); + + client.Dispose(); // Releases the connection + connectionRecorder.VerifyActivityRecorded(1); + + Activity conn = connectionRecorder.LastStartedActivity; + Activity dns = dnsRecorder.LastFinishedActivity; + Activity sock = socketRecorder.LastFinishedActivity; + TimeSpan tlsDuration = tlsRecorder.LastFinishedActivity?.Duration ?? TimeSpan.Zero; + Assert.True(conn.Duration > dns.Duration + sock.Duration + tlsDuration); + + void VerifySingleConnectionStarted() + { + Assert.Equal(1, connectionRecorder.Started); + Assert.Equal(0, connectionRecorder.Stopped); + dnsRecorder.VerifyActivityRecorded(1); + + Assert.True(socketRecorder.Started is 1 or 2 && socketRecorder.Stopped is 1 or 2); + + tlsRecorder.VerifyActivityRecorded(useTls ? 1 : 0); + + Activity conn = connectionRecorder.LastStartedActivity; + Activity dns = dnsRecorder.LastFinishedActivity; + Activity sock = socketRecorder.LastFinishedActivity; + + Assert.Null(conn.Parent); + Assert.Same(conn, dns.Parent); + Assert.Same(conn, sock.Parent); + Assert.True(conn.StartTimeUtc <= dns.StartTimeUtc); + Assert.True(dns.StartTimeUtc <= sock.StartTimeUtc); + + TimeSpan tlsDuration = TimeSpan.Zero; + if (useTls) + { + Activity tls = tlsRecorder.LastFinishedActivity; + tlsDuration = tls.Duration; + Assert.Same(conn, tls.Parent); + Assert.True(sock.StartTimeUtc <= tls.StartTimeUtc); + } + + // The connection activity should be linked to the request. + requestRecorder.LastFinishedActivity.Links.Single(l => l.Context == conn.Context); + } + }, + async server => + { + await server.AcceptConnectionAsync(async connection => + { + await connection.ReadRequestDataAsync(); + await connection.SendResponseAsync(HttpStatusCode.OK); + connection.CompleteRequestProcessing(); + + await connection.ReadRequestDataAsync(); + await connection.SendResponseAsync(HttpStatusCode.OK); + }); + }, options: new GenericLoopbackOptions() + { + UseSsl = useTls + }); + } + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public async Task SendAsync_ConnectionFailure_ConnectionActivityRecorded() + { + await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString()).DisposeAsync(); + static async Task RunTest(string useVersion, string testAsync) + { + using HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); + GetUnderlyingSocketsHttpHandler(handler).ConnectCallback = (_, __) => throw new Exception(); + + using HttpClient client = new HttpClient(handler); + + Activity parentActivity = new Activity("parent").Start(); + using ActivityRecorder connectionRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.HttpConnection"); + + await Assert.ThrowsAsync(() => client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, new Uri("http://foo.bar"), Version.Parse(useVersion), exactVersion: true))); + + connectionRecorder.VerifyActivityRecorded(1); + Assert.Null(connectionRecorder.LastFinishedActivity.Parent); + } + } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public async Task SendAsync_ExpectedDiagnosticSourceActivityLogging_InvalidBaggage() { @@ -990,8 +1112,7 @@ public static IEnumerable SocketsHttpHandler_ActivityCreation_MemberDa public async Task SendAsync_ActivityIsCreatedIfRequested(bool currentActivitySet, bool? diagnosticListenerActivityEnabled, bool? activitySourceCreatesActivity) { string parameters = $"{currentActivitySet},{diagnosticListenerActivityEnabled},{activitySourceCreatesActivity}"; - - await RemoteExecutor.Invoke(async (useVersion, testAsync, parametersString) => + await RemoteExecutor.Invoke(static async (useVersion, testAsync, parametersString) => { bool?[] parameters = parametersString.Split(',').Select(p => p.Length == 0 ? (bool?)null : bool.Parse(p)).ToArray(); bool currentActivitySet = parameters[0].Value; @@ -1003,7 +1124,7 @@ await RemoteExecutor.Invoke(async (useVersion, testAsync, parametersString) => { ActivitySource.AddActivityListener(new ActivityListener { - ShouldListenTo = _ => true, + ShouldListenTo = s => s.Name is "System.Net.Http" or "", Sample = (ref ActivityCreationOptions _) => { madeASamplingDecision = true; @@ -1032,7 +1153,7 @@ await RemoteExecutor.Invoke(async (useVersion, testAsync, parametersString) => // (when a DiagnosticListener forced one to be created) ActivitySource.AddActivityListener(new ActivityListener { - ShouldListenTo = _ => true, + ShouldListenTo = s => s.Name is "System.Net.Http" or "", ActivityStarted = created => { Assert.Null(parent); @@ -1071,8 +1192,8 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( Assert.Equal(activitySourceCreatesActivity.HasValue, madeASamplingDecision); Assert.Equal(diagnosticListenerActivityEnabled.HasValue, listenerCallbackWasCalled); - }, UseVersion.ToString(), TestAsync.ToString(), parameters).DisposeAsync(); - } + }, UseVersion.ToString(), TestAsync.ToString(), parameters).DisposeAsync(); + } private static T GetProperty(object obj, string propertyName) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index e60a55edf0a04..dfd7d0652c1d6 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -78,6 +78,8 @@ Link="CommonTest\System\Security\Cryptography\X509Certificates\CertificateAuthority.cs" /> + Gets the host name of the local machine. public static string GetHostName() { - long startingTimestamp = NameResolutionTelemetry.Log.BeforeResolution(string.Empty); + NameResolutionActivity activity = NameResolutionTelemetry.Log.BeforeResolution(string.Empty); string name; try { name = NameResolutionPal.GetHostName(); } - catch (Exception ex) when (LogFailure(string.Empty, startingTimestamp, ex)) + catch (Exception ex) when (LogFailure(string.Empty, activity, ex)) { Debug.Fail("LogFailure should return false"); throw; } - NameResolutionTelemetry.Log.AfterResolution(string.Empty, startingTimestamp); + NameResolutionTelemetry.Log.AfterResolution(string.Empty, activity); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(null, name); return name; @@ -155,8 +155,8 @@ public static Task GetHostEntryAsync(IPAddress address) throw new ArgumentException(SR.net_invalid_ip_addr, nameof(address)); } - return RunAsync(static (s, startingTimestamp) => { - IPHostEntry ipHostEntry = GetHostEntryCore((IPAddress)s, AddressFamily.Unspecified, startingTimestamp); + return RunAsync(static (s, activity) => { + IPHostEntry ipHostEntry = GetHostEntryCore((IPAddress)s, AddressFamily.Unspecified, activity); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info((IPAddress)s, $"{ipHostEntry} with {ipHostEntry.AddressList.Length} entries"); return ipHostEntry; }, address, CancellationToken.None); @@ -361,18 +361,18 @@ public static IPHostEntry EndResolve(IAsyncResult asyncResult) return ipHostEntry; } - private static IPHostEntry GetHostEntryCore(string hostName, AddressFamily addressFamily, long? startingTimestamp = null) => - (IPHostEntry)GetHostEntryOrAddressesCore(hostName, justAddresses: false, addressFamily, startingTimestamp); + private static IPHostEntry GetHostEntryCore(string hostName, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) => + (IPHostEntry)GetHostEntryOrAddressesCore(hostName, justAddresses: false, addressFamily, activityOrDefault); - private static IPAddress[] GetHostAddressesCore(string hostName, AddressFamily addressFamily, long? startingTimestamp = null) => - (IPAddress[])GetHostEntryOrAddressesCore(hostName, justAddresses: true, addressFamily, startingTimestamp); + private static IPAddress[] GetHostAddressesCore(string hostName, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) => + (IPAddress[])GetHostEntryOrAddressesCore(hostName, justAddresses: true, addressFamily, activityOrDefault); - private static object GetHostEntryOrAddressesCore(string hostName, bool justAddresses, AddressFamily addressFamily, long? startingTimestamp = null) + private static object GetHostEntryOrAddressesCore(string hostName, bool justAddresses, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) { ValidateHostName(hostName); - // startingTimestamp may have already been set if we're being called from RunAsync. - startingTimestamp ??= NameResolutionTelemetry.Log.BeforeResolution(hostName); + // NameResolutionActivity may have already been set if we're being called from RunAsync. + NameResolutionActivity activity = activityOrDefault ?? NameResolutionTelemetry.Log.BeforeResolution(hostName); object result; try @@ -394,33 +394,33 @@ private static object GetHostEntryOrAddressesCore(string hostName, bool justAddr Aliases = aliases }; } - catch (Exception ex) when (LogFailure(hostName, startingTimestamp, ex)) + catch (Exception ex) when (LogFailure(hostName, activity, ex)) { Debug.Fail("LogFailure should return false"); throw; } - NameResolutionTelemetry.Log.AfterResolution(hostName, startingTimestamp); + NameResolutionTelemetry.Log.AfterResolution(hostName, activity); return result; } - private static IPHostEntry GetHostEntryCore(IPAddress address, AddressFamily addressFamily, long? startingTimestamp = null) => - (IPHostEntry)GetHostEntryOrAddressesCore(address, justAddresses: false, addressFamily, startingTimestamp); + private static IPHostEntry GetHostEntryCore(IPAddress address, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) => + (IPHostEntry)GetHostEntryOrAddressesCore(address, justAddresses: false, addressFamily, activityOrDefault); - private static IPAddress[] GetHostAddressesCore(IPAddress address, AddressFamily addressFamily, long? startingTimestamp = null) => - (IPAddress[])GetHostEntryOrAddressesCore(address, justAddresses: true, addressFamily, startingTimestamp); + private static IPAddress[] GetHostAddressesCore(IPAddress address, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) => + (IPAddress[])GetHostEntryOrAddressesCore(address, justAddresses: true, addressFamily, activityOrDefault); // Does internal IPAddress reverse and then forward lookups (for Legacy and current public methods). - private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAddresses, AddressFamily addressFamily, long? startingTimestamp = null) + private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAddresses, AddressFamily addressFamily, NameResolutionActivity? activityOrDefault = default) { // Try to get the data for the host from its address. // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string // will only return that address and not the full list. // Do a reverse lookup to get the host name. - // startingTimestamp may have already been set if we're being called from RunAsync. - startingTimestamp ??= NameResolutionTelemetry.Log.BeforeResolution(address); + // NameResolutionActivity may have already been set if we're being called from RunAsync. + NameResolutionActivity activity = activityOrDefault ?? NameResolutionTelemetry.Log.BeforeResolution(address); SocketError errorCode; string? name; @@ -434,16 +434,16 @@ private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAd } Debug.Assert(name != null); } - catch (Exception ex) when (LogFailure(address, startingTimestamp, ex)) + catch (Exception ex) when (LogFailure(address, activity, ex)) { Debug.Fail("LogFailure should return false"); throw; } - NameResolutionTelemetry.Log.AfterResolution(address, startingTimestamp); + NameResolutionTelemetry.Log.AfterResolution(address, activity); // Do the forward lookup to get the IPs for that host name - startingTimestamp = NameResolutionTelemetry.Log.BeforeResolution(name); + activity = NameResolutionTelemetry.Log.BeforeResolution(name); object result; try @@ -464,13 +464,13 @@ private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAd AddressList = addresses }; } - catch (Exception ex) when (LogFailure(name, startingTimestamp, ex)) + catch (Exception ex) when (LogFailure(name, activity, ex)) { Debug.Fail("LogFailure should return false"); throw; } - NameResolutionTelemetry.Log.AfterResolution(name, startingTimestamp); + NameResolutionTelemetry.Log.AfterResolution(name, activity); // One of three things happened: // 1. Success. @@ -530,7 +530,7 @@ private static Task GetHostEntryOrAddressesCoreAsync(string hostName, bool justR ValidateHostName(hostName); Task? t; - if (NameResolutionTelemetry.Log.IsEnabled() || NameResolutionMetrics.IsEnabled()) + if (NameResolutionTelemetry.AnyDiagnosticsEnabled()) { t = justAddresses ? GetAddrInfoWithTelemetryAsync(hostName, justAddresses, family, cancellationToken) @@ -554,23 +554,23 @@ private static Task GetHostEntryOrAddressesCoreAsync(string hostName, bool justR if (justAddresses) { - return RunAsync(static (s, startingTimestamp) => s switch + return RunAsync(static (s, activity) => s switch { - string h => GetHostAddressesCore(h, AddressFamily.Unspecified, startingTimestamp), - KeyValuePair t => GetHostAddressesCore(t.Key, t.Value, startingTimestamp), - IPAddress a => GetHostAddressesCore(a, AddressFamily.Unspecified, startingTimestamp), - KeyValuePair t => GetHostAddressesCore(t.Key, t.Value, startingTimestamp), + string h => GetHostAddressesCore(h, AddressFamily.Unspecified, activity), + KeyValuePair t => GetHostAddressesCore(t.Key, t.Value, activity), + IPAddress a => GetHostAddressesCore(a, AddressFamily.Unspecified, activity), + KeyValuePair t => GetHostAddressesCore(t.Key, t.Value, activity), _ => null }, asyncState, cancellationToken); } else { - return RunAsync(static (s, startingTimestamp) => s switch + return RunAsync(static (s, activity) => s switch { - string h => GetHostEntryCore(h, AddressFamily.Unspecified, startingTimestamp), - KeyValuePair t => GetHostEntryCore(t.Key, t.Value, startingTimestamp), - IPAddress a => GetHostEntryCore(a, AddressFamily.Unspecified, startingTimestamp), - KeyValuePair t => GetHostEntryCore(t.Key, t.Value, startingTimestamp), + string h => GetHostEntryCore(h, AddressFamily.Unspecified, activity), + KeyValuePair t => GetHostEntryCore(t.Key, t.Value, activity), + IPAddress a => GetHostEntryCore(a, AddressFamily.Unspecified, activity), + KeyValuePair t => GetHostEntryCore(t.Key, t.Value, activity), _ => null }, asyncState, cancellationToken); } @@ -591,9 +591,9 @@ private static Task GetHostEntryOrAddressesCoreAsync(string hostName, bool justR // We will retry on thread-pool. return null; - static async Task CompleteAsync(Task task, string hostName, long startingTimestamp) + static async Task CompleteAsync(Task task, string hostName, long startingTimeStamp) { - _ = NameResolutionTelemetry.Log.BeforeResolution(hostName); + NameResolutionActivity activity = NameResolutionTelemetry.Log.BeforeResolution(hostName, startingTimeStamp); Exception? exception = null; try { @@ -606,7 +606,7 @@ static async Task CompleteAsync(Task task, string hostName, long startingTime } finally { - NameResolutionTelemetry.Log.AfterResolution(hostName, startingTimestamp, exception); + NameResolutionTelemetry.Log.AfterResolution(hostName, activity, exception); } } } @@ -631,9 +631,9 @@ private static void ValidateHostName(string hostName) } } - private static bool LogFailure(object hostNameOrAddress, long? startingTimestamp, Exception exception) + private static bool LogFailure(object hostNameOrAddress, in NameResolutionActivity activity, Exception exception) { - NameResolutionTelemetry.Log.AfterResolution(hostNameOrAddress, startingTimestamp, exception); + NameResolutionTelemetry.Log.AfterResolution(hostNameOrAddress, activity, exception); return false; } @@ -651,9 +651,15 @@ private static bool LogFailure(object hostNameOrAddress, long? startingTimestamp /// than having all concurrent requests for the same host share the exact same task, so that any shuffling of the results /// by the OS to enable round robin is still perceived. /// - private static Task RunAsync(Func func, object key, CancellationToken cancellationToken) + private static Task RunAsync(Func func, object key, CancellationToken cancellationToken) { - long startingTimestamp = NameResolutionTelemetry.Log.BeforeResolution(key); + Activity? activityToRestore = NameResolutionActivity.IsTracingEnabled() ? Activity.Current : null; + NameResolutionActivity activity = NameResolutionTelemetry.Log.BeforeResolution(key); + if (NameResolutionActivity.IsTracingEnabled()) + { + // Do not overwrite Activity.Current in the caller's ExecutionContext. + Activity.Current = activityToRestore; + } Task? task = null; @@ -670,7 +676,7 @@ private static Task RunAsync(Func func, Debug.Assert(!Monitor.IsEntered(s_tasks)); try { - return func(key, startingTimestamp); + return func(key, activity); } finally { diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 73ed325712ac5..3c033821080cb 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -9,6 +9,38 @@ namespace System.Net { + internal readonly struct NameResolutionActivity + { + private const string ActivitySourceName = "System.Net.NameResolution"; + private const string ActivityName = ActivitySourceName + ".DsnLookup"; + private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + + // _startingTimestamp == 0 means NameResolutionTelemetry and NameResolutionMetrics are both disabled. + private readonly long _startingTimestamp; + private readonly Activity? _activity; + + public NameResolutionActivity(long startingTimestamp) + { + _startingTimestamp = startingTimestamp; + _activity = s_activitySource.StartActivity(ActivityName, ActivityKind.Client); + } + + public static bool IsTracingEnabled() => s_activitySource.HasListeners(); + + // Returns true if either NameResolutionTelemetry or NameResolutionMetrics is enabled. + public bool Stop(out TimeSpan duration) + { + _activity?.Stop(); + if (_startingTimestamp == 0) + { + duration = default; + return false; + } + duration = Stopwatch.GetElapsedTime(_startingTimestamp); + return true; + } + } + [EventSource(Name = "System.Net.NameResolution")] internal sealed class NameResolutionTelemetry : EventSource { @@ -58,10 +90,17 @@ protected override void OnEventCommand(EventCommandEventArgs command) [Event(ResolutionFailedEventId, Level = EventLevel.Informational)] private void ResolutionFailed() => WriteEvent(ResolutionFailedEventId); + [NonEvent] + public static bool AnyDiagnosticsEnabled() => Log.IsEnabled() || NameResolutionMetrics.IsEnabled() || NameResolutionActivity.IsTracingEnabled(); [NonEvent] - public long BeforeResolution(object hostNameOrAddress) + public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long startingTimestamp = 0) { + if (!AnyDiagnosticsEnabled()) + { + return default; + } + if (IsEnabled()) { Interlocked.Increment(ref _lookupsRequested); @@ -74,23 +113,21 @@ public long BeforeResolution(object hostNameOrAddress) ResolutionStart(host); } - return Stopwatch.GetTimestamp(); + return new(startingTimestamp is not 0 ? startingTimestamp : Stopwatch.GetTimestamp()); } - return NameResolutionMetrics.IsEnabled() ? Stopwatch.GetTimestamp() : 0; + return new(startingTimestamp is not 0 ? startingTimestamp : NameResolutionMetrics.IsEnabled() ? Stopwatch.GetTimestamp() : 0); } [NonEvent] - public void AfterResolution(object hostNameOrAddress, long? startingTimestamp, Exception? exception = null) + public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, Exception? exception = null) { - Debug.Assert(startingTimestamp.HasValue); - if (startingTimestamp == 0) + if (!activity.Stop(out TimeSpan duration)) { + // We stopped the System.Diagnostics.Activity at this point and neither metrics nor EventSource is enabled. return; } - TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp.Value); - if (IsEnabled()) { Interlocked.Decrement(ref _currentLookups); diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs new file mode 100644 index 0000000000000..4119a835974f4 --- /dev/null +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.Net.NameResolution.Tests +{ + public class ActivityTest + { + private const string ActivitySourceName = "System.Net.NameResolution"; + private const string ActivityName = ActivitySourceName + ".DsnLookup"; + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public async Task ResolveValidHostName_ActivityRecorded(bool createParentActivity) + { + await RemoteExecutor.Invoke(static async (createParentActivity) => + { + const string ValidHostName = "localhost"; + using var recorder = new ActivityRecorder(ActivitySourceName, ActivityName) + { + ExpectedParent = bool.Parse(createParentActivity) ? new Activity("parent").Start() : null + }; + + await Dns.GetHostEntryAsync(ValidHostName); + recorder.VerifyActivityRecorded(times: 1); + + await Dns.GetHostAddressesAsync(ValidHostName); + recorder.VerifyActivityRecorded(times: 2); + + Dns.GetHostEntry(ValidHostName); + recorder.VerifyActivityRecorded(times: 3); + + Dns.GetHostAddresses(ValidHostName); + recorder.VerifyActivityRecorded(times: 4); + + Dns.EndGetHostEntry(Dns.BeginGetHostEntry(ValidHostName, null, null)); + recorder.VerifyActivityRecorded(times: 5); + + Dns.EndGetHostAddresses(Dns.BeginGetHostAddresses(ValidHostName, null, null)); + recorder.VerifyActivityRecorded(times: 6); + + }, createParentActivity.ToString()).DisposeAsync(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public static async Task ResolveInvalidHostName_ActivityRecorded(bool createParentActivity) + { + const string InvalidHostName = $"invalid...example.com...{nameof(ResolveInvalidHostName_ActivityRecorded)}"; + + await RemoteExecutor.Invoke(async (createParentActivity) => + { + using var recorder = new ActivityRecorder(ActivitySourceName, ActivityName) + { + ExpectedParent = bool.Parse(createParentActivity) ? new Activity("parent").Start() : null + }; + + await Assert.ThrowsAnyAsync(async () => await Dns.GetHostEntryAsync(InvalidHostName)); + await Assert.ThrowsAnyAsync(async () => await Dns.GetHostAddressesAsync(InvalidHostName)); + + Assert.ThrowsAny(() => Dns.GetHostEntry(InvalidHostName)); + Assert.ThrowsAny(() => Dns.GetHostAddresses(InvalidHostName)); + + Assert.ThrowsAny(() => Dns.EndGetHostEntry(Dns.BeginGetHostEntry(InvalidHostName, null, null))); + Assert.ThrowsAny(() => Dns.EndGetHostAddresses(Dns.BeginGetHostAddresses(InvalidHostName, null, null))); + + recorder.VerifyActivityRecorded(times: 6); + }, createParentActivity.ToString()).DisposeAsync(); + } + } +} diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj index ff009e7b84326..182e5d9eba19b 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj @@ -6,6 +6,7 @@ true + @@ -20,6 +21,8 @@ + + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 5a01ee065c2b5..f4949c6ddb151 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -15,6 +15,11 @@ namespace System.Net.Security { public partial class SslStream { + private const string ActivitySourceName = "System.Net.Security"; + private const string ActivityName = ActivitySourceName + ".TlsHandshake"; + + private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + private readonly SslAuthenticationOptions _sslAuthenticationOptions = new SslAuthenticationOptions(); private int _nestedAuth; private bool _isRenego; @@ -106,15 +111,23 @@ private Task ProcessAuthenticationAsync(bool isAsync = false, CancellationToken { ThrowIfExceptional(); - if (NetSecurityTelemetry.Log.IsEnabled()) + Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); + try { - return ProcessAuthenticationWithTelemetryAsync(isAsync, cancellationToken); + if (NetSecurityTelemetry.Log.IsEnabled()) + { + return ProcessAuthenticationWithTelemetryAsync(isAsync, cancellationToken); + } + else + { + return isAsync ? + ForceAuthenticationAsync(IsServer, null, cancellationToken) : + ForceAuthenticationAsync(IsServer, null, cancellationToken); + } } - else + finally { - return isAsync ? - ForceAuthenticationAsync(IsServer, null, cancellationToken) : - ForceAuthenticationAsync(IsServer, null, cancellationToken); + activity?.Stop(); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 5fffd852c7506..265e17f245159 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -53,6 +53,8 @@ Link="Common\System\IO\DelegateStream.cs" /> + + { + using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName); + + var test = new SslStreamStreamToStreamTest_Async(); + await test.SslStream_StreamToStream_Authentication_Success(); + + recorder.VerifyActivityRecorded(2); // client + server + }).DisposeAsync(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public async Task FailingHandshake_ActivityRecorded() + { + await RemoteExecutor.Invoke(async () => + { + using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName); + + var test = new SslStreamStreamToStreamTest_Async(); + await test.SslStream_ServerLocalCertificateSelectionCallbackReturnsNull_Throw(); + + recorder.VerifyActivityRecorded(2); // client + server + }).DisposeAsync(); + } + [OuterLoop] [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "X509 certificate store is not supported on iOS or tvOS.")] // Match SslStream_StreamToStream_Authentication_Success diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index ced52a7f14f7e..5198e80906163 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -292,6 +292,7 @@ + diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index c8df9f89c4a03..e3d6af0e795db 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2782,7 +2782,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan WildcardBindForConnectIfNecessary(endPointSnapshot.AddressFamily); - SocketsTelemetry.Log.ConnectStart(e._socketAddress!); + e._activity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, keepActivityCurrent: true); // Prepare for the native call. try @@ -2792,7 +2792,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, ex.Message); + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._activity, ex.Message); + e._activity = null; throw; } @@ -2808,7 +2809,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, ex.Message); + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._activity, ex.Message); + e._activity = null; _localEndPoint = null; @@ -3189,7 +3191,7 @@ private SocketAddress Serialize(ref EndPoint remoteEP) private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) { - SocketsTelemetry.Log.ConnectStart(socketAddress); + Activity? activity = SocketsTelemetry.Log.ConnectStart(socketAddress, keepActivityCurrent: false); SocketError errorCode; try { @@ -3197,7 +3199,7 @@ private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, ex.Message); + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, activity, ex.Message); throw; } @@ -3210,12 +3212,12 @@ private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) UpdateStatusAfterSocketError(socketException); if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, socketException); - SocketsTelemetry.Log.AfterConnect(errorCode); + SocketsTelemetry.Log.AfterConnect(errorCode, activity); throw socketException; } - SocketsTelemetry.Log.AfterConnect(SocketError.Success); + SocketsTelemetry.Log.AfterConnect(SocketError.Success, activity); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"connection to:{endPointSnapshot}"); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index 78dd22e5eda7b..d22feee4feced 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -74,6 +74,7 @@ public partial class SocketAsyncEventArgs : EventArgs, IDisposable private Socket? _currentSocket; private bool _userSocket; // if false when performing Connect, _currentSocket should be disposed private bool _disposeCalled; + internal Activity? _activity; // Controls thread safety via Interlocked. private const int Configuring = -1; @@ -224,7 +225,8 @@ private void AfterConnectAcceptTelemetry() break; case SocketAsyncOperation.Connect: - SocketsTelemetry.Log.AfterConnect(SocketError); + SocketsTelemetry.Log.AfterConnect(SocketError, _activity); + _activity = null; break; default: diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index bea730b47b162..9500fd995f408 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -10,6 +10,10 @@ namespace System.Net.Sockets [EventSource(Name = "System.Net.Sockets")] internal sealed class SocketsTelemetry : EventSource { + private const string ActivitySourceName = "System.Net.Sockets"; + private const string ConnectActivityName = ActivitySourceName + ".Connect"; + private static readonly ActivitySource s_connectActivitySource = new(ActivitySourceName); + public static readonly SocketsTelemetry Log = new SocketsTelemetry(); private PollingCounter? _currentOutgoingConnectAttemptsCounter; @@ -77,7 +81,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) } [NonEvent] - public void ConnectStart(SocketAddress address) + public Activity? ConnectStart(SocketAddress address, bool keepActivityCurrent) { Interlocked.Increment(ref _currentOutgoingConnectAttempts); @@ -85,14 +89,30 @@ public void ConnectStart(SocketAddress address) { ConnectStart(address.ToString()); } + + Activity? activity = null; + if (s_connectActivitySource.HasListeners()) + { + Activity? activityToReset = keepActivityCurrent ? Activity.Current : null; + activity = s_connectActivitySource.StartActivity(ConnectActivityName); + if (keepActivityCurrent) + { + // Do not overwrite Activity.Current in the caller's ExecutionContext. + Activity.Current = activityToReset; + } + } + + return activity; } [NonEvent] - public void AfterConnect(SocketError error, string? exceptionMessage = null) + public void AfterConnect(SocketError error, Activity? activity, string? exceptionMessage = null) { long newCount = Interlocked.Decrement(ref _currentOutgoingConnectAttempts); Debug.Assert(newCount >= 0); + activity?.Stop(); + if (error == SocketError.Success) { Debug.Assert(exceptionMessage is null); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index cc57803fa1c50..02ba46be4f07a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -78,6 +78,8 @@ + > s_remoteServerIsReachable = new Lazy>(() => Task.Run(async () => { try @@ -104,6 +109,63 @@ private static SocketHelperBase GetHelperBase(string socketMethod) }; } + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(nameof(SocketMethods_MemberData))] + public async Task Connect_Success_ActivityRecorded(string connectMethod) + { + await RemoteExecutor.Invoke(async connectMethod => + { + using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + server.BindToAnonymousPort(IPAddress.Loopback); + server.Listen(); + + Activity parent = new Activity("parent").Start(); + + using Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName) + { + ExpectedParent = parent + }; + + Task connectTask = GetHelperBase(connectMethod).ConnectAsync(client, server.LocalEndPoint); + await server.AcceptAsync(); + await connectTask; + + recorder.VerifyActivityRecorded(1); + Assert.Same(parent, Activity.Current); + parent.Stop(); + }, connectMethod).DisposeAsync(); + } + + [OuterLoop("Connection failure takes long on Windows.")] + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [MemberData(nameof(SocketMethods_MemberData))] + public async Task Connect_Failure_ActivityRecorded(string connectMethod) + { + await RemoteExecutor.Invoke(async connectMethod => + { + using Socket notListening = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + notListening.BindToAnonymousPort(IPAddress.Loopback); + + Activity parent = new Activity("parent").Start(); + + using Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName) + { + ExpectedParent = parent + }; + + await Assert.ThrowsAsync(() =>GetHelperBase(connectMethod) + .ConnectAsync(client, notListening.LocalEndPoint)); + + recorder.VerifyActivityRecorded(1); + Assert.Same(parent, Activity.Current); + parent.Stop(); + }, connectMethod).DisposeAsync(); + } + [OuterLoop] [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [MemberData(nameof(SocketMethods_Matrix_MemberData))] From 3945fe45a1690dd39e784536e813b735f62e016f Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 25 Jun 2024 18:23:08 +0200 Subject: [PATCH 02/37] address review feedback --- .../ConnectionPool/HttpConnectionPool.cs | 3 +- .../src/System/Net/Dns.cs | 5 +- .../src/System/Net/Security/SslStream.IO.cs | 56 +++++++++++-------- .../tests/FunctionalTests/TelemetryTest.cs | 15 +++-- 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index 8df77b18e3246..01783daf8ec9d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -677,10 +677,9 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt } else { - IPAddress[] addresses = Dns.GetHostAddresses(host); using (cancellationToken.UnsafeRegister(static s => ((Socket)s!).Dispose(), socket)) { - socket.Connect(addresses, port); + socket.Connect(endPoint); } } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs index 779f2e770ec43..c9e70f9729482 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs @@ -653,9 +653,10 @@ private static bool LogFailure(object hostNameOrAddress, in NameResolutionActivi /// private static Task RunAsync(Func func, object key, CancellationToken cancellationToken) { - Activity? activityToRestore = NameResolutionActivity.IsTracingEnabled() ? Activity.Current : null; + bool tracingEnabled = NameResolutionActivity.IsTracingEnabled(); + Activity? activityToRestore = tracingEnabled ? Activity.Current : null; NameResolutionActivity activity = NameResolutionTelemetry.Log.BeforeResolution(key); - if (NameResolutionActivity.IsTracingEnabled()) + if (tracingEnabled) { // Do not overwrite Activity.Current in the caller's ExecutionContext. Activity.Current = activityToRestore; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index f4949c6ddb151..c37f02ad2e311 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -111,30 +111,32 @@ private Task ProcessAuthenticationAsync(bool isAsync = false, CancellationToken { ThrowIfExceptional(); - Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); - try + if (NetSecurityTelemetry.Log.IsEnabled() || s_activitySource.HasListeners()) { - if (NetSecurityTelemetry.Log.IsEnabled()) - { - return ProcessAuthenticationWithTelemetryAsync(isAsync, cancellationToken); - } - else - { - return isAsync ? - ForceAuthenticationAsync(IsServer, null, cancellationToken) : - ForceAuthenticationAsync(IsServer, null, cancellationToken); - } + return ProcessAuthenticationWithTelemetryAsync(isAsync, cancellationToken); } - finally + else { - activity?.Stop(); + return isAsync ? + ForceAuthenticationAsync(IsServer, null, cancellationToken) : + ForceAuthenticationAsync(IsServer, null, cancellationToken); } } private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, CancellationToken cancellationToken) { - NetSecurityTelemetry.Log.HandshakeStart(IsServer, _sslAuthenticationOptions.TargetHost); - long startingTimestamp = Stopwatch.GetTimestamp(); + long startingTimestamp; + if (NetSecurityTelemetry.Log.IsEnabled()) + { + NetSecurityTelemetry.Log.HandshakeStart(IsServer, _sslAuthenticationOptions.TargetHost); + startingTimestamp = Stopwatch.GetTimestamp(); + } + else + { + startingTimestamp = 0; + } + + Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); try { @@ -144,17 +146,27 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell await task.ConfigureAwait(false); - // SslStream could already have been disposed at this point, in which case _connectionOpenedStatus == 2 - // Make sure that we increment the open connection counter only if it is guaranteed to be decremented in dispose/finalize - bool connectionOpen = Interlocked.CompareExchange(ref _connectionOpenedStatus, 1, 0) == 0; - - NetSecurityTelemetry.Log.HandshakeCompleted(GetSslProtocolInternal(), startingTimestamp, connectionOpen); + if (startingTimestamp is not 0) + { + // SslStream could already have been disposed at this point, in which case _connectionOpenedStatus == 2 + // Make sure that we increment the open connection counter only if it is guaranteed to be decremented in dispose/finalize + bool connectionOpen = Interlocked.CompareExchange(ref _connectionOpenedStatus, 1, 0) == 0; + NetSecurityTelemetry.Log.HandshakeCompleted(GetSslProtocolInternal(), startingTimestamp, connectionOpen); + } } catch (Exception ex) { - NetSecurityTelemetry.Log.HandshakeFailed(IsServer, startingTimestamp, ex.Message); + if (startingTimestamp is not 0) + { + NetSecurityTelemetry.Log.HandshakeFailed(IsServer, startingTimestamp, ex.Message); + } + throw; } + finally + { + activity?.Stop(); + } } // diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs index 3b3c502c587cb..a7b45de76323b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs @@ -31,19 +31,24 @@ public static void EventSource_ExistsWithCorrectId() Assert.NotEmpty(EventSource.GenerateManifest(esType, esType.Assembly.Location)); } - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "X509 certificate store is not supported on iOS or tvOS.")] // Match SslStream_StreamToStream_Authentication_Success - public async Task SuccessfulHandshake_ActivityRecorded() + [InlineData(false)] + [InlineData(true)] + public async Task SuccessfulHandshake_ActivityRecorded(bool synchronousApi) { - await RemoteExecutor.Invoke(async () => + await RemoteExecutor.Invoke(async synchronousApiStr => { using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName); - var test = new SslStreamStreamToStreamTest_Async(); + SslStreamStreamToStreamTest test = bool.Parse(synchronousApiStr) + ? new SslStreamStreamToStreamTest_SyncParameters() + : new SslStreamStreamToStreamTest_Async(); await test.SslStream_StreamToStream_Authentication_Success(); recorder.VerifyActivityRecorded(2); // client + server - }).DisposeAsync(); + Assert.True(recorder.LastFinishedActivity.Duration > TimeSpan.Zero); + }, synchronousApi.ToString()).DisposeAsync(); } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] From 08bc61173e051354ea4d7c8de9ad4385c7ac5050 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 25 Jun 2024 19:36:34 +0200 Subject: [PATCH 03/37] resolve conflicts --- .../Net/Http/SocketsHttpHandler/Http3Connection.cs | 2 +- .../Net/Http/SocketsHttpHandler/HttpConnectionBase.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index c00071ac3897c..9a864b455b6df 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -91,7 +91,7 @@ public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, bool in public void InitQuicConnection(QuicConnection connection) { - MarkConnectionAsEstablished(connection.RemoteEndPoint); + MarkConnectionAsEstablished(activity: null, remoteEndPoint: connection.RemoteEndPoint); _connection = connection; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index fa339b8a06b42..5067aa225118e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -24,7 +24,7 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace // May be null if none of the counters were enabled when the connection was established. private ConnectionMetrics? _connectionMetrics; - protected readonly Activity? _activity; + protected Activity? _activity; // Indicates whether we've counted this connection as established, so that we can // avoid decrementing the counter once it's closed in case telemetry was enabled in between. @@ -46,14 +46,15 @@ public HttpConnectionBase(HttpConnectionPool pool) Debug.Assert(pool != null); _pool = pool; } - public HttpConnectionBase(HttpConnectionPool pool, IPEndPoint? remoteEndPoint) + public HttpConnectionBase(HttpConnectionPool pool, Activity? activity, IPEndPoint? remoteEndPoint) : this(pool) { - MarkConnectionAsEstablished(remoteEndPoint); + MarkConnectionAsEstablished(activity, remoteEndPoint); } - protected void MarkConnectionAsEstablished(IPEndPoint? remoteEndPoint) + protected void MarkConnectionAsEstablished(Activity? activity, IPEndPoint? remoteEndPoint) { + _activity = activity; Debug.Assert(_pool.Settings._metrics is not null); SocketsHttpHandlerMetrics metrics = _pool.Settings._metrics; From e2cf15e87573a060c36de50fd0d38b9bfde9bf18 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 25 Jun 2024 19:53:13 +0200 Subject: [PATCH 04/37] get rid of finally block --- .../src/System/Net/Security/SslStream.IO.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index c37f02ad2e311..cb0bc129cdb4a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -136,7 +136,7 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell startingTimestamp = 0; } - Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); + using Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); try { @@ -163,10 +163,6 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell throw; } - finally - { - activity?.Stop(); - } } // From 5119f9cd7f4214b53632a2928597d1659d543b89 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 5 Jul 2024 23:11:54 +0200 Subject: [PATCH 05/37] System.Net.NameResolution: record tags and ActivityStatusCode --- .../tests/System/Net/ActivityRecorder.cs | 3 - .../src/System/Net/Dns.cs | 16 ++- .../src/System/Net/NameResolutionMetrics.cs | 15 +- .../src/System/Net/NameResolutionTelemetry.cs | 135 +++++++++++++----- .../tests/FunctionalTests/ActivityTest.cs | 47 +++++- 5 files changed, 151 insertions(+), 65 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs index d2a155985be5e..39f1a9ab656ed 100644 --- a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -1,11 +1,8 @@ // 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.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Threading; using Xunit; namespace System.Net.Test.Common diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs index c9e70f9729482..1b45e5d47e28d 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs @@ -29,7 +29,7 @@ public static string GetHostName() throw; } - NameResolutionTelemetry.Log.AfterResolution(string.Empty, activity); + NameResolutionTelemetry.Log.AfterResolution(string.Empty, activity, answer: name); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(null, name); return name; @@ -400,7 +400,7 @@ private static object GetHostEntryOrAddressesCore(string hostName, bool justAddr throw; } - NameResolutionTelemetry.Log.AfterResolution(hostName, activity); + NameResolutionTelemetry.Log.AfterResolution(hostName, activity, answer: result); return result; } @@ -440,7 +440,7 @@ private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAd throw; } - NameResolutionTelemetry.Log.AfterResolution(address, activity); + NameResolutionTelemetry.Log.AfterResolution(address, activity, answer: name); // Do the forward lookup to get the IPs for that host name activity = NameResolutionTelemetry.Log.BeforeResolution(name); @@ -470,7 +470,7 @@ private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAd throw; } - NameResolutionTelemetry.Log.AfterResolution(name, activity); + NameResolutionTelemetry.Log.AfterResolution(name, activity, answer: result); // One of three things happened: // 1. Success. @@ -595,9 +595,11 @@ static async Task CompleteAsync(Task task, string hostName, long startingTime { NameResolutionActivity activity = NameResolutionTelemetry.Log.BeforeResolution(hostName, startingTimeStamp); Exception? exception = null; + T? result = null; try { - return await ((Task)task).ConfigureAwait(false); + result = await ((Task)task).ConfigureAwait(false); + return result; } catch (Exception ex) { @@ -606,7 +608,7 @@ static async Task CompleteAsync(Task task, string hostName, long startingTime } finally { - NameResolutionTelemetry.Log.AfterResolution(hostName, activity, exception); + NameResolutionTelemetry.Log.AfterResolution(hostName, activity, answer: result, exception: exception); } } } @@ -633,7 +635,7 @@ private static void ValidateHostName(string hostName) private static bool LogFailure(object hostNameOrAddress, in NameResolutionActivity activity, Exception exception) { - NameResolutionTelemetry.Log.AfterResolution(hostNameOrAddress, activity, exception); + NameResolutionTelemetry.Log.AfterResolution(hostNameOrAddress, activity, answer: null, exception: exception); return false; } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs index fe1048e90b22d..0deac114af36d 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs @@ -19,7 +19,7 @@ internal static class NameResolutionMetrics public static bool IsEnabled() => s_lookupDuration.Enabled; - public static void AfterResolution(TimeSpan duration, string hostName, Exception? exception) + public static void AfterResolution(TimeSpan duration, string hostName, string? errorType, Exception? exception) { var hostNameTag = KeyValuePair.Create("dns.question.name", (object?)hostName); @@ -29,19 +29,10 @@ public static void AfterResolution(TimeSpan duration, string hostName, Exception } else { - var errorTypeTag = KeyValuePair.Create("error.type", (object?)GetErrorType(exception)); + errorType ??= NameResolutionTelemetry.GetErrorType(exception); + var errorTypeTag = KeyValuePair.Create("error.type", (object?)errorType); s_lookupDuration.Record(duration.TotalSeconds, hostNameTag, errorTypeTag); } } - - private static string GetErrorType(Exception exception) => (exception as SocketException)?.SocketErrorCode switch - { - SocketError.HostNotFound => "host_not_found", - SocketError.TryAgain => "try_again", - SocketError.AddressFamilyNotSupported => "address_family_not_supported", - SocketError.NoRecovery => "no_recovery", - - _ => exception.GetType().FullName! - }; } } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 3c033821080cb..a31ac1c67f65c 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -9,38 +9,6 @@ namespace System.Net { - internal readonly struct NameResolutionActivity - { - private const string ActivitySourceName = "System.Net.NameResolution"; - private const string ActivityName = ActivitySourceName + ".DsnLookup"; - private static readonly ActivitySource s_activitySource = new(ActivitySourceName); - - // _startingTimestamp == 0 means NameResolutionTelemetry and NameResolutionMetrics are both disabled. - private readonly long _startingTimestamp; - private readonly Activity? _activity; - - public NameResolutionActivity(long startingTimestamp) - { - _startingTimestamp = startingTimestamp; - _activity = s_activitySource.StartActivity(ActivityName, ActivityKind.Client); - } - - public static bool IsTracingEnabled() => s_activitySource.HasListeners(); - - // Returns true if either NameResolutionTelemetry or NameResolutionMetrics is enabled. - public bool Stop(out TimeSpan duration) - { - _activity?.Stop(); - if (_startingTimestamp == 0) - { - duration = default; - return false; - } - duration = Stopwatch.GetElapsedTime(_startingTimestamp); - return true; - } - } - [EventSource(Name = "System.Net.NameResolution")] internal sealed class NameResolutionTelemetry : EventSource { @@ -120,9 +88,9 @@ public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long st } [NonEvent] - public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, Exception? exception = null) + public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, object? answer, Exception? exception = null) { - if (!activity.Stop(out TimeSpan duration)) + if (!activity.Stop(hostNameOrAddress, answer, exception, out TimeSpan duration, out string? errorType)) { // We stopped the System.Diagnostics.Activity at this point and neither metrics nor EventSource is enabled. return; @@ -147,11 +115,12 @@ public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity if (NameResolutionMetrics.IsEnabled()) { - NameResolutionMetrics.AfterResolution(duration, GetHostnameFromStateObject(hostNameOrAddress), exception); + NameResolutionMetrics.AfterResolution(duration, GetHostnameFromStateObject(hostNameOrAddress), errorType, exception); } } - private static string GetHostnameFromStateObject(object hostNameOrAddress) + [NonEvent] + internal static string GetHostnameFromStateObject(object hostNameOrAddress) { Debug.Assert(hostNameOrAddress is not null); @@ -168,5 +137,99 @@ private static string GetHostnameFromStateObject(object hostNameOrAddress) return host; } + + [NonEvent] + internal static string GetErrorType(Exception exception) => (exception as SocketException)?.SocketErrorCode switch + { + SocketError.HostNotFound => "host_not_found", + SocketError.TryAgain => "try_again", + SocketError.AddressFamilyNotSupported => "address_family_not_supported", + SocketError.NoRecovery => "no_recovery", + + _ => exception.GetType().FullName! + }; + } + + /// + /// Encapsulates the starting timestamp together with an optional Activity, to represent the name resolution span for various telemetry pillars. + /// + internal readonly struct NameResolutionActivity + { + private const string ActivitySourceName = "System.Net.NameResolution"; + private const string ActivityName = ActivitySourceName + ".DsnLookup"; + private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + + // _startingTimestamp == 0 means NameResolutionTelemetry and NameResolutionMetrics are both disabled. + private readonly long _startingTimestamp; + private readonly Activity? _activity; + + public NameResolutionActivity(long startingTimestamp) + { + _startingTimestamp = startingTimestamp; + _activity = s_activitySource.StartActivity(ActivityName, ActivityKind.Client); + } + + public static bool IsTracingEnabled() => s_activitySource.HasListeners(); + + // Returns true if either NameResolutionTelemetry or NameResolutionMetrics is enabled. + public bool Stop(object hostNameOrAddress, object? answer, Exception? exception, out TimeSpan duration, out string? errorType) + { + errorType = null; + if (_activity is not null) + { + if (_activity.IsAllDataRequested) + { + string host = NameResolutionTelemetry.GetHostnameFromStateObject(hostNameOrAddress); + + _activity.SetTag("dns.question.name", host); + + if (answer is not null) + { + string[]? answerValues = answer switch + { + string h => [h], + IPAddress[] addresses => GetStringValues(addresses), + IPHostEntry entry => GetStringValues(entry.AddressList), + _ => null + }; + + Debug.Assert(answerValues is not null); + _activity.SetTag("dns.answer", answerValues); + } + else + { + Debug.Assert(exception is not null); + errorType = NameResolutionTelemetry.GetErrorType(exception); + _activity.SetTag("error.type", errorType); + } + } + + if (exception is not null) + { + _activity.SetStatus(ActivityStatusCode.Error); + } + + _activity.Stop(); + } + + if (_startingTimestamp == 0) + { + duration = default; + return false; + } + + duration = Stopwatch.GetElapsedTime(_startingTimestamp); + return true; + + static string[] GetStringValues(IPAddress[] addresses) + { + string[] result = new string[addresses.Length]; + for (int i = 0; i < addresses.Length; i++) + { + result[i] = addresses[i].ToString(); + } + return result; + } + } } } diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs index 4119a835974f4..5b2e6d22c13a1 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs @@ -1,7 +1,9 @@ // 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.Diagnostics; +using System.Linq; using System.Net.Sockets; using System.Net.Test.Common; using System.Threading.Tasks; @@ -27,24 +29,37 @@ await RemoteExecutor.Invoke(static async (createParentActivity) => { ExpectedParent = bool.Parse(createParentActivity) ? new Activity("parent").Start() : null }; + + string expected4 = IPAddress.Loopback.ToString(); + string expected6 = IPAddress.IPv6Loopback.ToString(); await Dns.GetHostEntryAsync(ValidHostName); - recorder.VerifyActivityRecorded(times: 1); + Verify(1); await Dns.GetHostAddressesAsync(ValidHostName); - recorder.VerifyActivityRecorded(times: 2); + Verify(2); Dns.GetHostEntry(ValidHostName); - recorder.VerifyActivityRecorded(times: 3); + Verify(3); Dns.GetHostAddresses(ValidHostName); - recorder.VerifyActivityRecorded(times: 4); + Verify(4); Dns.EndGetHostEntry(Dns.BeginGetHostEntry(ValidHostName, null, null)); - recorder.VerifyActivityRecorded(times: 5); + Verify(5); Dns.EndGetHostAddresses(Dns.BeginGetHostAddresses(ValidHostName, null, null)); - recorder.VerifyActivityRecorded(times: 6); + Verify(6); + + void Verify(int timesLookupRecorded) + { + recorder.VerifyActivityRecorded(timesLookupRecorded); + + KeyValuePair[] tags = recorder.LastFinishedActivity.TagObjects.ToArray(); + Assert.Equal(ValidHostName, tags.Single(t => t.Key == "dns.question.name").Value); + string[] answers = Assert.IsType(tags.Single(t => t.Key == "dns.answer").Value); + Assert.True(answers.Contains(expected4) || answers.Contains(expected6)); + } }, createParentActivity.ToString()).DisposeAsync(); } @@ -64,15 +79,33 @@ await RemoteExecutor.Invoke(async (createParentActivity) => }; await Assert.ThrowsAnyAsync(async () => await Dns.GetHostEntryAsync(InvalidHostName)); + Verify(1); + await Assert.ThrowsAnyAsync(async () => await Dns.GetHostAddressesAsync(InvalidHostName)); + Verify(2); Assert.ThrowsAny(() => Dns.GetHostEntry(InvalidHostName)); + Verify(3); + Assert.ThrowsAny(() => Dns.GetHostAddresses(InvalidHostName)); + Verify(4); Assert.ThrowsAny(() => Dns.EndGetHostEntry(Dns.BeginGetHostEntry(InvalidHostName, null, null))); + Verify(5); + Assert.ThrowsAny(() => Dns.EndGetHostAddresses(Dns.BeginGetHostAddresses(InvalidHostName, null, null))); + Verify(6); + + void Verify(int timesLookupRecorded) + { + recorder.VerifyActivityRecorded(timesLookupRecorded); + + Assert.Equal(ActivityStatusCode.Error, recorder.LastFinishedActivity.Status); - recorder.VerifyActivityRecorded(times: 6); + KeyValuePair[] tags = recorder.LastFinishedActivity.TagObjects.ToArray(); + Assert.Equal(InvalidHostName, tags.Single(t => t.Key == "dns.question.name").Value); + Assert.Equal("host_not_found", tags.Single(t => t.Key == "error.type").Value); + } }, createParentActivity.ToString()).DisposeAsync(); } } From 4b1ffa8fd95c1dac90419708dd163bf120201f56 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Sat, 6 Jul 2024 01:32:34 +0200 Subject: [PATCH 06/37] set DNS activity DisplayName --- .../tests/System/Net/ActivityRecorder.cs | 41 +++++++++++++++++++ .../src/System/Net/NameResolutionTelemetry.cs | 26 +++++++----- .../tests/FunctionalTests/ActivityTest.cs | 28 ++++++++----- 3 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs index 39f1a9ab656ed..a5c4e4b98d470 100644 --- a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Linq; +using System.Text; using Xunit; namespace System.Net.Test.Common @@ -68,4 +69,44 @@ public void VerifyActivityRecorded(int times) Assert.Equal(times, Stopped); } } + + internal static class ActivityAssert + { + public static void HasTag(Activity activity, string name, T expectedValue) + { + T? value = (T?)activity.TagObjects.Single(t => t.Key == name).Value; + Assert.False(value is null, $"The Activity tags should contain {name}."); + Assert.Equal(expectedValue, value); + } + + public static void HasTag(Activity activity, string name, Func verifyValue) + { + T? value = (T?)activity.TagObjects.Single(t => t.Key == name).Value; + Assert.False(value is null, $"The Activity tags should contain {name}."); + Assert.True(verifyValue(value)); + } + + public static void HasNoTag(Activity activity, string name) + { + bool contains = activity.TagObjects.Any(t => t.Key == name); + Assert.False(contains, $"The Activity tags should not contain {name}."); + } + + public static string CamelToSnake(string camel) + { + if (string.IsNullOrEmpty(camel)) return camel; + StringBuilder bld = new(); + bld.Append(char.ToLower(camel[0])); + for (int i = 1; i < camel.Length; i++) + { + char c = camel[i]; + bld.Append(char.ToLower(c)); + if (char.IsUpper(c)) + { + bld.Append('_'); + } + } + return bld.ToString(); + } + } } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index a31ac1c67f65c..b8187b0019be3 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -81,16 +81,17 @@ public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long st ResolutionStart(host); } - return new(startingTimestamp is not 0 ? startingTimestamp : Stopwatch.GetTimestamp()); + startingTimestamp = startingTimestamp is not 0 ? startingTimestamp : Stopwatch.GetTimestamp(); } - return new(startingTimestamp is not 0 ? startingTimestamp : NameResolutionMetrics.IsEnabled() ? Stopwatch.GetTimestamp() : 0); + startingTimestamp = startingTimestamp is not 0 ? startingTimestamp : NameResolutionMetrics.IsEnabled() ? Stopwatch.GetTimestamp() : 0; + return new NameResolutionActivity(hostNameOrAddress, startingTimestamp); } [NonEvent] public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, object? answer, Exception? exception = null) { - if (!activity.Stop(hostNameOrAddress, answer, exception, out TimeSpan duration, out string? errorType)) + if (!activity.Stop(answer, exception, out TimeSpan duration, out string? errorType)) { // We stopped the System.Diagnostics.Activity at this point and neither metrics nor EventSource is enabled. return; @@ -156,33 +157,38 @@ internal static string GetHostnameFromStateObject(object hostNameOrAddress) internal readonly struct NameResolutionActivity { private const string ActivitySourceName = "System.Net.NameResolution"; - private const string ActivityName = ActivitySourceName + ".DsnLookup"; + private const string ActivityName = ActivitySourceName + ".DnsLookup"; private static readonly ActivitySource s_activitySource = new(ActivitySourceName); // _startingTimestamp == 0 means NameResolutionTelemetry and NameResolutionMetrics are both disabled. private readonly long _startingTimestamp; private readonly Activity? _activity; - public NameResolutionActivity(long startingTimestamp) + public NameResolutionActivity(object hostNameOrAddress, long startingTimestamp) { _startingTimestamp = startingTimestamp; _activity = s_activitySource.StartActivity(ActivityName, ActivityKind.Client); + if (_activity is not null) + { + string host = NameResolutionTelemetry.GetHostnameFromStateObject(hostNameOrAddress); + _activity.DisplayName = $"DNS {host}"; + if (_activity.IsAllDataRequested) + { + _activity.SetTag("dns.question.name", host); + } + } } public static bool IsTracingEnabled() => s_activitySource.HasListeners(); // Returns true if either NameResolutionTelemetry or NameResolutionMetrics is enabled. - public bool Stop(object hostNameOrAddress, object? answer, Exception? exception, out TimeSpan duration, out string? errorType) + public bool Stop(object? answer, Exception? exception, out TimeSpan duration, out string? errorType) { errorType = null; if (_activity is not null) { if (_activity.IsAllDataRequested) { - string host = NameResolutionTelemetry.GetHostnameFromStateObject(hostNameOrAddress); - - _activity.SetTag("dns.question.name", host); - if (answer is not null) { string[]? answerValues = answer switch diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs index 5b2e6d22c13a1..f15a3bc0c9221 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs @@ -15,7 +15,7 @@ namespace System.Net.NameResolution.Tests public class ActivityTest { private const string ActivitySourceName = "System.Net.NameResolution"; - private const string ActivityName = ActivitySourceName + ".DsnLookup"; + private const string ActivityName = ActivitySourceName + ".DnsLookup"; [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(false)] @@ -54,11 +54,10 @@ await RemoteExecutor.Invoke(static async (createParentActivity) => void Verify(int timesLookupRecorded) { recorder.VerifyActivityRecorded(timesLookupRecorded); - - KeyValuePair[] tags = recorder.LastFinishedActivity.TagObjects.ToArray(); - Assert.Equal(ValidHostName, tags.Single(t => t.Key == "dns.question.name").Value); - string[] answers = Assert.IsType(tags.Single(t => t.Key == "dns.answer").Value); - Assert.True(answers.Contains(expected4) || answers.Contains(expected6)); + Activity activity = recorder.LastFinishedActivity; + VerifyCommonActivityInfo(activity, ValidHostName); + ActivityAssert.HasTag(activity, "dns.answer", (string[] answers) => answers.Contains(expected4) || answers.Contains(expected6)); + ActivityAssert.HasNoTag(activity, "error.type"); } }, createParentActivity.ToString()).DisposeAsync(); @@ -100,13 +99,20 @@ void Verify(int timesLookupRecorded) { recorder.VerifyActivityRecorded(timesLookupRecorded); - Assert.Equal(ActivityStatusCode.Error, recorder.LastFinishedActivity.Status); - - KeyValuePair[] tags = recorder.LastFinishedActivity.TagObjects.ToArray(); - Assert.Equal(InvalidHostName, tags.Single(t => t.Key == "dns.question.name").Value); - Assert.Equal("host_not_found", tags.Single(t => t.Key == "error.type").Value); + Activity activity = recorder.LastFinishedActivity; + Assert.Equal(ActivityStatusCode.Error, activity.Status); + VerifyCommonActivityInfo(activity, InvalidHostName); + ActivityAssert.HasTag(activity, "error.type", "host_not_found"); } }, createParentActivity.ToString()).DisposeAsync(); } + + static void VerifyCommonActivityInfo(Activity activity, string host) + { + Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal("System.Net.NameResolution.DnsLookup", activity.OperationName); + Assert.Equal($"DNS {host}", activity.DisplayName); + ActivityAssert.HasTag(activity, "dns.question.name", host); + } } } From 5e0e9717e4b9b83529c681a0d09782a9ff304019 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Sat, 6 Jul 2024 02:49:41 +0200 Subject: [PATCH 07/37] Socket Activity tags --- .../tests/System/Net/ActivityRecorder.cs | 15 +++-- .../src/System/Net/Sockets/Socket.cs | 4 +- .../System/Net/Sockets/SocketsTelemetry.cs | 60 +++++++++++++++++- .../tests/FunctionalTests/TelemetryTest.cs | 61 +++++++++++++------ 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs index a5c4e4b98d470..db3cd8b99bf9d 100644 --- a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -1,6 +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.Diagnostics; using System.Linq; using System.Text; @@ -74,14 +75,18 @@ internal static class ActivityAssert { public static void HasTag(Activity activity, string name, T expectedValue) { - T? value = (T?)activity.TagObjects.Single(t => t.Key == name).Value; - Assert.False(value is null, $"The Activity tags should contain {name}."); - Assert.Equal(expectedValue, value); + KeyValuePair tag = activity.TagObjects.SingleOrDefault(t => t.Key == name); + if (tag.Key is null) + { + Assert.Fail($"The Activity tags should contain {name}."); + } + + Assert.Equal(expectedValue, (T)tag.Value); } public static void HasTag(Activity activity, string name, Func verifyValue) { - T? value = (T?)activity.TagObjects.Single(t => t.Key == name).Value; + T? value = (T?)activity.TagObjects.SingleOrDefault(t => t.Key == name).Value; Assert.False(value is null, $"The Activity tags should contain {name}."); Assert.True(verifyValue(value)); } @@ -100,11 +105,11 @@ public static string CamelToSnake(string camel) for (int i = 1; i < camel.Length; i++) { char c = camel[i]; - bld.Append(char.ToLower(c)); if (char.IsUpper(c)) { bld.Append('_'); } + bld.Append(char.ToLower(c)); } return bld.ToString(); } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index e3d6af0e795db..b9a5116da4687 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2782,7 +2782,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan WildcardBindForConnectIfNecessary(endPointSnapshot.AddressFamily); - e._activity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, keepActivityCurrent: true); + e._activity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); // Prepare for the native call. try @@ -3191,7 +3191,7 @@ private SocketAddress Serialize(ref EndPoint remoteEP) private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) { - Activity? activity = SocketsTelemetry.Log.ConnectStart(socketAddress, keepActivityCurrent: false); + Activity? activity = SocketsTelemetry.Log.ConnectStart(socketAddress, endPointSnapshot, keepActivityCurrent: false); SocketError errorCode; try { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 9500fd995f408..0e8bd13b4a0bf 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -81,7 +81,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) } [NonEvent] - public Activity? ConnectStart(SocketAddress address, bool keepActivityCurrent) + public Activity? ConnectStart(SocketAddress address, EndPoint endPoint, bool keepActivityCurrent) { Interlocked.Increment(ref _currentOutgoingConnectAttempts); @@ -94,7 +94,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) if (s_connectActivitySource.HasListeners()) { Activity? activityToReset = keepActivityCurrent ? Activity.Current : null; - activity = s_connectActivitySource.StartActivity(ConnectActivityName); + activity = s_connectActivitySource.StartActivity(ConnectActivityName, ActivityKind.Client); if (keepActivityCurrent) { // Do not overwrite Activity.Current in the caller's ExecutionContext. @@ -102,6 +102,25 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) } } + if (activity is not null) + { + if (endPoint is IPEndPoint ipEndPoint) + { + string peerAddress = ipEndPoint.Address.ToString(); + int port = ipEndPoint.Port; + activity.DisplayName = $"socket connect {peerAddress}:{port}"; + activity.SetTag("network.peer.address", peerAddress); + activity.SetTag("network.peer.port", port); + activity.SetTag("network.type", ipEndPoint.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); + } + else if (endPoint is UnixDomainSocketEndPoint udsEndPoint) + { + string peerAddress = udsEndPoint.ToString(); + activity.DisplayName = $"socket connect {peerAddress}"; + activity.SetTag("network.peer.address", peerAddress); + } + } + return activity; } @@ -111,7 +130,16 @@ public void AfterConnect(SocketError error, Activity? activity, string? exceptio long newCount = Interlocked.Decrement(ref _currentOutgoingConnectAttempts); Debug.Assert(newCount >= 0); - activity?.Stop(); + if (activity is not null) + { + if (error != SocketError.Success) + { + activity.SetStatus(ActivityStatusCode.Error); + activity.SetTag("error.type", GetErrorType(error)); + } + + activity.Stop(); + } if (error == SocketError.Success) { @@ -186,6 +214,32 @@ public void DatagramSent() Interlocked.Increment(ref _datagramsSent); } + private static string GetErrorType(SocketError socketError) => socketError switch + { + // Common connect() errors expected to be seen: + // https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect#return-value + // https://man7.org/linux/man-pages/man2/connect.2.html + SocketError.NetworkDown => "network_down", + SocketError.AddressAlreadyInUse => "address_already_in_use", + SocketError.Interrupted => "interrupted", + SocketError.InProgress => "in_progress", + SocketError.AlreadyInProgress => "already_in_progress", + SocketError.AddressNotAvailable => "address_not_available", + SocketError.AddressFamilyNotSupported => "address_family_not_supported", + SocketError.ConnectionRefused => "connection_refused", + SocketError.Fault => "fault", + SocketError.InvalidArgument => "invalid_argument", + SocketError.IsConnected => "is_connected", + SocketError.NetworkUnreachable => "network_unreachable", + SocketError.HostUnreachable => "host_unreachable", + SocketError.NoBufferSpaceAvailable => "no_buffer_space_available", + SocketError.TimedOut => "timed_out", + SocketError.AccessDenied => "access_denied", + SocketError.ProtocolType => "protocol_type", + + _ => "_OTHER" + }; + protected override void OnEventCommand(EventCommandEventArgs command) { if (command.Command == EventCommand.Enable) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index 4ea738ac15fec..27297bb670b3b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -76,8 +76,8 @@ from acceptMethod in SocketMethods_MemberData() public static IEnumerable SocketMethods_WithBools_MemberData() { return from connectMethod in SocketMethods_MemberData() - from useDnsEndPoint in new[] { true, false } - select new[] { connectMethod[0], useDnsEndPoint }; + from boolValue in new[] { true, false } + select new[] { connectMethod[0], boolValue }; } private static async Task GetRemoteEndPointAsync(string useDnsEndPointString, int port) @@ -110,18 +110,21 @@ private static SocketHelperBase GetHelperBase(string socketMethod) } [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [MemberData(nameof(SocketMethods_MemberData))] - public async Task Connect_Success_ActivityRecorded(string connectMethod) + [MemberData(nameof(SocketMethods_WithBools_MemberData))] + public async Task Connect_Success_ActivityRecorded(string connectMethod, bool ipv6) { - await RemoteExecutor.Invoke(async connectMethod => + if (ipv6 && !Socket.OSSupportsIPv6) return; + + await RemoteExecutor.Invoke(static async (connectMethod, ipv6Str) => { - using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - server.BindToAnonymousPort(IPAddress.Loopback); + bool ipv6 = bool.Parse(ipv6Str); + using Socket server = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + server.BindToAnonymousPort(ipv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback); server.Listen(); Activity parent = new Activity("parent").Start(); - using Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + using Socket client = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName) { @@ -133,37 +136,59 @@ await RemoteExecutor.Invoke(async connectMethod => await connectTask; recorder.VerifyActivityRecorded(1); + Activity activity = recorder.LastFinishedActivity; + VerifyConnectActivity(activity, (IPEndPoint)server.LocalEndPoint, ipv6); + Assert.Same(parent, Activity.Current); parent.Stop(); - }, connectMethod).DisposeAsync(); + }, connectMethod, ipv6.ToString()).DisposeAsync(); + } + + static void VerifyConnectActivity(Activity activity, IPEndPoint remoteEndPoint, bool ipv6) + { + string address = remoteEndPoint.Address.ToString(); + int port = remoteEndPoint.Port; + Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal("System.Net.Sockets.Connect", activity.OperationName); + Assert.Equal($"socket connect {address}:{port}", activity.DisplayName); + ActivityAssert.HasTag(activity, "network.peer.address", address); + ActivityAssert.HasTag(activity, "network.peer.port", port); + ActivityAssert.HasTag(activity, "network.type", ipv6 ? "ipv6" : "ipv4"); } - [OuterLoop("Connection failure takes long on Windows.")] + //[OuterLoop("Connection failure takes long on Windows.")] [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [MemberData(nameof(SocketMethods_MemberData))] - public async Task Connect_Failure_ActivityRecorded(string connectMethod) + [MemberData(nameof(SocketMethods_WithBools_MemberData))] + public async Task Connect_Failure_ActivityRecorded(string connectMethod, bool ipv6) { - await RemoteExecutor.Invoke(async connectMethod => + await RemoteExecutor.Invoke(static async (connectMethod, ipv6Str) => { - using Socket notListening = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - notListening.BindToAnonymousPort(IPAddress.Loopback); + bool ipv6 = bool.Parse(ipv6Str); + using Socket notListening = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + notListening.BindToAnonymousPort(ipv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback); Activity parent = new Activity("parent").Start(); - using Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + using Socket client = new Socket(ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName) { ExpectedParent = parent }; - await Assert.ThrowsAsync(() =>GetHelperBase(connectMethod) + SocketException ex = await Assert.ThrowsAsync(() => GetHelperBase(connectMethod) .ConnectAsync(client, notListening.LocalEndPoint)); recorder.VerifyActivityRecorded(1); + Activity activity = recorder.LastFinishedActivity; + VerifyConnectActivity(activity, (IPEndPoint)notListening.LocalEndPoint, ipv6); + string expectedErrorType = ActivityAssert.CamelToSnake(ex.SocketErrorCode.ToString()); + ActivityAssert.HasTag(activity, "error.type", expectedErrorType); + Assert.Equal(ActivityStatusCode.Error, activity.Status); + Assert.Same(parent, Activity.Current); parent.Stop(); - }, connectMethod).DisposeAsync(); + }, connectMethod, ipv6.ToString()).DisposeAsync(); } [OuterLoop] From 4988004a7121e6b29bf73b0efb891427d82d20c1 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Sat, 6 Jul 2024 21:36:23 +0200 Subject: [PATCH 08/37] emit attributes on SslStream Activity --- .../tests/System/Net/ActivityRecorder.cs | 3 ++ .../src/System/Net/Security/SslStream.IO.cs | 49 ++++++++++++++++++- .../SslStreamStreamToStreamTest.cs | 16 +++--- .../tests/FunctionalTests/TelemetryTest.cs | 48 +++++++++++++++++- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs index db3cd8b99bf9d..d5df9715e6635 100644 --- a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -15,6 +15,7 @@ internal class ActivityRecorder : IDisposable private string _activityName; private readonly ActivityListener _listener; + private List _finishedActivities = new(); public Predicate Filter { get; set; } = _ => true; public bool VerifyParent { get; set; } = true; @@ -24,6 +25,7 @@ internal class ActivityRecorder : IDisposable public int Stopped { get; private set; } public Activity LastStartedActivity { get; private set; } public Activity LastFinishedActivity { get; private set; } + public IEnumerable FinishedActivities => _finishedActivities; public ActivityRecorder(string activitySourceName, string activityName) { @@ -55,6 +57,7 @@ public ActivityRecorder(string activitySourceName, string activityName) Stopped++; LastFinishedActivity = activity; + _finishedActivities.Add(activity); } } }; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index cb0bc129cdb4a..270808e438d7a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -137,7 +137,17 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell } using Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); + if (activity is not null) + { + activity.DisplayName = IsServer ? "TLS server" : $"TLS client {TargetHostName}"; + if (activity.IsAllDataRequested && !IsServer) + { + activity.SetTag("tls.client.server_name", TargetHostName); + } + } + Exception? exception = null; + SslProtocols? protocol = null; try { Task task = isAsync ? @@ -151,11 +161,13 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell // SslStream could already have been disposed at this point, in which case _connectionOpenedStatus == 2 // Make sure that we increment the open connection counter only if it is guaranteed to be decremented in dispose/finalize bool connectionOpen = Interlocked.CompareExchange(ref _connectionOpenedStatus, 1, 0) == 0; - NetSecurityTelemetry.Log.HandshakeCompleted(GetSslProtocolInternal(), startingTimestamp, connectionOpen); + protocol = GetSslProtocolInternal(); + NetSecurityTelemetry.Log.HandshakeCompleted(protocol.Value, startingTimestamp, connectionOpen); } } catch (Exception ex) { + exception = ex; if (startingTimestamp is not 0) { NetSecurityTelemetry.Log.HandshakeFailed(IsServer, startingTimestamp, ex.Message); @@ -163,6 +175,41 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell throw; } + finally + { + if (activity is not null && activity.IsAllDataRequested) + { + protocol ??= GetSslProtocolInternal(); + (string? protocolName, string? protocolVersion) = GetNameAndVersionString(protocol.Value); + + if (protocolName is not null) + { + Debug.Assert(protocolVersion is not null); + activity.SetTag("tls.protocol.name", protocolName); + activity.SetTag("tls.protocol.version", protocolVersion); + } + + if (exception is not null) + { + activity.SetStatus(ActivityStatusCode.Error); + activity.SetTag("error.type", exception.GetType().FullName); + } + } + } + + static (string?, string?) GetNameAndVersionString(SslProtocols protocol) => protocol switch + { +#pragma warning disable 0618 // Ssl2, Ssl3 are deprecated. + SslProtocols.Ssl2 => ("ssl", "2"), + SslProtocols.Ssl3 => ("ssl", "3"), +#pragma warning restore 0618 +#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete. + SslProtocols.Tls => ("tls", "1"), + SslProtocols.Tls12 => ("tls", "1.2"), +#pragma warning restore SYSLIB0039 + SslProtocols.Tls13 => ("tls", "1.3"), + _ => (null, null) + }; } // diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index 13613df3a2479..b6b14b9256cfa 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -22,25 +22,27 @@ public abstract class SslStreamStreamToStreamTest { private readonly byte[] _sampleMsg = "Sample Test Message"u8.ToArray(); - protected static async Task WithServerCertificate(X509Certificate serverCertificate, Func func) + internal string Name { get; private set; } + internal SslProtocols SslProtocol { get; private set; } + + protected async Task WithServerCertificate(X509Certificate serverCertificate, Func func) { X509Certificate certificate = serverCertificate ?? Configuration.Certificates.GetServerCertificate(); try { - string name; if (certificate is X509Certificate2 cert2) { - name = cert2.GetNameInfo(X509NameType.SimpleName, forIssuer: false); + Name = cert2.GetNameInfo(X509NameType.SimpleName, forIssuer: false); } else { using (cert2 = new X509Certificate2(certificate)) { - name = cert2.GetNameInfo(X509NameType.SimpleName, forIssuer: false); + Name = cert2.GetNameInfo(X509NameType.SimpleName, forIssuer: false); } } - await func(certificate, name).ConfigureAwait(false); + await func(certificate, Name).ConfigureAwait(false); } finally { @@ -77,6 +79,7 @@ public async Task SslStream_StreamToStream_Authentication_Success(X509Certificat using (var server = new SslStream(stream2, false, delegate { return true; })) { await DoHandshake(client, server, serverCert, clientCert); + SslProtocol = client.SslProtocol; Assert.True(client.IsAuthenticated); Assert.True(server.IsAuthenticated); } @@ -93,7 +96,8 @@ public async Task SslStream_StreamToStream_Authentication_IncorrectServerName_Fa using (var server = new SslStream(stream2)) using (var certificate = Configuration.Certificates.GetServerCertificate()) { - Task t1 = client.AuthenticateAsClientAsync("incorrectServer"); + Name = "incorrectServer"; + Task t1 = client.AuthenticateAsClientAsync(Name); Task t2 = server.AuthenticateAsServerAsync(certificate); await Assert.ThrowsAsync(() => t1.WaitAsync(TestConfiguration.PassingTestTimeout)); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs index a7b45de76323b..7437b32cbcee3 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Tracing; using System.Linq; using System.Net.Test.Common; @@ -47,7 +48,36 @@ await RemoteExecutor.Invoke(async synchronousApiStr => await test.SslStream_StreamToStream_Authentication_Success(); recorder.VerifyActivityRecorded(2); // client + server - Assert.True(recorder.LastFinishedActivity.Duration > TimeSpan.Zero); + Activity clientActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Client); + Activity serverActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Server); +#pragma warning disable 0618, SYSLIB0039 + (string protocolName, string protocolVersion) = test.SslProtocol switch + { + SslProtocols.Ssl2 => ("ssl", "2"), + SslProtocols.Ssl3 => ("ssl", "3"), + SslProtocols.Tls => ("tls", "1"), + SslProtocols.Tls11 => ("tls", "1.1"), + SslProtocols.Tls12 => ("tls", "1.2"), + SslProtocols.Tls13 => ("tls", "1.3"), + _ => throw new Exception("unknown protocol") + }; +#pragma warning restore 0618, SYSLIB0039 + + Assert.True(clientActivity.Duration > TimeSpan.Zero); + Assert.Equal("System.Net.Security.TlsHandshake", clientActivity.OperationName); + Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); + ActivityAssert.HasTag(clientActivity, "tls.client.server_name", test.Name); + ActivityAssert.HasTag(clientActivity, "tls.protocol.name", protocolName); + ActivityAssert.HasTag(clientActivity, "tls.protocol.version", protocolVersion); + ActivityAssert.HasNoTag(clientActivity, "error.type"); + + Assert.True(serverActivity.Duration > TimeSpan.Zero); + Assert.Equal("System.Net.Security.TlsHandshake", serverActivity.OperationName); + Assert.StartsWith($"TLS server", serverActivity.DisplayName); + ActivityAssert.HasTag(serverActivity, "tls.protocol.name", protocolName); + ActivityAssert.HasTag(serverActivity, "tls.protocol.version", protocolVersion); + ActivityAssert.HasNoTag(serverActivity, "error.type"); + }, synchronousApi.ToString()).DisposeAsync(); } @@ -59,9 +89,23 @@ await RemoteExecutor.Invoke(async () => using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName); var test = new SslStreamStreamToStreamTest_Async(); - await test.SslStream_ServerLocalCertificateSelectionCallbackReturnsNull_Throw(); + await test.SslStream_StreamToStream_Authentication_IncorrectServerName_Fail(); recorder.VerifyActivityRecorded(2); // client + server + + Activity clientActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Client); + Activity serverActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Server); + + Assert.Equal(ActivityStatusCode.Error, clientActivity.Status); + Assert.True(clientActivity.Duration > TimeSpan.Zero); + Assert.Equal("System.Net.Security.TlsHandshake", clientActivity.OperationName); + Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); + ActivityAssert.HasTag(clientActivity, "tls.client.server_name", test.Name); + ActivityAssert.HasTag(clientActivity, "error.type", typeof(AuthenticationException).FullName); + + Assert.True(serverActivity.Duration > TimeSpan.Zero); + Assert.Equal("System.Net.Security.TlsHandshake", serverActivity.OperationName); + Assert.StartsWith($"TLS server", serverActivity.DisplayName); }).DisposeAsync(); } From 7777b681cb0b78c8338b140a62670f1d89909c9d Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 8 Jul 2024 03:02:52 +0200 Subject: [PATCH 09/37] connection setup activity graph --- .../tests/System/Net/ActivityRecorder.cs | 18 +- .../src/System.Net.Http.csproj | 1 + .../Http/DiagnosticsHandlerLoggingStrings.cs | 4 +- .../src/System/Net/Http/DiagnosticsHelper.cs | 96 ++++++++++ .../System/Net/Http/Metrics/MetricsHandler.cs | 72 +------- .../Http/SocketsHttpHandler/ConnectHelper.cs | 11 +- .../ConnectionPool/HttpConnectionPool.cs | 36 ++-- .../ConnectionPool/HttpConnectionWaiter.cs | 21 ++- .../SocketsHttpHandler/Http2Connection.cs | 7 +- .../SocketsHttpHandler/Http3Connection.cs | 2 +- .../Http/SocketsHttpHandler/HttpConnection.cs | 7 +- .../SocketsHttpHandler/HttpConnectionBase.cs | 27 +-- .../tests/FunctionalTests/DiagnosticsTests.cs | 172 ++++++++++++------ 13 files changed, 304 insertions(+), 170 deletions(-) create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs diff --git a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs index d5df9715e6635..6647076d4bac5 100644 --- a/src/libraries/Common/tests/System/Net/ActivityRecorder.cs +++ b/src/libraries/Common/tests/System/Net/ActivityRecorder.cs @@ -72,18 +72,29 @@ public void VerifyActivityRecorded(int times) Assert.Equal(times, Started); Assert.Equal(times, Stopped); } + + public Activity VerifyActivityRecordedOnce() + { + VerifyActivityRecorded(1); + return LastFinishedActivity; + } } internal static class ActivityAssert { - public static void HasTag(Activity activity, string name, T expectedValue) + public static KeyValuePair HasTag(Activity activity, string name) { KeyValuePair tag = activity.TagObjects.SingleOrDefault(t => t.Key == name); if (tag.Key is null) { Assert.Fail($"The Activity tags should contain {name}."); } + return tag; + } + public static void HasTag(Activity activity, string name, T expectedValue) + { + KeyValuePair tag = HasTag(activity, name); Assert.Equal(expectedValue, (T)tag.Value); } @@ -100,6 +111,11 @@ public static void HasNoTag(Activity activity, string name) Assert.False(contains, $"The Activity tags should not contain {name}."); } + public static void FinishedInOrder(Activity first, Activity second) + { + Assert.True(first.StartTimeUtc + first.Duration < second.StartTimeUtc + second.Duration, $"{first.OperationName} should stop before {second.OperationName}"); + } + public static string CamelToSnake(string camel) { if (string.IsNullOrEmpty(camel)) return camel; diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index dea20f206cdc9..82f4c1b03c217 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -37,6 +37,7 @@ + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs index 5a8a013fbcd9d..45015585d408e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs @@ -18,6 +18,8 @@ internal static class DiagnosticsHandlerLoggingStrings public const string RequestActivityStopName = RequestActivityName + ".Stop"; public const string ConnectionNamespace = "System.Net.Http.Connections"; - public const string ConnectionActivityName = ConnectionNamespace + ".HttpConnection"; + public const string ConnectionSetupActivityName = ConnectionNamespace + ".ConnectionSetup"; + public const string WaitForConnectionNamespace = "System.Net.Http.ConnectionLink"; + public const string WaitForConnectionActivityName = WaitForConnectionNamespace + ".WaitForConnection"; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs new file mode 100644 index 0000000000000..7288c4a47ea92 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs @@ -0,0 +1,96 @@ +// 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.Diagnostics; +using System.Threading; + +namespace System.Net.Http +{ + internal static class DiagnosticsHelper + { + internal static ActivitySource WaitForConnectionActivitySource { get; } = new ActivitySource(DiagnosticsHandlerLoggingStrings.WaitForConnectionNamespace); + + internal static void AbortConnectionSetupActivity(Activity? activity, Exception exception) + { + Debug.Assert(exception is not null); + if (activity is null) return; + activity.SetStatus(ActivityStatusCode.Error); + string? errorType; + if (!TryGetErrorType(null, exception, out errorType)) + { + errorType = exception.GetType().FullName; + } + activity.SetTag("error.type", errorType); + activity.Stop(); + } + + public static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) + { + if (response is not null) + { + int statusCode = (int)response.StatusCode; + + // In case the status code indicates a client or a server error, return the string representation of the status code. + // See the paragraph Status and the definition of 'error.type' in + // https://github.com/open-telemetry/semantic-conventions/blob/2bad9afad58fbd6b33cc683d1ad1f006e35e4a5d/docs/http/http-spans.md + if (statusCode >= 400 && statusCode <= 599) + { + errorType = GetErrorStatusCodeString(statusCode); + return true; + } + } + + if (exception is null) + { + errorType = null; + return false; + } + + Debug.Assert(Enum.GetValues().Length == 12, "We need to extend the mapping in case new values are added to HttpRequestError."); + errorType = (exception as HttpRequestException)?.HttpRequestError switch + { + HttpRequestError.NameResolutionError => "name_resolution_error", + HttpRequestError.ConnectionError => "connection_error", + HttpRequestError.SecureConnectionError => "secure_connection_error", + HttpRequestError.HttpProtocolError => "http_protocol_error", + HttpRequestError.ExtendedConnectNotSupported => "extended_connect_not_supported", + HttpRequestError.VersionNegotiationError => "version_negotiation_error", + HttpRequestError.UserAuthenticationError => "user_authentication_error", + HttpRequestError.ProxyTunnelError => "proxy_tunnel_error", + HttpRequestError.InvalidResponse => "invalid_response", + HttpRequestError.ResponseEnded => "response_ended", + HttpRequestError.ConfigurationLimitExceeded => "configuration_limit_exceeded", + + // Fall back to the exception type name in case of HttpRequestError.Unknown or when exception is not an HttpRequestException. + _ => exception.GetType().FullName! + }; + return true; + } + + private static object[]? s_boxedStatusCodes; + private static string[]? s_statusCodeStrings; + +#pragma warning disable CA1859 // we explictly box here + public static object GetBoxedStatusCode(int statusCode) + { + object[] boxes = LazyInitializer.EnsureInitialized(ref s_boxedStatusCodes, static () => new object[512]); + + return (uint)statusCode < (uint)boxes.Length + ? boxes[statusCode] ??= statusCode + : statusCode; + } +#pragma warning restore + + private static string GetErrorStatusCodeString(int statusCode) + { + Debug.Assert(statusCode >= 400 && statusCode <= 599); + + string[] strings = LazyInitializer.EnsureInitialized(ref s_statusCodeStrings, static () => new string[200]); + int index = statusCode - 400; + return (uint)index < (uint)strings.Length + ? strings[index] ??= statusCode.ToString() + : statusCode.ToString(); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs index 942cd6ceaed36..da42316b5ab98 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs @@ -109,11 +109,11 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon if (response is not null) { - tags.Add("http.response.status_code", GetBoxedStatusCode((int)response.StatusCode)); + tags.Add("http.response.status_code", DiagnosticsHelper.GetBoxedStatusCode((int)response.StatusCode)); tags.Add("network.protocol.version", GetProtocolVersionString(response.Version)); } - if (TryGetErrorType(response, exception, out string? errorType)) + if (DiagnosticsHelper.TryGetErrorType(response, exception, out string? errorType)) { tags.Add("error.type", errorType); } @@ -131,49 +131,6 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon } } - private static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) - { - if (response is not null) - { - int statusCode = (int)response.StatusCode; - - // In case the status code indicates a client or a server error, return the string representation of the status code. - // See the paragraph Status and the definition of 'error.type' in - // https://github.com/open-telemetry/semantic-conventions/blob/2bad9afad58fbd6b33cc683d1ad1f006e35e4a5d/docs/http/http-spans.md - if (statusCode >= 400 && statusCode <= 599) - { - errorType = GetErrorStatusCodeString(statusCode); - return true; - } - } - - if (exception is null) - { - errorType = null; - return false; - } - - Debug.Assert(Enum.GetValues().Length == 12, "We need to extend the mapping in case new values are added to HttpRequestError."); - errorType = (exception as HttpRequestException)?.HttpRequestError switch - { - HttpRequestError.NameResolutionError => "name_resolution_error", - HttpRequestError.ConnectionError => "connection_error", - HttpRequestError.SecureConnectionError => "secure_connection_error", - HttpRequestError.HttpProtocolError => "http_protocol_error", - HttpRequestError.ExtendedConnectNotSupported => "extended_connect_not_supported", - HttpRequestError.VersionNegotiationError => "version_negotiation_error", - HttpRequestError.UserAuthenticationError => "user_authentication_error", - HttpRequestError.ProxyTunnelError => "proxy_tunnel_error", - HttpRequestError.InvalidResponse => "invalid_response", - HttpRequestError.ResponseEnded => "response_ended", - HttpRequestError.ConfigurationLimitExceeded => "configuration_limit_exceeded", - - // Fall back to the exception type name in case of HttpRequestError.Unknown or when exception is not an HttpRequestException. - _ => exception.GetType().FullName! - }; - return true; - } - private static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch { (1, 0) => "1.0", @@ -209,31 +166,6 @@ private static TagList InitializeCommonTags(HttpRequestMessage request) return new KeyValuePair("http.request.method", known?.Method ?? "_OTHER"); } - private static object[]? s_boxedStatusCodes; - private static string[]? s_statusCodeStrings; - -#pragma warning disable CA1859 // we explictly box here - private static object GetBoxedStatusCode(int statusCode) - { - object[] boxes = LazyInitializer.EnsureInitialized(ref s_boxedStatusCodes, static () => new object[512]); - - return (uint)statusCode < (uint)boxes.Length - ? boxes[statusCode] ??= statusCode - : statusCode; - } -#pragma warning restore - - private static string GetErrorStatusCodeString(int statusCode) - { - Debug.Assert(statusCode >= 400 && statusCode <= 599); - - string[] strings = LazyInitializer.EnsureInitialized(ref s_statusCodeStrings, static () => new string[200]); - int index = statusCode - 400; - return (uint)index < (uint)strings.Length - ? strings[index] ??= statusCode.ToString() - : statusCode.ToString(); - } - private sealed class SharedMeter : Meter { public static Meter Instance { get; } = new SharedMeter(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index 247c04a635b26..a535e501358db 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -78,16 +78,18 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu catch (Exception e) { sslStream.Dispose(); - activity?.Stop(); if (e is OperationCanceledException) { + DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); throw; } if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { - throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken); + e = CancellationHelper.CreateOperationCanceledException(e, cancellationToken); + DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + throw e; } HttpRequestException ex = new HttpRequestException(HttpRequestError.SecureConnectionError, SR.net_http_ssl_connection_failed, e); @@ -97,6 +99,7 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu // At this point, SSL connection for HTTP / 2 failed, and the exception should indicate the reason for the external client / user. ex.Data["HTTP2_ENABLED"] = false; } + DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); throw ex; } @@ -104,7 +107,9 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu if (cancellationToken.IsCancellationRequested) { sslStream.Dispose(); - throw CancellationHelper.CreateOperationCanceledException(null, cancellationToken); + Exception ex = CancellationHelper.CreateOperationCanceledException(null, cancellationToken); + DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + throw ex; } return sslStream; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index aebd66d8a480f..a4d483b643219 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -574,7 +574,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn // Connection activities should be new roots and not parented under whatever // request happens to be in progress when the connection is started. Activity.Current = null; - Activity? activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionActivityName); + Activity? activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName, ActivityKind.Client); switch (_kind) { @@ -602,7 +602,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn case HttpConnectionKind.ProxyTunnel: case HttpConnectionKind.SslProxyTunnel: - stream = await EstablishProxyTunnelAsync(async, cancellationToken).ConfigureAwait(false); + stream = await EstablishProxyTunnelAsync(async, activity, cancellationToken).ConfigureAwait(false); if (stream is HttpContentStream contentStream && contentStream._connection?._stream is Stream innerStream) { @@ -640,9 +640,10 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn stream = sslStream; } - static IPEndPoint? GetRemoteEndPoint(Stream stream) => (stream as NetworkStream)?.Socket?.RemoteEndPoint as IPEndPoint; - + activity?.Stop(); return (stream, transportContext, activity, remoteEndPoint); + + static IPEndPoint? GetRemoteEndPoint(Stream stream) => (stream as NetworkStream)?.Socket?.RemoteEndPoint as IPEndPoint; } private async ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, Activity? activity, CancellationToken cancellationToken) @@ -700,10 +701,11 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt } catch (Exception ex) { - activity?.Stop(); - throw ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? + ex = ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken) : ConnectHelper.CreateWrappedException(ex, host, port, cancellationToken); + DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + throw ex; } } @@ -767,7 +769,7 @@ private async ValueTask ApplyPlaintextFilterAsync(bool async, Stream str return newStream; } - private async ValueTask EstablishProxyTunnelAsync(bool async, CancellationToken cancellationToken) + private async ValueTask EstablishProxyTunnelAsync(bool async, Activity? activity, CancellationToken cancellationToken) { // Send a CONNECT request to the proxy server to establish a tunnel. HttpRequestMessage tunnelRequest = new HttpRequestMessage(HttpMethod.Connect, _proxyUri); @@ -783,15 +785,18 @@ private async ValueTask EstablishProxyTunnelAsync(bool async, Cancellati if (tunnelResponse.StatusCode != HttpStatusCode.OK) { tunnelResponse.Dispose(); - throw new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.Format(SR.net_http_proxy_tunnel_returned_failure_status_code, _proxyUri, (int)tunnelResponse.StatusCode)); + Exception ex = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.Format(SR.net_http_proxy_tunnel_returned_failure_status_code, _proxyUri, (int)tunnelResponse.StatusCode)); + DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + throw ex; } try { return tunnelResponse.Content.ReadAsStream(cancellationToken); } - catch + catch (Exception ex) { + DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); tunnelResponse.Dispose(); throw; } @@ -807,10 +812,17 @@ private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, { await SocksHelper.EstablishSocksTunnelAsync(stream, _originAuthority.IdnHost, _originAuthority.Port, _proxyUri, ProxyCredentials, async, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (!(e is OperationCanceledException)) + catch (Exception e) { - Debug.Assert(!(e is HttpRequestException)); - throw new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.net_http_proxy_tunnel_error, e); + if (e is not OperationCanceledException) + { + Debug.Assert(e is not HttpRequestException); + e = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.net_http_proxy_tunnel_error, e); + DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + throw e; + } + DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + throw; } return stream; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index 3ca1412ebe711..0cbc436e9ad32 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -19,7 +19,7 @@ internal sealed class HttpConnectionWaiter : TaskCompletionSourceWithCancella public ValueTask WaitForConnectionAsync(HttpRequestMessage request, HttpConnectionPool pool, bool async, CancellationToken requestCancellationToken) { - return HttpTelemetry.Log.IsEnabled() || pool.Settings._metrics!.RequestsQueueDuration.Enabled + return HttpTelemetry.Log.IsEnabled() || pool.Settings._metrics!.RequestsQueueDuration.Enabled || Activity.Current?.OperationName is DiagnosticsHandlerLoggingStrings.RequestActivityName ? WaitForConnectionWithTelemetryAsync(request, pool, async, requestCancellationToken) : WaitWithCancellationAsync(async, requestCancellationToken); } @@ -29,9 +29,26 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag Debug.Assert(typeof(T) == typeof(HttpConnection) || typeof(T) == typeof(Http2Connection)); long startingTimestamp = Stopwatch.GetTimestamp(); + using Activity? waitForConnectionActivity = DiagnosticsHelper.WaitForConnectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); try { - return await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); + T connection = await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); + if (waitForConnectionActivity is not null && connection?.ConnectionSetupActivity is Activity connectionSetupActivity) + { + waitForConnectionActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); + } + return connection; + } + catch (Exception ex) when (waitForConnectionActivity is not null) + { + waitForConnectionActivity.SetStatus(ActivityStatusCode.Error); + string? errorType = null; + if (!DiagnosticsHelper.TryGetErrorType(null, ex, out errorType)) + { + errorType = ex.GetType().FullName; + } + waitForConnectionActivity.SetTag("error.type", errorType); + throw; } finally { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 464eb53867ccd..dd7f685b9c280 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -128,8 +128,8 @@ internal enum KeepAliveState private long _keepAlivePingTimeoutTimestamp; private volatile KeepAliveState _keepAliveState; - public Http2Connection(HttpConnectionPool pool, Stream stream, Activity? activity, IPEndPoint? remoteEndPoint) - : base(pool, activity, remoteEndPoint) + public Http2Connection(HttpConnectionPool pool, Stream stream, Activity? connectionSetupActivity, IPEndPoint? remoteEndPoint) + : base(pool, connectionSetupActivity, remoteEndPoint) { _stream = stream; @@ -1838,7 +1838,7 @@ private void FinalTeardown() GC.SuppressFinalize(this); - _activity?.Stop(); + ConnectionSetupActivity?.Stop(); _stream.Dispose(); _connectionWindow.Dispose(); @@ -1982,7 +1982,6 @@ public async Task SendAsync(HttpRequestMessage request, boo Debug.Assert(async); Debug.Assert(!_pool.HasSyncObjLock); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); - LinkRequestActivity(); try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 9a864b455b6df..1224bdee5b961 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -91,7 +91,7 @@ public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, bool in public void InitQuicConnection(QuicConnection connection) { - MarkConnectionAsEstablished(activity: null, remoteEndPoint: connection.RemoteEndPoint); + MarkConnectionAsEstablished(connectionSetupActivity: null, remoteEndPoint: connection.RemoteEndPoint); _connection = connection; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index d2b8cb3e612bf..98c36a9d1211a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -74,9 +74,9 @@ public HttpConnection( HttpConnectionPool pool, Stream stream, TransportContext? transportContext, - Activity? activity, + Activity? connectionSetupActivity, IPEndPoint? remoteEndPoint) - : base(pool, activity, remoteEndPoint) + : base(pool, connectionSetupActivity, remoteEndPoint) { Debug.Assert(stream != null); @@ -112,7 +112,7 @@ private void Dispose(bool disposing) if (disposing) { GC.SuppressFinalize(this); - _activity?.Stop(); + ConnectionSetupActivity?.Stop(); _stream.Dispose(); } } @@ -539,7 +539,6 @@ public async Task SendAsync(HttpRequestMessage request, boo "The caller should have called PrepareForReuse or TryOwnScavengingTaskCompletion if the connection was idle on the pool."); MarkConnectionAsNotIdle(); - LinkRequestActivity(); TaskCompletionSource? allowExpect100ToContinue = null; Task? sendRequestContentTask = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index 246ea4c5a9290..c5e578f45b2bc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -24,8 +24,6 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace // May be null if none of the counters were enabled when the connection was established. private ConnectionMetrics? _connectionMetrics; - protected Activity? _activity; - // Indicates whether we've counted this connection as established, so that we can // avoid decrementing the counter once it's closed in case telemetry was enabled in between. private bool _httpTelemetryMarkedConnectionAsOpened; @@ -40,21 +38,24 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace public long Id { get; } = Interlocked.Increment(ref s_connectionCounter); + public Activity? ConnectionSetupActivity { get; private set; } + public HttpConnectionBase(HttpConnectionPool pool) { Debug.Assert(this is HttpConnection or Http2Connection or Http3Connection); Debug.Assert(pool != null); _pool = pool; } - public HttpConnectionBase(HttpConnectionPool pool, Activity? activity, IPEndPoint? remoteEndPoint) + + public HttpConnectionBase(HttpConnectionPool pool, Activity? connectionSetupActivity, IPEndPoint? remoteEndPoint) : this(pool) { - MarkConnectionAsEstablished(activity, remoteEndPoint); + MarkConnectionAsEstablished(connectionSetupActivity, remoteEndPoint); } - protected void MarkConnectionAsEstablished(Activity? activity, IPEndPoint? remoteEndPoint) + protected void MarkConnectionAsEstablished(Activity? connectionSetupActivity, IPEndPoint? remoteEndPoint) { - _activity = activity; + ConnectionSetupActivity = connectionSetupActivity; Debug.Assert(_pool.Settings._metrics is not null); SocketsHttpHandlerMetrics metrics = _pool.Settings._metrics; @@ -121,20 +122,6 @@ public void MarkConnectionAsNotIdle() _connectionMetrics?.IdleStateChanged(idle: false); } - public void LinkRequestActivity() - { - if (_activity is null) - { - return; - } - - Activity? requestActivity = Activity.Current; - if (requestActivity?.OperationName is DiagnosticsHandlerLoggingStrings.RequestActivityName) - { - requestActivity.AddLink(new ActivityLink(_activity.Context)); - } - } - /// Uses , but first special-cases several known headers for which we can use caching. public string GetResponseHeaderValueWithCaching(HeaderDescriptor descriptor, ReadOnlySpan value, Encoding? valueEncoding) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index ecb9a5a9405f7..f15a1f87fc788 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Net.Http.Headers; +using System.Net.Sockets; using System.Net.Test.Common; using System.Reflection; using System.Threading; @@ -381,7 +382,7 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(false)] [InlineData(true)] - public async Task SendAsync_Success_ConnectionActivityRecordedWithChildren(bool useTls) + public async Task SendAsync_Success_ConnectionSetupActivityGraphRecorded(bool useTls) { await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); static async Task RunTest(string useVersion, string testAsync, string useTlsString) @@ -394,9 +395,13 @@ static async Task RunTest(string useVersion, string testAsync, string useTlsStri { ExpectedParent = parentActivity }; + using ActivityRecorder waitForConnectionRecorder = new("System.Net.Http.ConnectionLink", "System.Net.Http.ConnectionLink.WaitForConnection") + { + VerifyParent = false + }; - using ActivityRecorder connectionRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.HttpConnection"); - using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DsnLookup") { VerifyParent = false }; + using ActivityRecorder connectionSetupRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.ConnectionSetup"); + using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DnsLookup") { VerifyParent = false }; using ActivityRecorder socketRecorder = new("System.Net.Sockets", "System.Net.Sockets.Connect") { VerifyParent = false }; using ActivityRecorder tlsRecorder = new("System.Net.Security", "System.Net.Security.TlsHandshake") { @@ -412,53 +417,61 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( await client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); - requestRecorder.VerifyActivityRecorded(1); - VerifySingleConnectionStarted(); - - await client.SendAsync(CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); - VerifySingleConnectionStarted(); - - client.Dispose(); // Releases the connection - connectionRecorder.VerifyActivityRecorded(1); - - Activity conn = connectionRecorder.LastStartedActivity; - Activity dns = dnsRecorder.LastFinishedActivity; + Activity req1 = requestRecorder.VerifyActivityRecordedOnce(); + Activity wait1 = waitForConnectionRecorder.VerifyActivityRecordedOnce(); + Activity conn = connectionSetupRecorder.VerifyActivityRecordedOnce(); + Activity dns = dnsRecorder.VerifyActivityRecordedOnce(); + Assert.True(socketRecorder.Stopped is 1 or 2); Activity sock = socketRecorder.LastFinishedActivity; - TimeSpan tlsDuration = tlsRecorder.LastFinishedActivity?.Duration ?? TimeSpan.Zero; - Assert.True(conn.Duration > dns.Duration + sock.Duration + tlsDuration); - - void VerifySingleConnectionStarted() + Activity? tls = null; + if (useTls) { - Assert.Equal(1, connectionRecorder.Started); - Assert.Equal(0, connectionRecorder.Stopped); - dnsRecorder.VerifyActivityRecorded(1); - - Assert.True(socketRecorder.Started is 1 or 2 && socketRecorder.Stopped is 1 or 2); - - tlsRecorder.VerifyActivityRecorded(useTls ? 1 : 0); + tls = tlsRecorder.VerifyActivityRecordedOnce(); + } + else + { + tlsRecorder.VerifyActivityRecorded(0); + } - Activity conn = connectionRecorder.LastStartedActivity; - Activity dns = dnsRecorder.LastFinishedActivity; - Activity sock = socketRecorder.LastFinishedActivity; + // Verify relationships between request and connection_setup, wait_for_connection: + Assert.Same(parentActivity, req1.Parent); + Assert.Same(req1, wait1.Parent); - Assert.Null(conn.Parent); - Assert.Same(conn, dns.Parent); - Assert.Same(conn, sock.Parent); - Assert.True(conn.StartTimeUtc <= dns.StartTimeUtc); - Assert.True(dns.StartTimeUtc <= sock.StartTimeUtc); + // Verify timing relationships between request, wait_for_connection, connection_setup: + ActivityAssert.FinishedInOrder(conn, wait1); + ActivityAssert.FinishedInOrder(wait1, req1); - TimeSpan tlsDuration = TimeSpan.Zero; - if (useTls) - { - Activity tls = tlsRecorder.LastFinishedActivity; - tlsDuration = tls.Duration; - Assert.Same(conn, tls.Parent); - Assert.True(sock.StartTimeUtc <= tls.StartTimeUtc); - } + // Verify the connection_setup graph: + Assert.Null(conn.Parent); + Assert.Same(conn, dns.Parent); + Assert.Same(conn, sock.Parent); + if (useTls) + { + Assert.Same(conn, tls.Parent); + } + wait1.Links.Single(l => l.Context == conn.Context); - // The connection activity should be linked to the request. - requestRecorder.LastFinishedActivity.Links.Single(l => l.Context == conn.Context); + // Verify timing relationships for connection setup: + ActivityAssert.FinishedInOrder(dns, sock); + if (useTls) + { + ActivityAssert.FinishedInOrder(sock, tls); + ActivityAssert.FinishedInOrder(tls, conn); } + else + { + ActivityAssert.FinishedInOrder(sock, conn); + } + + // Verify Attributes: + // TODO + + // Second request should reuse the first connection, no connection_setup and wait_for_connection should not be recorded again. + await client.SendAsync(CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); + requestRecorder.VerifyActivityRecorded(2); + Assert.NotSame(req1, requestRecorder.LastFinishedActivity); + waitForConnectionRecorder.VerifyActivityRecorded(1); + connectionSetupRecorder.VerifyActivityRecorded(1); }, async server => { @@ -478,24 +491,79 @@ await server.AcceptConnectionAsync(async connection => } } - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - public async Task SendAsync_ConnectionFailure_ConnectionActivityRecorded() + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData("dns")] + [InlineData("socket")] + public async Task SendAsync_ConnectionFailure_RecordsActivitiesWithCorrectErrorInfo(string failureType) { - await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString()).DisposeAsync(); - static async Task RunTest(string useVersion, string testAsync) + await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), failureType).DisposeAsync(); + static async Task RunTest(string useVersion, string testAsync, string failureType) { using HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); - GetUnderlyingSocketsHttpHandler(handler).ConnectCallback = (_, __) => throw new Exception(); using HttpClient client = new HttpClient(handler); Activity parentActivity = new Activity("parent").Start(); - using ActivityRecorder connectionRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.HttpConnection"); + using ActivityRecorder requestRecorder = new("System.Net.Http", "System.Net.Http.HttpRequestOut") + { + ExpectedParent = parentActivity + }; + using ActivityRecorder waitForConnectionRecorder = new("System.Net.Http.ConnectionLink", "System.Net.Http.ConnectionLink.WaitForConnection") + { + VerifyParent = false + }; + using ActivityRecorder connectionSetupRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.ConnectionSetup"); + using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DnsLookup") { VerifyParent = false }; + using ActivityRecorder socketRecorder = new("System.Net.Sockets", "System.Net.Sockets.Connect") { VerifyParent = false }; - await Assert.ThrowsAsync(() => client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, new Uri("http://foo.bar"), Version.Parse(useVersion), exactVersion: true))); + Uri uri; + using Socket? notListening = failureType is "socket" ? new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) : null; + if (failureType is "dns") + { + uri = new Uri("http://does.not.exist.sorry"); + } + else + { + Debug.Assert(notListening is not null); + notListening.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + IPEndPoint ep = (IPEndPoint)notListening.LocalEndPoint; + uri = new Uri($"http://{ep.Address}:{ep.Port}"); + } + + using HttpRequestMessage request = CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true); + await Assert.ThrowsAsync(() => client.SendAsync(bool.Parse(testAsync), request)); + + Activity req = requestRecorder.VerifyActivityRecordedOnce(); + Activity wait = waitForConnectionRecorder.VerifyActivityRecordedOnce(); + Activity conn = connectionSetupRecorder.VerifyActivityRecordedOnce(); - connectionRecorder.VerifyActivityRecorded(1); - Assert.Null(connectionRecorder.LastFinishedActivity.Parent); + Assert.Same(req, wait.Parent); + Assert.Null(conn.Parent); + + if (failureType == "dns") + { + Activity dns = dnsRecorder.VerifyActivityRecordedOnce(); + Assert.Same(conn, dns.Parent); + Assert.Equal(ActivityStatusCode.Error, dns.Status); + Assert.Equal(ActivityStatusCode.Error, conn.Status); + Assert.Equal(ActivityStatusCode.Error, wait.Status); + ActivityAssert.HasTag(dns, "error.type", "host_not_found"); + ActivityAssert.HasTag(conn, "error.type", "name_resolution_error"); + ActivityAssert.HasTag(wait, "error.type", "name_resolution_error"); + } + else + { + Debug.Assert(failureType is "socket"); + Activity sock = socketRecorder.VerifyActivityRecordedOnce(); + Assert.Same(conn, sock.Parent); + + Assert.Equal(ActivityStatusCode.Error, sock.Status); + Assert.Equal(ActivityStatusCode.Error, conn.Status); + Assert.Equal(ActivityStatusCode.Error, wait.Status); + ActivityAssert.HasTag(sock, "error.type", "connection_refused"); + ActivityAssert.HasTag(conn, "error.type", "connection_error"); + ActivityAssert.HasTag(wait, "error.type", "connection_error"); + } } } From fd608202b216a62e73eab42281c0f985388e9e84 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 8 Jul 2024 04:22:05 +0200 Subject: [PATCH 10/37] emit tags on http connection activities --- .../src/System.Net.Http.csproj | 1 + .../src/System/Net/Http/DiagnosticsHelper.cs | 16 ---- .../Http/SocketsHttpHandler/ConnectHelper.cs | 8 +- .../ConnectionSetupDiagnostics.cs | 89 +++++++++++++++++++ .../ConnectionPool/HttpConnectionPool.cs | 22 ++--- .../ConnectionPool/HttpConnectionWaiter.cs | 14 +-- .../tests/FunctionalTests/DiagnosticsTests.cs | 16 +++- 7 files changed, 121 insertions(+), 45 deletions(-) create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 82f4c1b03c217..fc94180c06ea0 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -175,6 +175,7 @@ + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs index 7288c4a47ea92..8e3a50f2da3dc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs @@ -9,22 +9,6 @@ namespace System.Net.Http { internal static class DiagnosticsHelper { - internal static ActivitySource WaitForConnectionActivitySource { get; } = new ActivitySource(DiagnosticsHandlerLoggingStrings.WaitForConnectionNamespace); - - internal static void AbortConnectionSetupActivity(Activity? activity, Exception exception) - { - Debug.Assert(exception is not null); - if (activity is null) return; - activity.SetStatus(ActivityStatusCode.Error); - string? errorType; - if (!TryGetErrorType(null, exception, out errorType)) - { - errorType = exception.GetType().FullName; - } - activity.SetTag("error.type", errorType); - activity.Stop(); - } - public static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) { if (response is not null) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index a535e501358db..87581c24d64c1 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -81,14 +81,14 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu if (e is OperationCanceledException) { - DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + ConnectionSetupDiagnostics.AbortActivity(activity, e); throw; } if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { e = CancellationHelper.CreateOperationCanceledException(e, cancellationToken); - DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + ConnectionSetupDiagnostics.AbortActivity(activity, e); throw e; } @@ -99,7 +99,7 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu // At this point, SSL connection for HTTP / 2 failed, and the exception should indicate the reason for the external client / user. ex.Data["HTTP2_ENABLED"] = false; } - DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + ConnectionSetupDiagnostics.AbortActivity(activity, ex); throw ex; } @@ -108,7 +108,7 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu { sslStream.Dispose(); Exception ex = CancellationHelper.CreateOperationCanceledException(null, cancellationToken); - DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + ConnectionSetupDiagnostics.AbortActivity(activity, ex); throw ex; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs new file mode 100644 index 0000000000000..387a5011e7e49 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -0,0 +1,89 @@ +// 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.Diagnostics; +using System.Threading; + +namespace System.Net.Http +{ + internal static class ConnectionSetupDiagnostics + { + private static readonly ActivitySource s_connectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); + private static readonly ActivitySource s_waitForConnectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.WaitForConnectionNamespace); + + public static Activity? StartConnectionSetupActivity(bool isSecure, HttpAuthority authority) + { + Activity? activity = null; + if (s_connectionActivitySource.HasListeners()) + { + // Connection activities should be new roots and not parented under whatever + // request happens to be in progress when the connection is started. + Activity.Current = null; + activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName, ActivityKind.Client); + } + + if (activity is not null) + { + activity.DisplayName = $"HTTP connection_setup {authority.HostValue}:{authority.Port}"; + if (activity.IsAllDataRequested) + { + activity.SetTag("server.address", authority.HostValue); + activity.SetTag("server.port", authority.Port); + activity.SetTag("url.scheme", isSecure ? "https" : "http"); + } + } + + return activity; + } + + public static void StopConnectionSetupActivity(Activity activity, IPEndPoint? remoteEndPoint) + { + Debug.Assert(activity is not null); + if (activity.IsAllDataRequested && remoteEndPoint is not null) + { + activity.SetTag("network.peer.address", remoteEndPoint.Address.ToString()); + } + activity.Stop(); + } + + public static void AbortActivity(Activity? activity, Exception exception) + { + Debug.Assert(exception is not null); + if (activity is null) return; + activity.SetStatus(ActivityStatusCode.Error); + + if (activity.IsAllDataRequested) + { + string? errorType; + if (!DiagnosticsHelper.TryGetErrorType(null, exception, out errorType)) + { + errorType = exception.GetType().FullName; + } + activity.SetTag("error.type", errorType); + } + activity.Stop(); + } + + public static Activity? StartWaitForConnectionActivity(HttpAuthority authority) + { + Activity? activity = s_waitForConnectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); + if (activity is not null) + { + activity.DisplayName = $"wait_for_connection {authority.HostValue}:{authority.Port}"; + } + + return activity; + } + + public static void StopWaitForConnectionActivity(Activity waitForConnectionActivity, HttpConnectionBase? connection) + { + Debug.Assert(waitForConnectionActivity is not null); + if (waitForConnectionActivity.IsAllDataRequested && connection?.ConnectionSetupActivity is Activity connectionSetupActivity) + { + waitForConnectionActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); + } + waitForConnectionActivity.Stop(); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index a4d483b643219..d752df9b5c6ec 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -32,7 +32,6 @@ internal sealed partial class HttpConnectionPool : IDisposable private static readonly List s_http3ApplicationProtocols = new List() { SslApplicationProtocol.Http3 }; private static readonly List s_http2ApplicationProtocols = new List() { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 }; private static readonly List s_http2OnlyApplicationProtocols = new List() { SslApplicationProtocol.Http2 }; - private static readonly ActivitySource s_connectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); private readonly HttpConnectionPoolManager _poolManager; private readonly HttpConnectionKind _kind; @@ -571,10 +570,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn Stream? stream = null; IPEndPoint? remoteEndPoint = null; - // Connection activities should be new roots and not parented under whatever - // request happens to be in progress when the connection is started. - Activity.Current = null; - Activity? activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName, ActivityKind.Client); + Activity? activity = ConnectionSetupDiagnostics.StartConnectionSetupActivity(IsSecure, OriginAuthority); switch (_kind) { @@ -640,7 +636,11 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn stream = sslStream; } - activity?.Stop(); + if (activity is not null) + { + ConnectionSetupDiagnostics.StopConnectionSetupActivity(activity, remoteEndPoint); + } + return (stream, transportContext, activity, remoteEndPoint); static IPEndPoint? GetRemoteEndPoint(Stream stream) => (stream as NetworkStream)?.Socket?.RemoteEndPoint as IPEndPoint; @@ -704,7 +704,7 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt ex = ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken) : ConnectHelper.CreateWrappedException(ex, host, port, cancellationToken); - DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + ConnectionSetupDiagnostics.AbortActivity(activity, ex); throw ex; } } @@ -786,7 +786,7 @@ private async ValueTask EstablishProxyTunnelAsync(bool async, Activity? { tunnelResponse.Dispose(); Exception ex = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.Format(SR.net_http_proxy_tunnel_returned_failure_status_code, _proxyUri, (int)tunnelResponse.StatusCode)); - DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + ConnectionSetupDiagnostics.AbortActivity(activity, ex); throw ex; } @@ -796,7 +796,7 @@ private async ValueTask EstablishProxyTunnelAsync(bool async, Activity? } catch (Exception ex) { - DiagnosticsHelper.AbortConnectionSetupActivity(activity, ex); + ConnectionSetupDiagnostics.AbortActivity(activity, ex); tunnelResponse.Dispose(); throw; } @@ -818,10 +818,10 @@ private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, { Debug.Assert(e is not HttpRequestException); e = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.net_http_proxy_tunnel_error, e); - DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + ConnectionSetupDiagnostics.AbortActivity(activity, e); throw e; } - DiagnosticsHelper.AbortConnectionSetupActivity(activity, e); + ConnectionSetupDiagnostics.AbortActivity(activity, e); throw; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index 0cbc436e9ad32..9bdfdad274092 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -29,25 +29,19 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag Debug.Assert(typeof(T) == typeof(HttpConnection) || typeof(T) == typeof(Http2Connection)); long startingTimestamp = Stopwatch.GetTimestamp(); - using Activity? waitForConnectionActivity = DiagnosticsHelper.WaitForConnectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); + Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(pool.OriginAuthority); try { T connection = await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); - if (waitForConnectionActivity is not null && connection?.ConnectionSetupActivity is Activity connectionSetupActivity) + if (waitForConnectionActivity is not null) { - waitForConnectionActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); + ConnectionSetupDiagnostics.StopWaitForConnectionActivity(waitForConnectionActivity, connection); } return connection; } catch (Exception ex) when (waitForConnectionActivity is not null) { - waitForConnectionActivity.SetStatus(ActivityStatusCode.Error); - string? errorType = null; - if (!DiagnosticsHelper.TryGetErrorType(null, ex, out errorType)) - { - errorType = ex.GetType().FullName; - } - waitForConnectionActivity.SetTag("error.type", errorType); + ConnectionSetupDiagnostics.AbortActivity(waitForConnectionActivity, ex); throw; } finally diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index f15a1f87fc788..5cf702299b58a 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -462,11 +462,19 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( { ActivityAssert.FinishedInOrder(sock, conn); } - - // Verify Attributes: - // TODO - // Second request should reuse the first connection, no connection_setup and wait_for_connection should not be recorded again. + // Verify display names and attributes: + Assert.Equal($"wait_for_connection localhost:{uri.Port}", wait1.DisplayName); + Assert.Equal($"HTTP connection_setup localhost:{uri.Port}", conn.DisplayName); + ActivityAssert.HasTag(conn, "network.peer.address", + (string a) => a == IPAddress.Loopback.ToString() || + a == IPAddress.Loopback.MapToIPv6().ToString() || + a == IPAddress.IPv6Loopback.ToString()); + ActivityAssert.HasTag(conn, "server.address", "localhost"); + ActivityAssert.HasTag(conn, "server.port", uri.Port); + ActivityAssert.HasTag(conn, "url.scheme", useTls ? "https" : "http"); + + // The second request should reuse the first connection, connection_setup and wait_for_connection should not be recorded again. await client.SendAsync(CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); requestRecorder.VerifyActivityRecorded(2); Assert.NotSame(req1, requestRecorder.LastFinishedActivity); From 4ce1499ba028b083a49b19ead440bbdb56a58067 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 8 Jul 2024 14:18:45 +0200 Subject: [PATCH 11/37] fix MacOS failure --- .../System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 5cf702299b58a..da7b224b346c3 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -555,7 +555,7 @@ static async Task RunTest(string useVersion, string testAsync, string failureTyp Assert.Equal(ActivityStatusCode.Error, dns.Status); Assert.Equal(ActivityStatusCode.Error, conn.Status); Assert.Equal(ActivityStatusCode.Error, wait.Status); - ActivityAssert.HasTag(dns, "error.type", "host_not_found"); + ActivityAssert.HasTag(dns, "error.type", (string t) => t is "host_not_found" or "timed_out"); ActivityAssert.HasTag(conn, "error.type", "name_resolution_error"); ActivityAssert.HasTag(wait, "error.type", "name_resolution_error"); } @@ -568,7 +568,7 @@ static async Task RunTest(string useVersion, string testAsync, string failureTyp Assert.Equal(ActivityStatusCode.Error, sock.Status); Assert.Equal(ActivityStatusCode.Error, conn.Status); Assert.Equal(ActivityStatusCode.Error, wait.Status); - ActivityAssert.HasTag(sock, "error.type", "connection_refused"); + ActivityAssert.HasTag(sock, "error.type", (string t) => t is "connection_refused" or "timed_out"); ActivityAssert.HasTag(conn, "error.type", "connection_error"); ActivityAssert.HasTag(wait, "error.type", "connection_error"); } From ecce03bc85500a3b3d4a799075ebe70a2e798abc Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 8 Jul 2024 16:15:43 +0200 Subject: [PATCH 12/37] adjustments --- .../ConnectionPool/ConnectionSetupDiagnostics.cs | 7 ++----- .../ConnectionPool/HttpConnectionPool.Http1.cs | 1 + .../ConnectionPool/HttpConnectionPool.Http2.cs | 1 + .../Http/SocketsHttpHandler/Http2Connection.cs | 2 -- .../Net/Http/SocketsHttpHandler/HttpConnection.cs | 1 - .../src/System/Net/Sockets/SocketsTelemetry.cs | 15 +++++++++++---- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index 387a5011e7e49..10d168800be23 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -55,11 +55,8 @@ public static void AbortActivity(Activity? activity, Exception exception) if (activity.IsAllDataRequested) { - string? errorType; - if (!DiagnosticsHelper.TryGetErrorType(null, exception, out errorType)) - { - errorType = exception.GetType().FullName; - } + DiagnosticsHelper.TryGetErrorType(null, exception, out string? errorType); + Debug.Assert(errorType is not null, "DiagnosticsHelper.TryGetErrorType() should succeed whenever an exception is provided."); activity.SetTag("error.type", errorType); } activity.Stop(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs index d65e1b6486de2..b8827b5079388 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs @@ -295,6 +295,7 @@ private async Task InjectNewHttp11ConnectionAsync(RequestQueue.Q internal async ValueTask CreateHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(request, async, cancellationToken).ConfigureAwait(false); + Debug.Assert(activity is null or { IsStopped : true }, "ConnectAsync() has stop the connection setup Activity."); return await ConstructHttp11ConnectionAsync(async, stream, transportContext, request, activity, remoteEndPoint, cancellationToken).ConfigureAwait(false); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs index c3999c520f0f2..602676054594c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs @@ -186,6 +186,7 @@ private async Task InjectNewHttp2ConnectionAsync(RequestQueue. try { (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(queueItem.Request, true, cts.Token).ConfigureAwait(false); + Debug.Assert(activity is null or { IsStopped: true }, "ConnectAsync() has stop the connection setup Activity."); if (IsSecure) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index dd7f685b9c280..5ed1c52624f4f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -1837,8 +1837,6 @@ private void FinalTeardown() Debug.Assert(_streamsInUse == 0); GC.SuppressFinalize(this); - - ConnectionSetupActivity?.Stop(); _stream.Dispose(); _connectionWindow.Dispose(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index 98c36a9d1211a..61f5f3d3a4776 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -112,7 +112,6 @@ private void Dispose(bool disposing) if (disposing) { GC.SuppressFinalize(this); - ConnectionSetupActivity?.Stop(); _stream.Dispose(); } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 0e8bd13b4a0bf..fa03c1fa5c1c9 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -109,15 +109,22 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) string peerAddress = ipEndPoint.Address.ToString(); int port = ipEndPoint.Port; activity.DisplayName = $"socket connect {peerAddress}:{port}"; - activity.SetTag("network.peer.address", peerAddress); - activity.SetTag("network.peer.port", port); - activity.SetTag("network.type", ipEndPoint.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); + if (activity.IsAllDataRequested) + { + activity.SetTag("network.peer.address", peerAddress); + activity.SetTag("network.peer.port", port); + activity.SetTag("network.type", ipEndPoint.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); + } } else if (endPoint is UnixDomainSocketEndPoint udsEndPoint) { string peerAddress = udsEndPoint.ToString(); activity.DisplayName = $"socket connect {peerAddress}"; - activity.SetTag("network.peer.address", peerAddress); + + if (activity.IsAllDataRequested) + { + activity.SetTag("network.peer.address", peerAddress); + } } } From dc563ad482293bac425a3b0d6e05fc65f7980aef Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 9 Jul 2024 22:13:27 +0200 Subject: [PATCH 13/37] consolidate connection setup Activity error handling into a single catch block --- .../Http/SocketsHttpHandler/ConnectHelper.cs | 12 +- .../ConnectionSetupDiagnostics.cs | 17 +- .../HttpConnectionPool.Http1.cs | 1 - .../HttpConnectionPool.Http2.cs | 1 - .../ConnectionPool/HttpConnectionPool.cs | 149 +++++++++--------- .../ConnectionPool/HttpConnectionWaiter.cs | 4 +- 6 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index 87581c24d64c1..ef6c5db24f33f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -55,7 +55,7 @@ private static SslClientAuthenticationOptions SetUpRemoteCertificateValidationCa return sslOptions; } - public static async ValueTask EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, Activity? activity, CancellationToken cancellationToken) + public static async ValueTask EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken) { sslOptions = SetUpRemoteCertificateValidationCallback(sslOptions, request); @@ -81,15 +81,12 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu if (e is OperationCanceledException) { - ConnectionSetupDiagnostics.AbortActivity(activity, e); throw; } if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { - e = CancellationHelper.CreateOperationCanceledException(e, cancellationToken); - ConnectionSetupDiagnostics.AbortActivity(activity, e); - throw e; + throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken); } HttpRequestException ex = new HttpRequestException(HttpRequestError.SecureConnectionError, SR.net_http_ssl_connection_failed, e); @@ -99,7 +96,6 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu // At this point, SSL connection for HTTP / 2 failed, and the exception should indicate the reason for the external client / user. ex.Data["HTTP2_ENABLED"] = false; } - ConnectionSetupDiagnostics.AbortActivity(activity, ex); throw ex; } @@ -107,9 +103,7 @@ public static async ValueTask EstablishSslConnectionAsync(SslClientAu if (cancellationToken.IsCancellationRequested) { sslStream.Dispose(); - Exception ex = CancellationHelper.CreateOperationCanceledException(null, cancellationToken); - ConnectionSetupDiagnostics.AbortActivity(activity, ex); - throw ex; + throw CancellationHelper.CreateOperationCanceledException(null, cancellationToken); } return sslStream; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index 10d168800be23..950ddd1ef163d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -37,17 +37,25 @@ internal static class ConnectionSetupDiagnostics return activity; } - public static void StopConnectionSetupActivity(Activity activity, IPEndPoint? remoteEndPoint) + public static void StopConnectionSetupActivity(Activity activity, Exception? exception, IPEndPoint? remoteEndPoint) { Debug.Assert(activity is not null); - if (activity.IsAllDataRequested && remoteEndPoint is not null) + if (exception is not null) { - activity.SetTag("network.peer.address", remoteEndPoint.Address.ToString()); + ReportError(activity, exception); } + else + { + if (activity.IsAllDataRequested && remoteEndPoint is not null) + { + activity.SetTag("network.peer.address", remoteEndPoint.Address.ToString()); + } + } + activity.Stop(); } - public static void AbortActivity(Activity? activity, Exception exception) + public static void ReportError(Activity? activity, Exception exception) { Debug.Assert(exception is not null); if (activity is null) return; @@ -59,7 +67,6 @@ public static void AbortActivity(Activity? activity, Exception exception) Debug.Assert(errorType is not null, "DiagnosticsHelper.TryGetErrorType() should succeed whenever an exception is provided."); activity.SetTag("error.type", errorType); } - activity.Stop(); } public static Activity? StartWaitForConnectionActivity(HttpAuthority authority) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs index b8827b5079388..d65e1b6486de2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http1.cs @@ -295,7 +295,6 @@ private async Task InjectNewHttp11ConnectionAsync(RequestQueue.Q internal async ValueTask CreateHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(request, async, cancellationToken).ConfigureAwait(false); - Debug.Assert(activity is null or { IsStopped : true }, "ConnectAsync() has stop the connection setup Activity."); return await ConstructHttp11ConnectionAsync(async, stream, transportContext, request, activity, remoteEndPoint, cancellationToken).ConfigureAwait(false); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs index 602676054594c..c3999c520f0f2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http2.cs @@ -186,7 +186,6 @@ private async Task InjectNewHttp2ConnectionAsync(RequestQueue. try { (Stream stream, TransportContext? transportContext, Activity? activity, IPEndPoint? remoteEndPoint) = await ConnectAsync(queueItem.Request, true, cts.Token).ConfigureAwait(false); - Debug.Assert(activity is null or { IsStopped: true }, "ConnectAsync() has stop the connection setup Activity."); if (IsSecure) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index d752df9b5c6ec..5573df990656f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -569,76 +569,87 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn { Stream? stream = null; IPEndPoint? remoteEndPoint = null; + Exception? exception = null; + TransportContext? transportContext = null; Activity? activity = ConnectionSetupDiagnostics.StartConnectionSetupActivity(IsSecure, OriginAuthority); - switch (_kind) + try { - case HttpConnectionKind.Http: - case HttpConnectionKind.Https: - case HttpConnectionKind.ProxyConnect: - stream = await ConnectToTcpHostAsync(_originAuthority.IdnHost, _originAuthority.Port, request, async, activity, cancellationToken).ConfigureAwait(false); - // remoteEndPoint is returned for diagnostic purposes. - remoteEndPoint = GetRemoteEndPoint(stream); - if (_kind == HttpConnectionKind.ProxyConnect && _sslOptionsProxy != null) - { - stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, activity, cancellationToken).ConfigureAwait(false); - } - break; + switch (_kind) + { + case HttpConnectionKind.Http: + case HttpConnectionKind.Https: + case HttpConnectionKind.ProxyConnect: + stream = await ConnectToTcpHostAsync(_originAuthority.IdnHost, _originAuthority.Port, request, async, cancellationToken).ConfigureAwait(false); + // remoteEndPoint is returned for diagnostic purposes. + remoteEndPoint = GetRemoteEndPoint(stream); + if (_kind == HttpConnectionKind.ProxyConnect && _sslOptionsProxy != null) + { + stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, cancellationToken).ConfigureAwait(false); + } + break; - case HttpConnectionKind.Proxy: - stream = await ConnectToTcpHostAsync(_proxyUri!.IdnHost, _proxyUri.Port, request, async, activity, cancellationToken).ConfigureAwait(false); - // remoteEndPoint is returned for diagnostic purposes. - remoteEndPoint = GetRemoteEndPoint(stream); - if (_sslOptionsProxy != null) - { - stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, activity, cancellationToken).ConfigureAwait(false); - } - break; + case HttpConnectionKind.Proxy: + stream = await ConnectToTcpHostAsync(_proxyUri!.IdnHost, _proxyUri.Port, request, async, cancellationToken).ConfigureAwait(false); + // remoteEndPoint is returned for diagnostic purposes. + remoteEndPoint = GetRemoteEndPoint(stream); + if (_sslOptionsProxy != null) + { + stream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptionsProxy, request, async, stream, cancellationToken).ConfigureAwait(false); + } + break; - case HttpConnectionKind.ProxyTunnel: - case HttpConnectionKind.SslProxyTunnel: - stream = await EstablishProxyTunnelAsync(async, activity, cancellationToken).ConfigureAwait(false); + case HttpConnectionKind.ProxyTunnel: + case HttpConnectionKind.SslProxyTunnel: + stream = await EstablishProxyTunnelAsync(async, cancellationToken).ConfigureAwait(false); - if (stream is HttpContentStream contentStream && contentStream._connection?._stream is Stream innerStream) - { - remoteEndPoint = GetRemoteEndPoint(innerStream); - } + if (stream is HttpContentStream contentStream && contentStream._connection?._stream is Stream innerStream) + { + remoteEndPoint = GetRemoteEndPoint(innerStream); + } - break; + break; - case HttpConnectionKind.SocksTunnel: - case HttpConnectionKind.SslSocksTunnel: - stream = await EstablishSocksTunnel(request, async, activity, cancellationToken).ConfigureAwait(false); - // remoteEndPoint is returned for diagnostic purposes. - remoteEndPoint = GetRemoteEndPoint(stream); - break; - } + case HttpConnectionKind.SocksTunnel: + case HttpConnectionKind.SslSocksTunnel: + stream = await EstablishSocksTunnel(request, async, cancellationToken).ConfigureAwait(false); + // remoteEndPoint is returned for diagnostic purposes. + remoteEndPoint = GetRemoteEndPoint(stream); + break; + } - Debug.Assert(stream != null); + Debug.Assert(stream != null); - TransportContext? transportContext = null; - if (IsSecure) - { - SslStream? sslStream = stream as SslStream; - if (sslStream == null) + if (IsSecure) { - sslStream = await ConnectHelper.EstablishSslConnectionAsync(GetSslOptionsForRequest(request), request, async, stream, activity, cancellationToken).ConfigureAwait(false); - } - else - { - if (NetEventSource.Log.IsEnabled()) + SslStream? sslStream = stream as SslStream; + if (sslStream == null) { - Trace($"Connected with custom SslStream: alpn='${sslStream.NegotiatedApplicationProtocol}'"); + sslStream = await ConnectHelper.EstablishSslConnectionAsync(GetSslOptionsForRequest(request), request, async, stream, cancellationToken).ConfigureAwait(false); } + else + { + if (NetEventSource.Log.IsEnabled()) + { + Trace($"Connected with custom SslStream: alpn='${sslStream.NegotiatedApplicationProtocol}'"); + } + } + transportContext = sslStream.TransportContext; + stream = sslStream; } - transportContext = sslStream.TransportContext; - stream = sslStream; } - - if (activity is not null) + catch (Exception ex) when (activity is not null) + { + exception = ex; + throw; + } + finally { - ConnectionSetupDiagnostics.StopConnectionSetupActivity(activity, remoteEndPoint); + if (activity is not null) + { + ConnectionSetupDiagnostics.StopConnectionSetupActivity(activity, exception, remoteEndPoint); + } } return (stream, transportContext, activity, remoteEndPoint); @@ -646,7 +657,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn static IPEndPoint? GetRemoteEndPoint(Stream stream) => (stream as NetworkStream)?.Socket?.RemoteEndPoint as IPEndPoint; } - private async ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, Activity? activity, CancellationToken cancellationToken) + private async ValueTask ConnectToTcpHostAsync(string host, int port, HttpRequestMessage initialRequest, bool async, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -701,11 +712,9 @@ private async ValueTask ConnectToTcpHostAsync(string host, int port, Htt } catch (Exception ex) { - ex = ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? + throw ex is OperationCanceledException oce && oce.CancellationToken == cancellationToken ? CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken) : ConnectHelper.CreateWrappedException(ex, host, port, cancellationToken); - ConnectionSetupDiagnostics.AbortActivity(activity, ex); - throw ex; } } @@ -769,7 +778,7 @@ private async ValueTask ApplyPlaintextFilterAsync(bool async, Stream str return newStream; } - private async ValueTask EstablishProxyTunnelAsync(bool async, Activity? activity, CancellationToken cancellationToken) + private async ValueTask EstablishProxyTunnelAsync(bool async, CancellationToken cancellationToken) { // Send a CONNECT request to the proxy server to establish a tunnel. HttpRequestMessage tunnelRequest = new HttpRequestMessage(HttpMethod.Connect, _proxyUri); @@ -785,44 +794,34 @@ private async ValueTask EstablishProxyTunnelAsync(bool async, Activity? if (tunnelResponse.StatusCode != HttpStatusCode.OK) { tunnelResponse.Dispose(); - Exception ex = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.Format(SR.net_http_proxy_tunnel_returned_failure_status_code, _proxyUri, (int)tunnelResponse.StatusCode)); - ConnectionSetupDiagnostics.AbortActivity(activity, ex); - throw ex; + throw new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.Format(SR.net_http_proxy_tunnel_returned_failure_status_code, _proxyUri, (int)tunnelResponse.StatusCode)); } try { return tunnelResponse.Content.ReadAsStream(cancellationToken); } - catch (Exception ex) + catch { - ConnectionSetupDiagnostics.AbortActivity(activity, ex); tunnelResponse.Dispose(); throw; } } - private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, bool async, Activity? activity, CancellationToken cancellationToken) + private async ValueTask EstablishSocksTunnel(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { Debug.Assert(_proxyUri != null); - Stream stream = await ConnectToTcpHostAsync(_proxyUri.IdnHost, _proxyUri.Port, request, async, activity, cancellationToken).ConfigureAwait(false); + Stream stream = await ConnectToTcpHostAsync(_proxyUri.IdnHost, _proxyUri.Port, request, async, cancellationToken).ConfigureAwait(false); try { await SocksHelper.EstablishSocksTunnelAsync(stream, _originAuthority.IdnHost, _originAuthority.Port, _proxyUri, ProxyCredentials, async, cancellationToken).ConfigureAwait(false); } - catch (Exception e) + catch (Exception e) when (e is not OperationCanceledException) { - if (e is not OperationCanceledException) - { - Debug.Assert(e is not HttpRequestException); - e = new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.net_http_proxy_tunnel_error, e); - ConnectionSetupDiagnostics.AbortActivity(activity, e); - throw e; - } - ConnectionSetupDiagnostics.AbortActivity(activity, e); - throw; + Debug.Assert(e is not HttpRequestException); + throw new HttpRequestException(HttpRequestError.ProxyTunnelError, SR.net_http_proxy_tunnel_error, e); } return stream; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index 9bdfdad274092..9edb9cdda4843 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -29,6 +29,7 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag Debug.Assert(typeof(T) == typeof(HttpConnection) || typeof(T) == typeof(Http2Connection)); long startingTimestamp = Stopwatch.GetTimestamp(); + Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(pool.OriginAuthority); try { @@ -41,11 +42,12 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag } catch (Exception ex) when (waitForConnectionActivity is not null) { - ConnectionSetupDiagnostics.AbortActivity(waitForConnectionActivity, ex); + ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, ex); throw; } finally { + waitForConnectionActivity?.Stop(); TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp); int versionMajor = typeof(T) == typeof(HttpConnection) ? 1 : 2; From c099441d411ffe1c641aae465c448e414950d796 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 9 Jul 2024 23:09:27 +0200 Subject: [PATCH 14/37] address more review feedback --- .../src/System/Net/Http/DiagnosticsHelper.cs | 2 +- .../ConnectionPool/ConnectionSetupDiagnostics.cs | 2 +- .../tests/FunctionalTests/DiagnosticsTests.cs | 4 ++-- .../src/System/Net/NameResolutionMetrics.cs | 4 ++-- .../src/System/Net/NameResolutionTelemetry.cs | 9 ++++----- .../src/System/Net/Sockets/Socket.cs | 10 +++++----- .../src/System/Net/Sockets/SocketAsyncEventArgs.cs | 6 +++--- .../src/System/Net/Sockets/SocketsTelemetry.cs | 5 ++--- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs index 8e3a50f2da3dc..60d2b90da7f06 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs @@ -17,7 +17,7 @@ public static bool TryGetErrorType(HttpResponseMessage? response, Exception? exc // In case the status code indicates a client or a server error, return the string representation of the status code. // See the paragraph Status and the definition of 'error.type' in - // https://github.com/open-telemetry/semantic-conventions/blob/2bad9afad58fbd6b33cc683d1ad1f006e35e4a5d/docs/http/http-spans.md + // https://github.com/open-telemetry/semantic-conventions/blob/release/v1.23.x/docs/http/http-spans.md#Status if (statusCode >= 400 && statusCode <= 599) { errorType = GetErrorStatusCodeString(statusCode); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index 950ddd1ef163d..06fa3d1e5696e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -74,7 +74,7 @@ public static void ReportError(Activity? activity, Exception exception) Activity? activity = s_waitForConnectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); if (activity is not null) { - activity.DisplayName = $"wait_for_connection {authority.HostValue}:{authority.Port}"; + activity.DisplayName = $"HTTP wait_for_connection {authority.HostValue}:{authority.Port}"; } return activity; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index da7b224b346c3..57e28e79193ec 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -464,7 +464,7 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( } // Verify display names and attributes: - Assert.Equal($"wait_for_connection localhost:{uri.Port}", wait1.DisplayName); + Assert.Equal($"HTTP wait_for_connection localhost:{uri.Port}", wait1.DisplayName); Assert.Equal($"HTTP connection_setup localhost:{uri.Port}", conn.DisplayName); ActivityAssert.HasTag(conn, "network.peer.address", (string a) => a == IPAddress.Loopback.ToString() || @@ -1198,7 +1198,7 @@ await RemoteExecutor.Invoke(static async (useVersion, testAsync, parametersStrin { ActivitySource.AddActivityListener(new ActivityListener { - ShouldListenTo = s => s.Name is "System.Net.Http" or "", + ShouldListenTo = s => s.Name is "System.Net.Http", Sample = (ref ActivityCreationOptions _) => { madeASamplingDecision = true; diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs index 0deac114af36d..bd79eb391546e 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionMetrics.cs @@ -19,7 +19,7 @@ internal static class NameResolutionMetrics public static bool IsEnabled() => s_lookupDuration.Enabled; - public static void AfterResolution(TimeSpan duration, string hostName, string? errorType, Exception? exception) + public static void AfterResolution(TimeSpan duration, string hostName, Exception? exception) { var hostNameTag = KeyValuePair.Create("dns.question.name", (object?)hostName); @@ -29,7 +29,7 @@ public static void AfterResolution(TimeSpan duration, string hostName, string? e } else { - errorType ??= NameResolutionTelemetry.GetErrorType(exception); + string errorType = NameResolutionTelemetry.GetErrorType(exception); var errorTypeTag = KeyValuePair.Create("error.type", (object?)errorType); s_lookupDuration.Record(duration.TotalSeconds, hostNameTag, errorTypeTag); } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index b8187b0019be3..3656fcbd9512e 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -91,7 +91,7 @@ public NameResolutionActivity BeforeResolution(object hostNameOrAddress, long st [NonEvent] public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity activity, object? answer, Exception? exception = null) { - if (!activity.Stop(answer, exception, out TimeSpan duration, out string? errorType)) + if (!activity.Stop(answer, exception, out TimeSpan duration)) { // We stopped the System.Diagnostics.Activity at this point and neither metrics nor EventSource is enabled. return; @@ -116,7 +116,7 @@ public void AfterResolution(object hostNameOrAddress, in NameResolutionActivity if (NameResolutionMetrics.IsEnabled()) { - NameResolutionMetrics.AfterResolution(duration, GetHostnameFromStateObject(hostNameOrAddress), errorType, exception); + NameResolutionMetrics.AfterResolution(duration, GetHostnameFromStateObject(hostNameOrAddress), exception); } } @@ -182,9 +182,8 @@ public NameResolutionActivity(object hostNameOrAddress, long startingTimestamp) public static bool IsTracingEnabled() => s_activitySource.HasListeners(); // Returns true if either NameResolutionTelemetry or NameResolutionMetrics is enabled. - public bool Stop(object? answer, Exception? exception, out TimeSpan duration, out string? errorType) + public bool Stop(object? answer, Exception? exception, out TimeSpan duration) { - errorType = null; if (_activity is not null) { if (_activity.IsAllDataRequested) @@ -205,7 +204,7 @@ public bool Stop(object? answer, Exception? exception, out TimeSpan duration, ou else { Debug.Assert(exception is not null); - errorType = NameResolutionTelemetry.GetErrorType(exception); + string errorType = NameResolutionTelemetry.GetErrorType(exception); _activity.SetTag("error.type", errorType); } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index b9a5116da4687..e4f7f41e87600 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2782,7 +2782,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan WildcardBindForConnectIfNecessary(endPointSnapshot.AddressFamily); - e._activity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); + e._connectActivity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); // Prepare for the native call. try @@ -2792,8 +2792,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._activity, ex.Message); - e._activity = null; + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._connectActivity, ex.Message); + e._connectActivity = null; throw; } @@ -2809,8 +2809,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._activity, ex.Message); - e._activity = null; + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._connectActivity, ex.Message); + e._connectActivity = null; _localEndPoint = null; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index d22feee4feced..c9398fb7dda8c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -74,7 +74,7 @@ public partial class SocketAsyncEventArgs : EventArgs, IDisposable private Socket? _currentSocket; private bool _userSocket; // if false when performing Connect, _currentSocket should be disposed private bool _disposeCalled; - internal Activity? _activity; + internal Activity? _connectActivity; // Controls thread safety via Interlocked. private const int Configuring = -1; @@ -225,8 +225,8 @@ private void AfterConnectAcceptTelemetry() break; case SocketAsyncOperation.Connect: - SocketsTelemetry.Log.AfterConnect(SocketError, _activity); - _activity = null; + SocketsTelemetry.Log.AfterConnect(SocketError, _connectActivity); + _connectActivity = null; break; default: diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index fa03c1fa5c1c9..3dd07e1150f31 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -106,12 +106,11 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) { if (endPoint is IPEndPoint ipEndPoint) { - string peerAddress = ipEndPoint.Address.ToString(); int port = ipEndPoint.Port; - activity.DisplayName = $"socket connect {peerAddress}:{port}"; + activity.DisplayName = $"socket connect {ipEndPoint.Address}:{port}"; if (activity.IsAllDataRequested) { - activity.SetTag("network.peer.address", peerAddress); + activity.SetTag("network.peer.address", ipEndPoint.Address.ToString()); activity.SetTag("network.peer.port", port); activity.SetTag("network.type", ipEndPoint.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); } From 17e62a08af65480ef05923f9ca259dff5f9006b5 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 00:50:46 +0200 Subject: [PATCH 15/37] merge stuff --- .config/guardian/.gdnbaselines | 47 - docs/design/datacontracts/Exception.md | 40 +- docs/design/datacontracts/Loader.md | 107 +++ eng/Version.Details.xml | 120 +-- eng/Versions.props | 52 +- global.json | 2 +- .../System.Private.CoreLib.sln | 406 ++++++++- src/coreclr/binder/bindertracing.cpp | 2 +- src/coreclr/debug/daccess/daccess.cpp | 1 + src/coreclr/debug/daccess/dacimpl.h | 3 + src/coreclr/debug/daccess/request.cpp | 104 ++- src/coreclr/debug/runtimeinfo/contracts.jsonc | 1 + .../debug/runtimeinfo/datadescriptor.h | 34 + src/coreclr/dlls/mscorrc/mscorrc.rc | 2 - src/coreclr/dlls/mscorrc/resource.h | 4 +- src/coreclr/jit/compiler.h | 4 +- src/coreclr/jit/gschecks.cpp | 3 + src/coreclr/jit/hwintrinsicarm64.cpp | 2 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 10 +- src/coreclr/jit/hwintrinsiclistarm64sve.h | 16 +- src/coreclr/jit/lclmorph.cpp | 9 +- src/coreclr/jit/lclvars.cpp | 6 - src/coreclr/jit/liveness.cpp | 114 ++- src/coreclr/jit/lsraarm64.cpp | 18 +- src/coreclr/jit/promotion.h | 17 +- src/coreclr/jit/promotionliveness.cpp | 76 +- src/coreclr/nativeaot/nativeaot.sln | 485 +++++++++-- .../pal/src/exception/machexception.cpp | 21 +- src/coreclr/pal/src/exception/machmessage.h | 2 +- src/coreclr/pal/src/thread/context.cpp | 12 + .../Compiler/ExportsFileWriter.cs | 17 +- src/coreclr/utilcode/check.cpp | 2 +- src/coreclr/utilcode/debug.cpp | 2 +- src/coreclr/vm/appdomain.cpp | 14 +- src/coreclr/vm/appdomain.hpp | 4 +- src/coreclr/vm/assembly.cpp | 16 +- src/coreclr/vm/assembly.hpp | 5 +- src/coreclr/vm/assemblynative.cpp | 22 +- src/coreclr/vm/assemblyspec.cpp | 10 +- src/coreclr/vm/assemblyspec.hpp | 12 +- src/coreclr/vm/callconvbuilder.cpp | 8 +- src/coreclr/vm/ceeload.cpp | 79 +- src/coreclr/vm/ceeload.h | 25 +- src/coreclr/vm/clsload.cpp | 22 +- src/coreclr/vm/clsload.hpp | 1 - src/coreclr/vm/customattribute.cpp | 34 +- src/coreclr/vm/customattribute.h | 2 +- src/coreclr/vm/domainassembly.cpp | 36 - src/coreclr/vm/domainassembly.h | 9 - src/coreclr/vm/eventtrace.cpp | 2 +- src/coreclr/vm/interoputil.cpp | 12 +- src/coreclr/vm/nativeimage.cpp | 2 +- src/coreclr/vm/nativeimage.h | 2 +- src/coreclr/vm/object.h | 17 +- src/coreclr/vm/peassembly.cpp | 47 +- src/coreclr/vm/peassembly.h | 6 +- src/coreclr/vm/typeparse.cpp | 2 +- src/coreclr/vm/zapsig.cpp | 2 +- .../Interop.OpenSsl.cs | 10 + .../Interop/Windows/SspiCli/ISSPIInterface.cs | 4 +- .../Interop/Windows/SspiCli/SSPIAuthType.cs | 8 +- .../Windows/SspiCli/SSPISecureChannelType.cs | 8 +- .../Interop/Windows/SspiCli/SSPIWrapper.cs | 8 +- .../Windows/SspiCli/SecuritySafeHandles.cs | 111 +-- .../Net/Security/SecurityBuffer.Windows.cs | 8 +- .../Net/Prerequisites/Deployment/config.ps1 | 59 -- .../Net/Prerequisites/Deployment/setup.ps1 | 225 ----- .../setup_activedirectory_client.ps1 | 86 -- ...setup_activedirectory_domaincontroller.ps1 | 94 -- .../Deployment/setup_certificates.ps1 | 128 --- .../Prerequisites/Deployment/setup_client.ps1 | 63 -- .../Prerequisites/Deployment/setup_common.ps1 | 149 ---- .../Deployment/setup_firewall.ps1 | 31 - .../Deployment/setup_iisserver.ps1 | 199 ----- .../tests/System/Net/Prerequisites/README.md | 38 - .../tests/System/Net/SslProtocolSupport.cs | 38 +- .../System/IO/Compression/ZipFile.Extract.cs | 6 +- .../src/System.Net.Http.csproj | 2 +- .../src/System/Net/Http/DiagnosticsHandler.cs | 58 +- .../src/System/Net/Http/DiagnosticsHelper.cs | 41 + .../src/System/Net/Http/GlobalHttpSettings.cs | 5 + .../System/Net/Http/Metrics/MetricsHandler.cs | 20 +- .../Metrics/SocketsHttpHandlerMetrics.cs | 2 +- .../tests/FunctionalTests/DiagnosticsTests.cs | 200 ++++- .../tests/FunctionalTests/MetricsTest.cs | 59 +- .../tests/UnitTests/DiagnosticsHelperTest.cs | 116 +++ .../System.Net.Http.Unit.Tests.csproj | 3 + .../MsQuicCipherSuitesPolicyTests.cs | 14 +- .../tests/FunctionalTests/MsQuicTests.cs | 8 +- .../FunctionalTests/QuicListenerTests.cs | 3 +- .../tests/FunctionalTests/QuicStreamTests.cs | 46 +- .../FunctionalTests/QuicTestCollection.cs | 31 +- .../Net/NegotiateAuthenticationPal.Windows.cs | 4 +- .../src/System/Net/Security/SslStream.IO.cs | 15 +- .../System/Net/Security/SslStream.Protocol.cs | 15 +- .../Net/Security/SslStreamPal.Android.cs | 10 +- .../System/Net/Security/SslStreamPal.OSX.cs | 11 +- .../System/Net/Security/SslStreamPal.Unix.cs | 13 +- .../Net/Security/SslStreamPal.Windows.cs | 22 +- .../SslStreamAllowTlsResumeTests.cs | 13 +- .../FunctionalTests/SslStreamFramingTest.cs | 207 +++++ .../System.Net.Security.Tests.csproj | 1 + .../src/Resources/Strings.resx | 6 + .../src/System/Int128.cs | 4 +- .../System/Threading/ThreadPoolWorkQueue.cs | 103 ++- .../src/System/UInt128.cs | 4 +- .../Runtime/Serialization/SchemaExporter.cs | 3 +- .../GetObjectForIUnknownTests.Windows.cs | 70 ++ .../src/System/Numerics/BigInteger.cs | 11 +- .../MethodCoverage.cs | 2 + ...syncEnumerableToBlockingEnumerableTests.cs | 3 + .../Task/TaskContinueWithTests.cs | 2 + .../System.Text.Json/ref/System.Text.Json.cs | 1 + .../Text/Json/Schema/JsonSchemaExporter.cs | 12 +- .../Json/Schema/JsonSchemaExporterContext.cs | 12 +- .../tests/Common/JsonSchemaExporterTests.cs | 33 + .../tests/ThreadPoolTests.cs | 83 ++ .../System.Threading/tests/MutexTests.cs | 1 + .../tests/SemaphoreSlimTests.cs | 1 + .../System.Private.CoreLib.sln | 805 +++++++++++++++++- src/mono/browser/runtime/cwraps.ts | 2 +- src/mono/wasi/build/WasiApp.targets | 10 +- src/mono/wasm/host/BrowserHost.cs | 6 - .../CMakeLists.txt | 2 +- .../pal_jni.c | 5 +- .../pal_jni.h | 5 + .../pal_jni_onload.c | 10 + .../cdacreader/src/Contracts/Exception.cs | 13 +- .../cdacreader/src/Contracts/Exception_1.cs | 20 +- .../cdacreader/src/Contracts/Loader.cs | 62 ++ .../cdacreader/src/Contracts/Loader_1.cs | 73 ++ .../cdacreader/src/Contracts/Registry.cs | 1 + .../managed/cdacreader/src/Data/Exception.cs | 33 + .../managed/cdacreader/src/Data/Module.cs | 96 +++ src/native/managed/cdacreader/src/DataType.cs | 3 +- .../cdacreader/src/Legacy/ISOSDacInterface.cs | 56 +- .../cdacreader/src/Legacy/SOSDacImpl.cs | 79 +- 137 files changed, 4003 insertions(+), 1953 deletions(-) delete mode 100644 .config/guardian/.gdnbaselines create mode 100644 docs/design/datacontracts/Loader.md delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/config.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_client.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_domaincontroller.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_certificates.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_client.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_common.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_firewall.ps1 delete mode 100644 src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_iisserver.ps1 create mode 100644 src/libraries/System.Net.Http/tests/UnitTests/DiagnosticsHelperTest.cs create mode 100644 src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamFramingTest.cs create mode 100644 src/native/libs/System.Security.Cryptography.Native.Android/pal_jni_onload.c create mode 100644 src/native/managed/cdacreader/src/Contracts/Loader.cs create mode 100644 src/native/managed/cdacreader/src/Contracts/Loader_1.cs create mode 100644 src/native/managed/cdacreader/src/Data/Exception.cs create mode 100644 src/native/managed/cdacreader/src/Data/Module.cs diff --git a/.config/guardian/.gdnbaselines b/.config/guardian/.gdnbaselines deleted file mode 100644 index 5518c7ef9126d..0000000000000 --- a/.config/guardian/.gdnbaselines +++ /dev/null @@ -1,47 +0,0 @@ -{ - "properties": { - "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines" - }, - "version": "1.0.0", - "baselines": { - "default": { - "name": "default", - "createdDate": "2024-04-10 20:32:31Z", - "lastUpdatedDate": "2024-04-10 20:32:31Z" - } - }, - "results": { - "2e4598005fdee72a4700697760c5f1b199c25d15a7c54de438ce939f125f3710": { - "signature": "2e4598005fdee72a4700697760c5f1b199c25d15a7c54de438ce939f125f3710", - "alternativeSignatures": [ - "6b533da7f95704f4476b24f493f88b2b1fd7d3bba69105bf63530140e0b3c8f1" - ], - "target": "src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_domaincontroller.ps1", - "line": 36, - "memberOf": [ - "default" - ], - "tool": "psscriptanalyzer", - "ruleId": "PSAvoidUsingConvertToSecureStringWithPlainText", - "createdDate": "2024-04-10 20:32:31Z", - "expirationDate": "2024-09-28 00:14:56Z", - "justification": "This error is baselined with an expiration date of 180 days from 2024-04-11 00:14:56Z" - }, - "df6d1096725378c354a363dbb40fca84b9eed42a724ffbde7de57a88fc4042df": { - "signature": "df6d1096725378c354a363dbb40fca84b9eed42a724ffbde7de57a88fc4042df", - "alternativeSignatures": [ - "b090ab235a86ec5bc15243c19bc432f09e5aef816854bcbe120ab04c7c0332e1" - ], - "target": "src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_iisserver.ps1", - "line": 82, - "memberOf": [ - "default" - ], - "tool": "psscriptanalyzer", - "ruleId": "PSAvoidUsingConvertToSecureStringWithPlainText", - "createdDate": "2024-04-10 20:32:31Z", - "expirationDate": "2024-09-28 00:14:56Z", - "justification": "This error is baselined with an expiration date of 180 days from 2024-04-11 00:14:56Z" - } - } -} \ No newline at end of file diff --git a/docs/design/datacontracts/Exception.md b/docs/design/datacontracts/Exception.md index e507c23f00c4f..61455b180d76c 100644 --- a/docs/design/datacontracts/Exception.md +++ b/docs/design/datacontracts/Exception.md @@ -1,28 +1,56 @@ -# Contract Thread +# Contract Exception This contract is for getting information about exceptions in the process. ## APIs of contract +```csharp +record struct ExceptionData( + TargetPointer Message, + TargetPointer InnerException, + TargetPointer StackTrace, + TargetPointer WatsonBuckets, + TargetPointer StackTraceString, + TargetPointer RemoteStackTraceString, + int HResult, + int XCode); +``` + ``` csharp -TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException); +TargetPointer GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo); +ExceptionData GetExceptionData(TargetPointer exceptionAddr) ``` ## Version 1 Data descriptors used: - `ExceptionInfo` +- `Exception` ``` csharp -TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) +TargetPointer GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo) { - if (exception == TargetPointer.Null) + if (exceptionInfo == TargetPointer.Null) throw new InvalidArgumentException(); - nextNestedException = target.ReadPointer(address + /* ExceptionInfo::PreviousNestedInfo offset*/); - TargetPointer thrownObjHandle = target.ReadPointer(address + /* ExceptionInfo::ThrownObject offset */); + nextNestedException = target.ReadPointer(exceptionInfo + /* ExceptionInfo::PreviousNestedInfo offset*/); + TargetPointer thrownObjHandle = target.ReadPointer(exceptionInfo + /* ExceptionInfo::ThrownObject offset */); return = thrownObjHandle != TargetPointer.Null ? target.ReadPointer(thrownObjHandle) : TargetPointer.Null; } + +ExceptionData GetExceptionData(TargetPointer exceptionAddr) +{ + return new ExceptionData( + target.ReadPointer(exceptionAddr + /* Exception::Message offset */), + target.ReadPointer(exceptionAddr + /* Exception::InnerException offset */), + target.ReadPointer(exceptionAddr + /* Exception::StackTrace offset */), + target.ReadPointer(exceptionAddr + /* Exception::WatsonBuckets offset */), + target.ReadPointer(exceptionAddr + /* Exception::StackTraceString offset */), + target.ReadPointer(exceptionAddr + /* Exception::RemoteStackTraceString offset */), + target.Read(exceptionAddr + /* Exception::HResult offset */), + target.Read(exceptionAddr + /* Exception::XCode offset */), + ); +} ``` diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md new file mode 100644 index 0000000000000..4291c96569b27 --- /dev/null +++ b/docs/design/datacontracts/Loader.md @@ -0,0 +1,107 @@ +# Contract Loader + +This contract is for getting information about loaded modules and assemblies + +## APIs of contract + +``` csharp +readonly struct ModuleHandle +{ + // Opaque handle - no public members + + internal TargetPointer Address; +} + +[Flags] +enum ModuleFlags +{ + EditAndContinue = 0x00000008, // Edit and Continue is enabled for this module + ReflectionEmit = 0x00000040, // Reflection.Emit was used to create this module +} + +record struct ModuleLookupTables( + TargetPointer FieldDefToDesc, + TargetPointer ManifestModuleReferences, + TargetPointer MemberRefToDesc, + TargetPointer MethodDefToDesc, + TargetPointer TypeDefToMethodTable, + TargetPointer TypeRefToMethodTable); +``` + +``` csharp +ModuleHandle GetModuleHandle(TargetPointer); +TargetPointer GetAssembly(ModuleHandle handle); +ModuleFlags GetFlags(ModuleHandle handle); +TargetPointer GetLoaderAllocator(ModuleHandle handle); +TargetPointer GetThunkHeap(ModuleHandle handle); +TargetPointer GetILBase(ModuleHandle handle); +TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size); +ModuleLookupTables GetLookupTables(ModuleHandle handle); +``` + +## Version 1 + +Data descriptors used: +- `Module` + +``` csharp +ModuleHandle GetModuleHandle(TargetPointer modulePointer) +{ + return new ModuleHandle(modulePointer); +} + +TargetPointer GetAssembly(ModuleHandle handle) +{ + return target.ReadPointer(handle.Address + /* Module::Assrembly offset */); +} + +ModuleFlags GetFlags(ModuleHandle handle) +{ + return target.Read(handle.Address + /* Module::Flags offset */); +} + +TargetPointer GetLoaderAllocator(ModuleHandle handle) +{ + return target.ReadPointer(handle.Address + /* Module::LoaderAllocator offset */); +} + +TargetPointer GetThunkHeap(ModuleHandle handle) +{ + return target.ReadPointer(handle.Address + /* Module::ThunkHeap offset */); +} + +TargetPointer GetILBase(ModuleHandle handle) +{ + return target.ReadPointer(handle.Address + /* Module::Base offset */); +} + +TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size) +{ + TargetPointer baseAddress = GetILBase(handle); + if (baseAddress == TargetPointer.Null) + { + size = 0; + return TargetPointer.Null; + } + + // Read CLR header per https://learn.microsoft.com/windows/win32/debug/pe-format + ulong clrHeaderRVA = ... + + // Read Metadata per ECMA-335 II.25.3.3 CLI Header + ulong metadataDirectoryAddress = baseAddress + clrHeaderRva + /* offset to Metadata */ + int rva = target.Read(metadataDirectoryAddress); + size = target.Read(metadataDirectoryAddress + sizeof(int)); + return baseAddress + rva; +} + +ModuleLookupTables GetLookupTables(ModuleHandle handle) +{ + return new ModuleLookupTables( + FieldDefToDescMap: target.ReadPointer(handle.Address + /* Module::FieldDefToDescMap */), + ManifestModuleReferencesMap: target.ReadPointer(handle.Address + /* Module::ManifestModuleReferencesMap */), + MemberRefToDescMap: target.ReadPointer(handle.Address + /* Module::MemberRefToDescMap */), + MethodDefToDescMap: target.ReadPointer(handle.Address + /* Module::MethodDefToDescMap */), + TypeDefToMethodTableMap: target.ReadPointer(handle.Address + /* Module::TypeDefToMethodTableMap */), + TypeRefToMethodTableMap: target.ReadPointer(handle.Address + /* Module::TypeRefToMethodTableMap */)); +} +``` diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 458372435e0d6..37b6d2ba26aca 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - d7046f8482b4e470a2c9046998671f86dd69773c + 42787a07ecba682549f520293bb5a6941bdccb50 https://github.com/dotnet/msquic @@ -12,9 +12,9 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/emsdk - ffe9afdc046cf7a6f82cc7c5796aade54047af64 + d3583522209829d1ed0440662ba136c7b7700b16 https://github.com/dotnet/llvm-project @@ -68,14 +68,14 @@ 7e4af02521473d89d6144b3da58fef253e498974 - + https://github.com/dotnet/emsdk - ffe9afdc046cf7a6f82cc7c5796aade54047af64 + d3583522209829d1ed0440662ba136c7b7700b16 - + https://github.com/dotnet/emsdk - ffe9afdc046cf7a6f82cc7c5796aade54047af64 + d3583522209829d1ed0440662ba136c7b7700b16 @@ -174,57 +174,57 @@ https://github.com/dotnet/arcade ede13bd35571c0c8b0c01edcb057031904c5c955 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 https://github.com/dotnet/llvm-project @@ -282,43 +282,43 @@ https://github.com/dotnet/llvm-project 26f8c30340764cfa7fa9090dc01a36c222bf09c1 - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b - + https://github.com/dotnet/runtime - d38e5593427f63e513ca3be11c3fdccb07b88ce1 + 4e278fe17f69ea31fbdcbab74ac47ec6fa84914b https://github.com/dotnet/xharness @@ -352,13 +352,13 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization c3acfd159662959ff09f3a0d7663023db48bb78a - + https://github.com/dotnet/hotreload-utils - 10963c8df78c0881bc5fad76657fce2ddc6e47b4 + 48812ad620b54916f684b7e7ff885de8ad675ebf - + https://github.com/dotnet/runtime-assets - ec2da34cd7e31a605d6f30f02021a8d76947c99d + 0cab6ca16f49b666163d4e1c0e3c080faf5a4e05 https://github.com/dotnet/roslyn @@ -386,14 +386,14 @@ 19b5e961ecb97b008106f1b646c077e0bffde4a7 - + https://github.com/dotnet/sdk - ea9243f9cb36e56aba4cf6364a4d53a5c2d458fb + 5e03abbcf74bdef38ca67f04fbd4982e333d1f58 - + https://github.com/dotnet/sdk - ea9243f9cb36e56aba4cf6364a4d53a5c2d458fb + 5e03abbcf74bdef38ca67f04fbd4982e333d1f58 diff --git a/eng/Versions.props b/eng/Versions.props index 9c5aae615e1b3..e608e4e4d1a2d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -81,7 +81,7 @@ 0.2.0 - 9.0.100-preview.7.24323.5 + 9.0.100-preview.7.24358.3 9.0.0-beta.24327.1 9.0.0-beta.24327.1 @@ -104,10 +104,10 @@ 6.0.0-preview.1.102 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 6.0.0 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 6.0.0 1.1.1 @@ -119,39 +119,39 @@ 8.0.0 5.0.0 4.5.5 - 9.0.0-preview.6.24323.2 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 + 9.0.0-preview.7.24357.2 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 6.0.0 7.0.0 4.5.4 4.5.0 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 8.0.0 8.0.0 8.0.0 8.0.0 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 - 9.0.0-beta.24324.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 + 9.0.0-beta.24358.1 1.0.0-prerelease.24223.3 1.0.0-prerelease.24223.3 @@ -184,7 +184,7 @@ 9.0.0-prerelease.24317.3 9.0.0-prerelease.24317.3 9.0.0-prerelease.24317.3 - 9.0.0-alpha.0.24324.1 + 9.0.0-alpha.0.24351.1 3.12.0 4.5.0 6.0.0 @@ -214,9 +214,9 @@ 0.11.5-alpha.24324.1 - 9.0.0-preview.6.24323.2 + 9.0.0-preview.7.24357.2 - 9.0.0-preview.7.24324.1 + 9.0.0-preview.7.24358.1 2.3.5 9.0.0-alpha.1.24167.3 @@ -239,9 +239,9 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-9_0_100_Transport --> - 9.0.0-preview.7.24319.4 + 9.0.0-preview.7.24352.2 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion) - 9.0.0-preview.7.24319.4 + 9.0.0-preview.7.24352.2 1.1.87-gba258badda 1.0.0-v3.14.0.5722 diff --git a/global.json b/global.json index 1200b9dd2ff71..b46b6d43bf3ec 100644 --- a/global.json +++ b/global.json @@ -13,6 +13,6 @@ "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24327.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.6.24323.2" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.7.24357.2" } } diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln index 66c65e680d469..ccd486794b792 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28902.138 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35017.193 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "System.Private.CoreLib.csproj", "{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}" EndProject @@ -8,26 +8,59 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "System.Private.CoreLib.Shar EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "..\..\libraries\System.Private.CoreLib\gen\System.Private.CoreLib.Generators.csproj", "{7196828B-5E00-4BC6-9A1E-492C948E41A3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.Tasks", "..\..\tools\illink\src\ILLink.Tasks\ILLink.Tasks.csproj", "{EE093971-5189-4438-84CF-EBC8C8AC7713}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{D47C8483-58B6-4669-A2CF-9EF1C26C3F48}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.RoslynAnalyzer", "..\..\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj", "{F4311FB3-2A1D-4309-AEAE-324373B56163}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.CodeFixProvider", "..\..\tools\illink\src\ILLink.CodeFix\ILLink.CodeFixProvider.csproj", "{13D30D8B-8997-4D6C-B09B-BD2A7F238420}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\Mono.Linker.csproj", "{94712627-28B7-4757-8988-4259DC7E9F5F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.DependencyAnalysisFramework", "..\tools\aot\ILCompiler.DependencyAnalysisFramework\ILCompiler.DependencyAnalysisFramework.csproj", "{FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{AC9B32A7-1C99-4915-83D9-7A47DD22B9B6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0D24A796-E606-41C0-BEB5-8621A7568E01}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{265BA810-289A-4BD6-8DEB-F896F8011365}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\ref\Mono.Linker.csproj", "{6574A353-18D4-4198-A2CE-12FF3CC5AA0A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{520534D2-D466-499B-81BA-F005DEEB3BA9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{4847C9F6-F653-4A8C-9150-65C250112D66}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\..\libraries\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{C99433C1-ADDE-4077-8590-207ADC67ED41}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\..\libraries\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{04388B88-25F9-4CDA-AA6F-FB839A9C2A58}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{C0B7FE54-16F9-46A8-B9A7-7577A97F01C9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\libraries\System.Private.CoreLib\ref\System.Private.CoreLib.csproj", "{58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ILLink.Shared", "..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.shproj", "{FF598E93-8E9E-4091-9F50-61A7572663AE}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{3da06c3a-2e7b-4cb7-80ed-9b12916013f9}*SharedItemsImports = 5 - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|amd64 = Checked|amd64 Checked|Any CPU = Checked|Any CPU Checked|arm = Checked|arm Checked|arm64 = Checked|arm64 + Checked|x64 = Checked|x64 Checked|x86 = Checked|x86 Debug|amd64 = Debug|amd64 Debug|Any CPU = Debug|Any CPU Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 + Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|amd64 = Release|amd64 Release|Any CPU = Release|Any CPU Release|arm = Release|arm Release|arm64 = Release|arm64 + Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution @@ -38,6 +71,8 @@ Global {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm.Build.0 = Checked|arm {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm64.ActiveCfg = Checked|arm64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm64.Build.0 = Checked|arm64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|x64.ActiveCfg = Checked|x64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|x64.Build.0 = Checked|x64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|x86.ActiveCfg = Checked|x86 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|x86.Build.0 = Checked|x86 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|amd64.ActiveCfg = Debug|x64 @@ -47,6 +82,8 @@ Global {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm.Build.0 = Debug|arm {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm64.ActiveCfg = Debug|arm64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm64.Build.0 = Debug|arm64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|x64.ActiveCfg = Debug|x64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|x64.Build.0 = Debug|x64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|x86.ActiveCfg = Debug|x86 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|x86.Build.0 = Debug|x86 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|amd64.ActiveCfg = Release|x64 @@ -56,6 +93,8 @@ Global {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm.Build.0 = Release|arm {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm64.ActiveCfg = Release|arm64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm64.Build.0 = Release|arm64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x64.ActiveCfg = Release|x64 + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x64.Build.0 = Release|x64 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x86.ActiveCfg = Release|x86 {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x86.Build.0 = Release|x86 {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|amd64.ActiveCfg = Debug|Any CPU @@ -66,6 +105,8 @@ Global {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm.Build.0 = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm64.ActiveCfg = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm64.Build.0 = Debug|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x64.ActiveCfg = Release|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x64.Build.0 = Release|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x86.ActiveCfg = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x86.Build.0 = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|amd64.ActiveCfg = Debug|Any CPU @@ -76,6 +117,8 @@ Global {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm.Build.0 = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm64.ActiveCfg = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm64.Build.0 = Debug|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x64.ActiveCfg = Debug|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x64.Build.0 = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x86.ActiveCfg = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x86.Build.0 = Debug|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|amd64.ActiveCfg = Release|Any CPU @@ -86,13 +129,364 @@ Global {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm.Build.0 = Release|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm64.ActiveCfg = Release|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm64.Build.0 = Release|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x64.ActiveCfg = Release|Any CPU + {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x64.Build.0 = Release|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x86.ActiveCfg = Release|Any CPU {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x86.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|amd64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|amd64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|Any CPU.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|arm.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|arm.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|arm64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|arm64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|x64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|x64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|x86.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Checked|x86.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|amd64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|amd64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|arm.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|arm.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|arm64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|arm64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|x64.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|x64.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|x86.ActiveCfg = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Debug|x86.Build.0 = Debug|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|amd64.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|amd64.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|Any CPU.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|arm.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|arm.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|arm64.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|arm64.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|x64.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|x64.Build.0 = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|x86.ActiveCfg = Release|Any CPU + {EE093971-5189-4438-84CF-EBC8C8AC7713}.Release|x86.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|amd64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|amd64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|Any CPU.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|arm.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|arm.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|arm64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|arm64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|x64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|x64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|x86.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Checked|x86.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|amd64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|amd64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|arm.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|arm.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|arm64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|arm64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|x64.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|x64.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|x86.ActiveCfg = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Debug|x86.Build.0 = Debug|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|amd64.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|amd64.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|Any CPU.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|arm.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|arm.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|arm64.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|arm64.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|x64.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|x64.Build.0 = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|x86.ActiveCfg = Release|Any CPU + {F4311FB3-2A1D-4309-AEAE-324373B56163}.Release|x86.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|amd64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|amd64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|Any CPU.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|arm.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|arm.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|arm64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|arm64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|x64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|x64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|x86.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Checked|x86.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|amd64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|amd64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|arm.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|arm.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|arm64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|arm64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|x64.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|x64.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|x86.ActiveCfg = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Debug|x86.Build.0 = Debug|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|amd64.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|amd64.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|Any CPU.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|arm.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|arm.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|arm64.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|arm64.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|x64.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|x64.Build.0 = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|x86.ActiveCfg = Release|Any CPU + {13D30D8B-8997-4D6C-B09B-BD2A7F238420}.Release|x86.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|amd64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|amd64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|Any CPU.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|arm.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|arm.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|arm64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|arm64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|x64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|x64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|x86.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Checked|x86.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|amd64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|amd64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|arm.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|arm.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|arm64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|arm64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|x64.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|x64.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|x86.ActiveCfg = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Debug|x86.Build.0 = Debug|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|amd64.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|amd64.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|Any CPU.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|arm.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|arm.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|arm64.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|arm64.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|x64.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|x64.Build.0 = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|x86.ActiveCfg = Release|Any CPU + {94712627-28B7-4757-8988-4259DC7E9F5F}.Release|x86.Build.0 = Release|Any CPU + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|amd64.ActiveCfg = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|amd64.Build.0 = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|Any CPU.ActiveCfg = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|Any CPU.Build.0 = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|arm.ActiveCfg = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|arm.Build.0 = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|arm64.ActiveCfg = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|arm64.Build.0 = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|x64.ActiveCfg = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|x64.Build.0 = Checked|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|x86.ActiveCfg = Checked|x86 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Checked|x86.Build.0 = Checked|x86 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|amd64.ActiveCfg = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|amd64.Build.0 = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|Any CPU.ActiveCfg = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|Any CPU.Build.0 = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|arm.ActiveCfg = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|arm.Build.0 = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|arm64.ActiveCfg = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|arm64.Build.0 = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|x64.ActiveCfg = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|x64.Build.0 = Debug|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|x86.ActiveCfg = Debug|x86 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Debug|x86.Build.0 = Debug|x86 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|amd64.ActiveCfg = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|amd64.Build.0 = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|Any CPU.ActiveCfg = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|Any CPU.Build.0 = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|arm.ActiveCfg = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|arm.Build.0 = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|arm64.ActiveCfg = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|arm64.Build.0 = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|x64.ActiveCfg = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|x64.Build.0 = Release|x64 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|x86.ActiveCfg = Release|x86 + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E}.Release|x86.Build.0 = Release|x86 + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|amd64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|amd64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|Any CPU.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|arm.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|arm.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|arm64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|arm64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|x64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|x64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|x86.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Checked|x86.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|amd64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|amd64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|arm.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|arm.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|arm64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|arm64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|x64.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|x64.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|x86.ActiveCfg = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Debug|x86.Build.0 = Debug|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|amd64.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|amd64.Build.0 = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|Any CPU.Build.0 = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|arm.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|arm.Build.0 = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|arm64.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|arm64.Build.0 = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|x64.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|x64.Build.0 = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|x86.ActiveCfg = Release|Any CPU + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A}.Release|x86.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|amd64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|amd64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|Any CPU.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|arm.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|arm.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|arm64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|arm64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|x64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|x64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|x86.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Checked|x86.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|amd64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|amd64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|arm.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|arm.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|arm64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|arm64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|x64.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|x64.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|x86.ActiveCfg = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Debug|x86.Build.0 = Debug|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|amd64.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|amd64.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|Any CPU.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|arm.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|arm.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|arm64.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|arm64.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|x64.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|x64.Build.0 = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|x86.ActiveCfg = Release|Any CPU + {C99433C1-ADDE-4077-8590-207ADC67ED41}.Release|x86.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|amd64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|amd64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|Any CPU.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|arm.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|arm.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|arm64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|arm64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|x64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|x64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|x86.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Checked|x86.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|amd64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|amd64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|arm.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|arm.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|arm64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|arm64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|x64.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|x64.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|x86.ActiveCfg = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Debug|x86.Build.0 = Debug|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|amd64.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|amd64.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|Any CPU.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|arm.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|arm.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|arm64.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|arm64.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|x64.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|x64.Build.0 = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|x86.ActiveCfg = Release|Any CPU + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58}.Release|x86.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|amd64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|amd64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|Any CPU.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|arm.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|arm.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|arm64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|arm64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|x64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|x64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|x86.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Checked|x86.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|amd64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|amd64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|arm.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|arm.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|arm64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|arm64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|x64.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|x64.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|x86.ActiveCfg = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Debug|x86.Build.0 = Debug|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|amd64.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|amd64.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|Any CPU.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|arm.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|arm.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|arm64.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|arm64.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|x64.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|x64.Build.0 = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|x86.ActiveCfg = Release|Any CPU + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9} = {520534D2-D466-499B-81BA-F005DEEB3BA9} + {845C8B26-350B-4E63-BD11-2C8150444E28} = {520534D2-D466-499B-81BA-F005DEEB3BA9} + {7196828B-5E00-4BC6-9A1E-492C948E41A3} = {4847C9F6-F653-4A8C-9150-65C250112D66} + {EE093971-5189-4438-84CF-EBC8C8AC7713} = {0D24A796-E606-41C0-BEB5-8621A7568E01} + {F4311FB3-2A1D-4309-AEAE-324373B56163} = {265BA810-289A-4BD6-8DEB-F896F8011365} + {13D30D8B-8997-4D6C-B09B-BD2A7F238420} = {265BA810-289A-4BD6-8DEB-F896F8011365} + {94712627-28B7-4757-8988-4259DC7E9F5F} = {0D24A796-E606-41C0-BEB5-8621A7568E01} + {FCF6BB26-EBD8-40FA-B33A-02E86D543C2E} = {0D24A796-E606-41C0-BEB5-8621A7568E01} + {AC9B32A7-1C99-4915-83D9-7A47DD22B9B6} = {D47C8483-58B6-4669-A2CF-9EF1C26C3F48} + {0D24A796-E606-41C0-BEB5-8621A7568E01} = {D47C8483-58B6-4669-A2CF-9EF1C26C3F48} + {265BA810-289A-4BD6-8DEB-F896F8011365} = {D47C8483-58B6-4669-A2CF-9EF1C26C3F48} + {6574A353-18D4-4198-A2CE-12FF3CC5AA0A} = {AC9B32A7-1C99-4915-83D9-7A47DD22B9B6} + {C99433C1-ADDE-4077-8590-207ADC67ED41} = {4847C9F6-F653-4A8C-9150-65C250112D66} + {04388B88-25F9-4CDA-AA6F-FB839A9C2A58} = {4847C9F6-F653-4A8C-9150-65C250112D66} + {58A9924A-2C19-4BF1-8F22-B3E7F74F9BAF} = {C0B7FE54-16F9-46A8-B9A7-7577A97F01C9} + {FF598E93-8E9E-4091-9F50-61A7572663AE} = {0D24A796-E606-41C0-BEB5-8621A7568E01} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DA05075A-7CDA-4F65-AF6A-CB5DB6CF936F} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{3da06c3a-2e7b-4cb7-80ed-9b12916013f9}*SharedItemsImports = 5 + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{94712627-28b7-4757-8988-4259dc7e9f5f}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{f4311fb3-2a1d-4309-aeae-324373b56163}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 + EndGlobalSection EndGlobal diff --git a/src/coreclr/binder/bindertracing.cpp b/src/coreclr/binder/bindertracing.cpp index 66354d16b0197..5a0f1a9470a3e 100644 --- a/src/coreclr/binder/bindertracing.cpp +++ b/src/coreclr/binder/bindertracing.cpp @@ -88,7 +88,7 @@ namespace if (spec->GetName() != nullptr) spec->GetDisplayName(ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE | ASM_DISPLAYF_PUBLIC_KEY_TOKEN, request.AssemblyName); - DomainAssembly *parentAssembly = spec->GetParentAssembly(); + ::Assembly *parentAssembly = spec->GetParentAssembly(); if (parentAssembly != nullptr) { PEAssembly *pPEAssembly = parentAssembly->GetPEAssembly(); diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 6dd0f52fa2e55..5b6b4f03ef3a1 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -5512,6 +5512,7 @@ ClrDataAccess::Initialize(void) // Get SOS interfaces from the cDAC if available. IUnknown* unk = m_cdac.SosInterface(); (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos); + (void)unk->QueryInterface(__uuidof(ISOSDacInterface2), (void**)&m_cdacSos2); (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9); } } diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 57be1538e2bb7..f15fb1aafdb33 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1231,9 +1231,11 @@ class ClrDataAccess HRESULT GetThreadDataImpl(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData); HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data); + HRESULT GetModuleDataImpl(CLRDATA_ADDRESS addr, struct DacpModuleData *moduleData); HRESULT GetNestedExceptionDataImpl(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException); HRESULT GetMethodTableDataImpl(CLRDATA_ADDRESS mt, struct DacpMethodTableData *data); HRESULT GetMethodTableForEEClassImpl (CLRDATA_ADDRESS eeClassReallyMT, CLRDATA_ADDRESS *value); + HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data); BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord); #ifndef TARGET_UNIX @@ -1423,6 +1425,7 @@ class ClrDataAccess CDAC m_cdac; NonVMComHolder m_cdacSos; + NonVMComHolder m_cdacSos2; NonVMComHolder m_cdacSos9; #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 1021fc3db128f..2dc737db2e700 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1706,13 +1706,62 @@ ClrDataAccess::GetModule(CLRDATA_ADDRESS addr, IXCLRDataModule **mod) } HRESULT -ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *ModuleData) +ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData* moduleData) { - if (addr == 0 || ModuleData == NULL) + if (addr == 0 || moduleData == NULL) return E_INVALIDARG; SOSDacEnter(); + if (m_cdacSos != NULL) + { + hr = m_cdacSos->GetModuleData(addr, moduleData); + if (FAILED(hr)) + { + hr = GetModuleDataImpl(addr, moduleData); + } +#ifdef _DEBUG + else + { + DacpModuleData moduleDataLocal; + HRESULT hrLocal = GetModuleDataImpl(addr, &moduleDataLocal); + _ASSERTE(hr == hrLocal); + _ASSERTE(moduleData->Address == moduleDataLocal.Address); + _ASSERTE(moduleData->PEAssembly == moduleDataLocal.PEAssembly); + _ASSERTE(moduleData->ilBase == moduleDataLocal.ilBase); + _ASSERTE(moduleData->metadataStart == moduleDataLocal.metadataStart); + _ASSERTE(moduleData->metadataSize == moduleDataLocal.metadataSize); + _ASSERTE(moduleData->Assembly == moduleDataLocal.Assembly); + _ASSERTE(moduleData->bIsReflection == moduleDataLocal.bIsReflection); + _ASSERTE(moduleData->bIsPEFile == moduleDataLocal.bIsPEFile); + _ASSERTE(moduleData->dwBaseClassIndex == moduleDataLocal.dwBaseClassIndex); + _ASSERTE(moduleData->dwModuleID == moduleDataLocal.dwModuleID); + _ASSERTE(moduleData->dwTransientFlags == moduleDataLocal.dwTransientFlags); + _ASSERTE(moduleData->TypeDefToMethodTableMap == moduleDataLocal.TypeDefToMethodTableMap); + _ASSERTE(moduleData->TypeRefToMethodTableMap == moduleDataLocal.TypeRefToMethodTableMap); + _ASSERTE(moduleData->MethodDefToDescMap == moduleDataLocal.MethodDefToDescMap); + _ASSERTE(moduleData->FieldDefToDescMap == moduleDataLocal.FieldDefToDescMap); + _ASSERTE(moduleData->MemberRefToDescMap == moduleDataLocal.MemberRefToDescMap); + _ASSERTE(moduleData->FileReferencesMap == moduleDataLocal.FileReferencesMap); + _ASSERTE(moduleData->ManifestModuleReferencesMap == moduleDataLocal.ManifestModuleReferencesMap); + _ASSERTE(moduleData->LoaderAllocator == moduleDataLocal.LoaderAllocator); + _ASSERTE(moduleData->ThunkHeap == moduleDataLocal.ThunkHeap); + _ASSERTE(moduleData->dwModuleIndex == moduleDataLocal.dwModuleIndex); + } +#endif + } + else + { + hr = GetModuleDataImpl(addr, moduleData); + } + + SOSDacLeave(); + return hr; +} + +HRESULT +ClrDataAccess::GetModuleDataImpl(CLRDATA_ADDRESS addr, struct DacpModuleData *ModuleData) +{ Module* pModule = PTR_Module(TO_TADDR(addr)); ZeroMemory(ModuleData,sizeof(DacpModuleData)); @@ -1721,7 +1770,7 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module COUNT_T metadataSize = 0; if (!pModule->IsReflectionEmit()) { - ModuleData->ilBase = TO_CDADDR(dac_cast(pModule->GetPEAssembly()->GetLoadedLayout()->GetBase())); + ModuleData->ilBase = TO_CDADDR(dac_cast(pModule->m_baseAddress)); } ModuleData->metadataStart = (CLRDATA_ADDRESS)dac_cast(pModule->GetPEAssembly()->GetLoadedMetadata(&metadataSize)); @@ -1754,8 +1803,7 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module } EX_END_CATCH(SwallowAllExceptions) - SOSDacLeave(); - return hr; + return S_OK; } HRESULT @@ -2232,12 +2280,11 @@ ClrDataAccess::GetPEFileBase(CLRDATA_ADDRESS moduleAddr, CLRDATA_ADDRESS *base) SOSDacEnter(); PTR_Module pModule = PTR_Module(TO_TADDR(moduleAddr)); - PEAssembly* pPEAssembly = pModule->GetPEAssembly(); // More fields later? - if (!pPEAssembly->IsReflectionEmit()) + if (!pModule->IsReflectionEmit()) { - *base = TO_CDADDR(dac_cast(pPEAssembly->GetLoadedLayout()->GetBase())); + *base = TO_CDADDR(dac_cast(pModule->m_baseAddress)); } else { @@ -4600,8 +4647,42 @@ HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct Da SOSDacEnter(); - PTR_ExceptionObject pObj = dac_cast(TO_TADDR(objAddr)); + if (m_cdacSos2 != NULL) + { + hr = m_cdacSos2->GetObjectExceptionData(objAddr, data); + if (FAILED(hr)) + { + hr = GetObjectExceptionDataImpl(objAddr, data); + } +#ifdef _DEBUG + else + { + DacpExceptionObjectData dataLocal; + HRESULT hrLocal = GetObjectExceptionDataImpl(objAddr, &dataLocal); + _ASSERTE(hr == hrLocal); + _ASSERTE(data->Message == dataLocal.Message); + _ASSERTE(data->InnerException == dataLocal.InnerException); + _ASSERTE(data->StackTrace == dataLocal.StackTrace); + _ASSERTE(data->WatsonBuckets == dataLocal.WatsonBuckets); + _ASSERTE(data->StackTraceString == dataLocal.StackTraceString); + _ASSERTE(data->RemoteStackTraceString == dataLocal.RemoteStackTraceString); + _ASSERTE(data->HResult == dataLocal.HResult); + _ASSERTE(data->XCode == dataLocal.XCode); + } +#endif + } + else + { + hr = GetObjectExceptionDataImpl(objAddr, data); + } + SOSDacLeave(); + return hr; +} + +HRESULT ClrDataAccess::GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data) +{ + PTR_ExceptionObject pObj = dac_cast(TO_TADDR(objAddr)); data->Message = TO_CDADDR(dac_cast(pObj->GetMessage())); data->InnerException = TO_CDADDR(dac_cast(pObj->GetInnerException())); data->StackTrace = TO_CDADDR(dac_cast(pObj->GetStackTraceArrayObject())); @@ -4610,10 +4691,7 @@ HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct Da data->RemoteStackTraceString = TO_CDADDR(dac_cast(pObj->GetRemoteStackTraceString())); data->HResult = pObj->GetHResult(); data->XCode = pObj->GetXCode(); - - SOSDacLeave(); - - return hr; + return S_OK; } HRESULT ClrDataAccess::IsRCWDCOMProxy(CLRDATA_ADDRESS rcwAddr, BOOL* isDCOMProxy) diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/debug/runtimeinfo/contracts.jsonc index 44e7f914f9b07..f40991da45b67 100644 --- a/src/coreclr/debug/runtimeinfo/contracts.jsonc +++ b/src/coreclr/debug/runtimeinfo/contracts.jsonc @@ -10,6 +10,7 @@ // so to conditionally include contracts, put additional contracts in a separate file { "Exception": 1, + "Loader": 1, "RuntimeTypeSystem": 1, "Thread": 1 } diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 0e0aa0c8a819d..a0c71736fd6f9 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -141,6 +141,21 @@ CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Pointer, offsetof(gc_alloc_context, CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Limit, offsetof(gc_alloc_context, alloc_limit)) CDAC_TYPE_END(GCAllocContext) +// Exception + +// Use exact managed type field names for the descriptor as field names often can't change due to binary serialization or implicit diagnostic contracts +CDAC_TYPE_BEGIN(Exception) +CDAC_TYPE_INDETERMINATE(Exception) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _message, cdac_offsets::_message) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _innerException, cdac_offsets::_innerException) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _stackTrace, cdac_offsets::_stackTrace) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _watsonBuckets, cdac_offsets::_watsonBuckets) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _stackTraceString, cdac_offsets::_stackTraceString) +CDAC_TYPE_FIELD(Exception, /*pointer*/, _remoteStackTraceString, cdac_offsets::_remoteStackTraceString) +CDAC_TYPE_FIELD(Exception, /*int32*/, _HResult, cdac_offsets::_HResult) +CDAC_TYPE_FIELD(Exception, /*int32*/, _xcode, cdac_offsets::_xcode) +CDAC_TYPE_END(Exception) + CDAC_TYPE_BEGIN(ExceptionInfo) CDAC_TYPE_INDETERMINATE(ExceptionInfo) #if FEATURE_EH_FUNCLETS @@ -152,10 +167,29 @@ CDAC_TYPE_FIELD(PreviousNestedInfo, /*pointer*/, PreviousNestedInfo, offsetof(Ex #endif CDAC_TYPE_END(ExceptionInfo) + CDAC_TYPE_BEGIN(GCHandle) CDAC_TYPE_SIZE(sizeof(OBJECTHANDLE)) CDAC_TYPE_END(GCHandle) +// Loader + +CDAC_TYPE_BEGIN(Module) +CDAC_TYPE_INDETERMINATE(Module) +CDAC_TYPE_FIELD(Module, /*pointer*/, Assembly, cdac_offsets::Assembly) +CDAC_TYPE_FIELD(Module, /*pointer*/, Base, cdac_offsets::Base) +CDAC_TYPE_FIELD(Module, /*pointer*/, Flags, cdac_offsets::Flags) +CDAC_TYPE_FIELD(Module, /*pointer*/, LoaderAllocator, cdac_offsets::LoaderAllocator) +CDAC_TYPE_FIELD(Module, /*pointer*/, ThunkHeap, cdac_offsets::ThunkHeap) + +CDAC_TYPE_FIELD(Module, /*pointer*/, FieldDefToDescMap, cdac_offsets::FieldDefToDescMap) +CDAC_TYPE_FIELD(Module, /*pointer*/, ManifestModuleReferencesMap, cdac_offsets::ManifestModuleReferencesMap) +CDAC_TYPE_FIELD(Module, /*pointer*/, MemberRefToDescMap, cdac_offsets::MemberRefToDescMap) +CDAC_TYPE_FIELD(Module, /*pointer*/, MethodDefToDescMap, cdac_offsets::MethodDefToDescMap) +CDAC_TYPE_FIELD(Module, /*pointer*/, TypeDefToMethodTableMap, cdac_offsets::TypeDefToMethodTableMap) +CDAC_TYPE_FIELD(Module, /*pointer*/, TypeRefToMethodTableMap, cdac_offsets::TypeRefToMethodTableMap) +CDAC_TYPE_END(Module) + // Metadata CDAC_TYPE_BEGIN(MethodTable) diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 5b4faf05edb44..0088949d31712 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -402,7 +402,6 @@ BEGIN IDS_EE_CANNOT_COERCE_BYREF_VARIANT "Object cannot be coerced to the original type of the ByRef VARIANT it was obtained from." IDS_EE_WRAPPER_MUST_HAVE_DEF_CONS "The new wrapper type must have an empty constructor." IDS_EE_INVALID_STD_DISPID_NAME "Standard DISPID member name is formed incorrectly. The name must be in the following format: [DISPID=XXX]." - IDS_EE_NO_IDISPATCH_ON_TARGET "COM target does not implement IDispatch." IDS_EE_NON_STD_NAME_WITH_STD_DISPID "All named parameters must be specified as [DISPID=XXX] when invoking on a standard members specified as [DISPID=XXX}." IDS_EE_INVOKE_NEW_ENUM_INVALID_RETURN "Variant returned from an Invoke call with a DISPID of -4 does not contain a valid IUnknown pointer." IDS_EE_COM_OBJECT_RELEASE_RACE "COM object that has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread." @@ -412,7 +411,6 @@ BEGIN IDS_EE_CANNOTCASTSAME "[A]%1 cannot be cast to [B]%2. %3. %4." IDS_EE_INVALID_VT_FOR_CUSTOM_MARHALER "Type of the VARIANT specified for a parameter with a custom marshaler is not supported by the custom marshaler." IDS_EE_BAD_COMEXTENDS_CLASS "Types extending from COM objects should override all methods of an interface implemented by the base COM class." - IDS_EE_INTERFACE_NOT_DISPATCH_BASED "The interface does not support late bound calls since it does not derive from IDispatch." IDS_EE_MARSHAL_UNMAPPABLE_CHAR "Cannot marshal: Encountered unmappable character." IDS_EE_NOCUSTOMMARSHALER "A call to GetInstance() for custom marshaler '%1' returned null, which is not allowed." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index f1e7f1fba9a3e..24e82ff5afbb4 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -195,7 +195,7 @@ #define IDS_EE_CANNOT_COERCE_BYREF_VARIANT 0x17d2 #define IDS_EE_WRAPPER_MUST_HAVE_DEF_CONS 0x17d3 #define IDS_EE_INVALID_STD_DISPID_NAME 0x17d4 -#define IDS_EE_NO_IDISPATCH_ON_TARGET 0x17d5 + #define IDS_EE_NON_STD_NAME_WITH_STD_DISPID 0x17d6 #define IDS_EE_INVOKE_NEW_ENUM_INVALID_RETURN 0x17d7 #define IDS_EE_COM_OBJECT_RELEASE_RACE 0x17d8 @@ -215,8 +215,6 @@ #define IDS_EE_MISSING_FIELD 0x17f7 #define IDS_EE_MISSING_METHOD 0x17f8 -#define IDS_EE_INTERFACE_NOT_DISPATCH_BASED 0x17f9 - #define IDS_EE_UNHANDLED_EXCEPTION 0x17fc #define IDS_EE_EXCEPTION_TOSTRING_FAILED 0x17fd diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 916f277a1275c..d467d903c8ab4 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5516,6 +5516,7 @@ class Compiler void fgLocalVarLivenessInit(); + template void fgPerNodeLocalVarLiveness(GenTree* node); void fgPerBlockLocalVarLiveness(); @@ -5527,7 +5528,7 @@ class Compiler void fgLiveVarAnalysis(); - void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call); + void fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call); void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node); bool fgComputeLifeTrackedLocalDef(VARSET_TP& life, @@ -5549,6 +5550,7 @@ class Compiler bool* pStmtInfoDirty DEBUGARG(bool* treeModf)); void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP keepAliveVars); + bool fgIsTrackedRetBufferAddress(LIR::Range& range, GenTree* node); bool fgTryRemoveNonLocal(GenTree* node, LIR::Range* blockRange); diff --git a/src/coreclr/jit/gschecks.cpp b/src/coreclr/jit/gschecks.cpp index 0b4deec87d228..0baa5ad289c24 100644 --- a/src/coreclr/jit/gschecks.cpp +++ b/src/coreclr/jit/gschecks.cpp @@ -416,6 +416,7 @@ void Compiler::gsParamsToShadows() shadowVarDsc->lvDoNotEnregister = varDsc->lvDoNotEnregister; #ifdef DEBUG shadowVarDsc->SetDoNotEnregReason(varDsc->GetDoNotEnregReason()); + shadowVarDsc->SetHiddenBufferStructArg(varDsc->IsHiddenBufferStructArg()); #endif if (varTypeIsStruct(type)) @@ -503,6 +504,7 @@ void Compiler::gsParamsToShadows() } } + compCurBB = fgFirstBB; // Now insert code to copy the params to their shadow copy. for (UINT lclNum = 0; lclNum < lvaOldCount; lclNum++) { @@ -522,6 +524,7 @@ void Compiler::gsParamsToShadows() compCurBB = fgFirstBB; // Needed by some morphing (void)fgNewStmtAtBeg(fgFirstBB, fgMorphTree(store)); } + compCurBB = nullptr; // If the method has "Jmp CalleeMethod", then we need to copy shadow params back to original // params before "jmp" to CalleeMethod. diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 3a13fcfab7358..8f52fe617a9f7 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -2784,7 +2784,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, op4 = getArgForHWIntrinsic(argType, argClass); assert(HWIntrinsicInfo::isImmOp(intrinsic, op4)); - op3 = addRangeCheckIfNeeded(intrinsic, op4, mustExpand, immLowerBound, immUpperBound); + op4 = addRangeCheckIfNeeded(intrinsic, op4, mustExpand, immLowerBound, immUpperBound); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg3, &argClass))); op3 = getArgForHWIntrinsic(argType, argClass); diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 5c7b97e3ebc07..2fa052fcbdcad 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -308,6 +308,11 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) emitSize = emitActualTypeSize(intrin.baseType); opt = INS_OPTS_NONE; } + else if (HWIntrinsicInfo::IsScalable(intrin.id)) + { + emitSize = EA_SCALABLE; + opt = emitter::optGetSveInsOpt(emitTypeSize(intrin.baseType)); + } else if (intrin.category == HW_Category_Special) { assert(intrin.id == NI_ArmBase_Yield); @@ -315,11 +320,6 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) emitSize = EA_UNKNOWN; opt = INS_OPTS_NONE; } - else if (HWIntrinsicInfo::IsScalable(intrin.id)) - { - emitSize = EA_SCALABLE; - opt = emitter::optGetSveInsOpt(emitTypeSize(intrin.baseType)); - } else { emitSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->GetSimdSize())); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index b976202ef822d..0dcee81c83e4d 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -99,10 +99,10 @@ HARDWARE_INTRINSIC(Sve, FusedMultiplyAddNegated, HARDWARE_INTRINSIC(Sve, FusedMultiplySubtract, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmls, INS_sve_fmls}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, FusedMultiplySubtractBySelectedScalar, -1, 4, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fmls, INS_sve_fmls}, HW_Category_SIMDByIndexedElement, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics|HW_Flag_FmaIntrinsic|HW_Flag_LowVectorOperation) HARDWARE_INTRINSIC(Sve, FusedMultiplySubtractNegated, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_fnmls, INS_sve_fnmls}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation|HW_Flag_FmaIntrinsic|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(Sve, GatherPrefetch16Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_sve_prfh, INS_sve_prfh, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, GatherPrefetch32Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfw, INS_sve_prfw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, GatherPrefetch64Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfd, INS_sve_prfd, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, GatherPrefetch8Bit, -1, -1, false, {INS_sve_prfb, INS_sve_prfb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) +HARDWARE_INTRINSIC(Sve, GatherPrefetch16Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_sve_prfh, INS_sve_prfh, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, GatherPrefetch32Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfw, INS_sve_prfw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, GatherPrefetch64Bit, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfd, INS_sve_prfd, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, GatherPrefetch8Bit, -1, -1, false, {INS_sve_prfb, INS_sve_prfb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) HARDWARE_INTRINSIC(Sve, GatherVector, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, GatherVectorByteZeroExtend, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1b, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, GatherVectorInt16SignExtend, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sh, INS_sve_ld1sh, INS_sve_ld1sh, INS_sve_ld1sh, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) @@ -192,10 +192,10 @@ HARDWARE_INTRINSIC(Sve, Not, HARDWARE_INTRINSIC(Sve, Or, -1, -1, false, {INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_sve_orr, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_OptionalEmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, OrAcross, -1, -1, false, {INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_sve_orv, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, PopCount, -1, -1, false, {INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt, INS_sve_cnt}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) -HARDWARE_INTRINSIC(Sve, PrefetchBytes, -1, 3, false, {INS_invalid, INS_sve_prfb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, PrefetchInt16, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_prfh, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, PrefetchInt32, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) -HARDWARE_INTRINSIC(Sve, PrefetchInt64, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfd, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand) +HARDWARE_INTRINSIC(Sve, PrefetchBytes, -1, 3, false, {INS_invalid, INS_sve_prfb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, PrefetchInt16, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_prfh, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, PrefetchInt32, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) +HARDWARE_INTRINSIC(Sve, PrefetchInt64, -1, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_prfd, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation|HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasImmediateOperand|HW_Flag_HasEnumOperand|HW_Flag_SpecialSideEffect_Other) HARDWARE_INTRINSIC(Sve, ReciprocalEstimate, -1, 1, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_frecpe, INS_sve_frecpe}, HW_Category_SIMD, HW_Flag_Scalable) HARDWARE_INTRINSIC(Sve, ReciprocalExponent, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_frecpx, INS_sve_frecpx}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, ReciprocalSqrtEstimate, -1, 1, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_frsqrte, INS_sve_frsqrte}, HW_Category_SIMD, HW_Flag_Scalable) diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 3ad2c9e7a7e77..2a9d0f9a36914 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1250,12 +1250,9 @@ class LocalAddressVisitor final : public GenTreeVisitor if (m_compiler->opts.compJitOptimizeStructHiddenBuffer && (callUser != nullptr) && m_compiler->IsValidLclAddr(lclNum, val.Offset())) { - // We will only attempt this optimization for locals that are: - // a) Not susceptible to liveness bugs (see "lvaSetHiddenBufferStructArg"). - // b) Do not later turn into indirections. - // - bool isSuitableLocal = - varTypeIsStruct(varDsc) && varDsc->lvIsTemp && !m_compiler->lvaIsImplicitByRefLocal(lclNum); + // We will only attempt this optimization for locals that do not + // later turn into indirections. + bool isSuitableLocal = varTypeIsStruct(varDsc) && !m_compiler->lvaIsImplicitByRefLocal(lclNum); #ifdef TARGET_X86 if (m_compiler->lvaIsArgAccessedViaVarArgsCookie(lclNum)) { diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 74c8fd1add0ff..62d3769879b20 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3068,12 +3068,6 @@ void Compiler::lvaSetVarAddrExposed(unsigned varNum DEBUGARG(AddressExposedReaso // *do not* mark the local address-exposed and treat the call much like a local store node throughout // the compilation. // -// TODO-ADDR-Bug: currently, we rely on these locals not being present in call argument lists, -// outside of the buffer address argument itself, as liveness - currently - treats the location node -// associated with the address itself as the definition point, and call arguments can be reordered -// rather arbitrarily. We should fix liveness to treat the call as the definition point instead and -// enable this optimization for "!lvIsTemp" locals. -// void Compiler::lvaSetHiddenBufferStructArg(unsigned varNum) { LclVarDsc* varDsc = lvaGetDesc(varNum); diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index 575b85813ee8f..c20fa8f54c6ec 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -192,9 +192,14 @@ void Compiler::fgLocalVarLivenessInit() // Set fgCurMemoryUse and fgCurMemoryDef when memory is read or updated // Call fgMarkUseDef for any Local variables encountered // +// Template arguments: +// lowered - Whether or not this is liveness on lowered IR, where LCL_ADDRs +// on tracked locals may appear. +// // Arguments: // tree - The current node. // +template void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree) { assert(tree != nullptr); @@ -209,12 +214,25 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree) case GT_LCL_VAR: case GT_LCL_FLD: - case GT_LCL_ADDR: case GT_STORE_LCL_VAR: case GT_STORE_LCL_FLD: fgMarkUseDef(tree->AsLclVarCommon()); break; + case GT_LCL_ADDR: + if (lowered) + { + // If this is a definition of a retbuf then we process it as + // part of the GT_CALL node. + if (fgIsTrackedRetBufferAddress(LIR::AsRange(compCurBB), tree)) + { + break; + } + + fgMarkUseDef(tree->AsLclVarCommon()); + } + break; + case GT_IND: case GT_BLK: // For Volatile indirection, first mutate GcHeap/ByrefExposed @@ -303,6 +321,12 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree) } } } + + GenTreeLclVarCommon* definedLcl = gtCallGetDefinedRetBufLclAddr(call); + if (definedLcl != nullptr) + { + fgMarkUseDef(definedLcl); + } break; } @@ -367,7 +391,7 @@ void Compiler::fgPerBlockLocalVarLiveness() { for (GenTree* node : LIR::AsRange(block)) { - fgPerNodeLocalVarLiveness(node); + fgPerNodeLocalVarLiveness(node); } } else if (fgNodeThreading == NodeThreading::AllTrees) @@ -377,7 +401,7 @@ void Compiler::fgPerBlockLocalVarLiveness() compCurStmt = stmt; for (GenTree* const node : stmt->TreeList()) { - fgPerNodeLocalVarLiveness(node); + fgPerNodeLocalVarLiveness(node); } } } @@ -744,10 +768,11 @@ void Compiler::fgLiveVarAnalysis() // due to a GT_CALL node. // // Arguments: -// life - The live set that is being computed. -// call - The call node in question. +// life - The live set that is being computed. +// keepAliveVars - Tracked locals that must be kept alive everywhere in the block +// call - The call node in question. // -void Compiler::fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call) +void Compiler::fgComputeLifeCall(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTreeCall* call) { assert(call != nullptr); @@ -808,6 +833,12 @@ void Compiler::fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call) } } } + + GenTreeLclVarCommon* definedLcl = gtCallGetDefinedRetBufLclAddr(call); + if (definedLcl != nullptr) + { + fgComputeLifeLocal(life, keepAliveVars, definedLcl); + } } //------------------------------------------------------------------------ @@ -1140,11 +1171,11 @@ void Compiler::fgComputeLife(VARSET_TP& life, AGAIN: assert(tree->OperGet() != GT_QMARK); - if (tree->gtOper == GT_CALL) + if (tree->IsCall()) { - fgComputeLifeCall(life, tree->AsCall()); + fgComputeLifeCall(life, keepAliveVars, tree->AsCall()); } - else if (tree->OperIsNonPhiLocal() || tree->OperIs(GT_LCL_ADDR)) + else if (tree->OperIsNonPhiLocal()) { bool isDeadStore = fgComputeLifeLocal(life, keepAliveVars, tree); if (isDeadStore) @@ -1191,6 +1222,15 @@ void Compiler::fgComputeLife(VARSET_TP& life, } } +//--------------------------------------------------------------------- +// fgComputeLifeLIR - fill out liveness flags in the IR nodes of the block +// provided the live-out set. +// +// Arguments +// life - the set of live-out variables from the block +// block - the block +// keepAliveVars - variables that are globally live (usually due to being live into an EH successor) +// void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP keepAliveVars) { noway_assert(VarSetOps::IsSubset(this, keepAliveVars, life)); @@ -1247,7 +1287,7 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR } else { - fgComputeLifeCall(life, call); + fgComputeLifeCall(life, keepAliveVars, call); } break; } @@ -1295,11 +1335,21 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR } else { + // For LCL_ADDRs that are defined by being passed as a + // retbuf we will handle them when we get to the call. We + // cannot consider them to be defined at the point of the + // LCL_ADDR since there may be uses between the LCL_ADDR + // and call. + if (fgIsTrackedRetBufferAddress(blockRange, node)) + { + break; + } + isDeadStore = fgComputeLifeLocal(life, keepAliveVars, node); if (isDeadStore) { LIR::Use addrUse; - if (blockRange.TryGetUse(node, &addrUse) && (addrUse.User()->OperIs(GT_STOREIND, GT_STORE_BLK))) + if (blockRange.TryGetUse(node, &addrUse) && addrUse.User()->OperIs(GT_STOREIND, GT_STORE_BLK)) { GenTreeIndir* const store = addrUse.User()->AsIndir(); @@ -1465,6 +1515,48 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR } } +//--------------------------------------------------------------------- +// fgIsTrackedRetBufferAddress - given a LCL_ADDR node, check if it is the +// return buffer definition of a call. +// +// Arguments +// range - the block range containing the LCL_ADDR +// node - the LCL_ADDR +// +bool Compiler::fgIsTrackedRetBufferAddress(LIR::Range& range, GenTree* node) +{ + assert(node->OperIs(GT_LCL_ADDR)); + if ((node->gtFlags & GTF_VAR_DEF) == 0) + { + return false; + } + + LclVarDsc* dsc = lvaGetDesc(node->AsLclVarCommon()); + if (!dsc->lvTracked) + { + return false; + } + + GenTree* curNode = node; + do + { + LIR::Use use; + if (!range.TryGetUse(curNode, &use)) + { + return false; + } + + curNode = use.User(); + + if (curNode->IsCall()) + { + return gtCallGetDefinedRetBufLclAddr(curNode->AsCall()) == node; + } + } while (curNode->OperIs(GT_FIELD_LIST) || curNode->OperIsPutArg()); + + return false; +} + //--------------------------------------------------------------------- // fgTryRemoveNonLocal - try to remove a node if it is unused and has no direct // side effects. diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 9aa2cc7dfbcef..d1fb48fc16d93 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1980,18 +1980,10 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou case NI_Sve_LoadVectorNonTemporal: case NI_Sve_LoadVector128AndReplicateToVector: case NI_Sve_StoreAndZip: - case NI_Sve_PrefetchBytes: - case NI_Sve_PrefetchInt16: - case NI_Sve_PrefetchInt32: - case NI_Sve_PrefetchInt64: assert(intrinsicTree->OperIsMemoryLoadOrStore()); srcCount += BuildAddrUses(intrin.op2); break; - case NI_Sve_GatherPrefetch8Bit: - case NI_Sve_GatherPrefetch16Bit: - case NI_Sve_GatherPrefetch32Bit: - case NI_Sve_GatherPrefetch64Bit: case NI_Sve_GatherVector: case NI_Sve_GatherVectorByteZeroExtend: case NI_Sve_GatherVectorInt16SignExtend: @@ -2004,6 +1996,16 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou case NI_Sve_GatherVectorUInt32WithByteOffsetsZeroExtend: case NI_Sve_GatherVectorUInt32ZeroExtend: assert(intrinsicTree->OperIsMemoryLoadOrStore()); + FALLTHROUGH; + + case NI_Sve_PrefetchBytes: + case NI_Sve_PrefetchInt16: + case NI_Sve_PrefetchInt32: + case NI_Sve_PrefetchInt64: + case NI_Sve_GatherPrefetch8Bit: + case NI_Sve_GatherPrefetch16Bit: + case NI_Sve_GatherPrefetch32Bit: + case NI_Sve_GatherPrefetch64Bit: if (!varTypeIsSIMD(intrin.op2->gtType)) { srcCount += BuildAddrUses(intrin.op2); diff --git a/src/coreclr/jit/promotion.h b/src/coreclr/jit/promotion.h index b1f3975f3134f..b70901ec1ae30 100644 --- a/src/coreclr/jit/promotion.h +++ b/src/coreclr/jit/promotion.h @@ -218,14 +218,15 @@ class PromotionLiveness StructDeaths GetDeathsForStructLocal(GenTreeLclVarCommon* use); private: - void MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, BitVec& defSet); - void MarkIndex(unsigned index, bool isUse, bool isDef, BitVec& useSet, BitVec& defSet); - void ComputeUseDefSets(); - void InterBlockLiveness(); - bool PerBlockLiveness(BasicBlock* block); - void AddHandlerLiveVars(BasicBlock* block, BitVec& ehLiveVars); - void FillInLiveness(); - void FillInLiveness(BitVec& life, BitVec volatileVars, GenTreeLclVarCommon* lcl); + void MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, BitVec& useSet, BitVec& defSet); + unsigned GetSizeOfStructLocal(Statement* stmt, GenTreeLclVarCommon* lcl); + void MarkIndex(unsigned index, bool isUse, bool isDef, BitVec& useSet, BitVec& defSet); + void ComputeUseDefSets(); + void InterBlockLiveness(); + bool PerBlockLiveness(BasicBlock* block); + void AddHandlerLiveVars(BasicBlock* block, BitVec& ehLiveVars); + void FillInLiveness(); + void FillInLiveness(BitVec& life, BitVec volatileVars, Statement* stmt, GenTreeLclVarCommon* lcl); #ifdef DEBUG void DumpVarSet(BitVec set, BitVec allVars); #endif diff --git a/src/coreclr/jit/promotionliveness.cpp b/src/coreclr/jit/promotionliveness.cpp index dce67b92bd8cc..5cd19dc169a6e 100644 --- a/src/coreclr/jit/promotionliveness.cpp +++ b/src/coreclr/jit/promotionliveness.cpp @@ -133,7 +133,7 @@ void PromotionLiveness::ComputeUseDefSets() { for (GenTreeLclVarCommon* lcl : stmt->LocalsTreeList()) { - MarkUseDef(lcl, bb.VarUse, bb.VarDef); + MarkUseDef(stmt, lcl, bb.VarUse, bb.VarDef); } } else @@ -143,7 +143,7 @@ void PromotionLiveness::ComputeUseDefSets() // Skip liveness updates/marking for defs; they may be conditionally executed. if ((lcl->gtFlags & GTF_VAR_DEF) == 0) { - MarkUseDef(lcl, bb.VarUse, bb.VarDef); + MarkUseDef(stmt, lcl, bb.VarUse, bb.VarDef); } } } @@ -155,7 +155,7 @@ void PromotionLiveness::ComputeUseDefSets() { for (GenTreeLclVarCommon* lcl : stmt->LocalsTreeList()) { - MarkUseDef(lcl, bb.VarUse, bb.VarDef); + MarkUseDef(stmt, lcl, bb.VarUse, bb.VarDef); } } } @@ -179,11 +179,12 @@ void PromotionLiveness::ComputeUseDefSets() // Mark use/def information for a single appearence of a local. // // Parameters: +// stmt - Statement containing the local // lcl - The local node // useSet - The use set to mark in. // defSet - The def set to mark in. // -void PromotionLiveness::MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, BitVec& defSet) +void PromotionLiveness::MarkUseDef(Statement* stmt, GenTreeLclVarCommon* lcl, BitVec& useSet, BitVec& defSet) { AggregateInfo* agg = m_aggregates.Lookup(lcl->GetLclNum()); if (agg == nullptr) @@ -198,17 +199,8 @@ void PromotionLiveness::MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, Bit unsigned baseIndex = m_structLclToTrackedIndex[lcl->GetLclNum()]; var_types accessType = lcl->TypeGet(); - if (accessType == TYP_STRUCT) + if ((accessType == TYP_STRUCT) || lcl->OperIs(GT_LCL_ADDR)) { - if (lcl->OperIs(GT_LCL_ADDR)) - { - // For LCL_ADDR this is a retbuf and we expect it to be a def. We - // don't know the exact size here so we cannot mark anything as - // being fully defined, thus we can just return. - assert(isDef); - return; - } - if (lcl->OperIsScalarLocal()) { // Mark remainder and all fields. @@ -220,7 +212,7 @@ void PromotionLiveness::MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, Bit else { unsigned offs = lcl->GetLclOffs(); - unsigned size = lcl->GetLayout(m_compiler)->GetSize(); + unsigned size = GetSizeOfStructLocal(stmt, lcl); size_t index = Promotion::BinarySearch(reps, offs); if ((ssize_t)index < 0) @@ -264,6 +256,30 @@ void PromotionLiveness::MarkUseDef(GenTreeLclVarCommon* lcl, BitVec& useSet, Bit } } +//------------------------------------------------------------------------ +// GetSizeOfStructLocal: +// Get the size of a struct local (either a TYP_STRUCT typed local, or a +// GT_LCL_ADDR retbuf definition). +// +// Parameters: +// stmt - Statement containing the local +// lcl - The local node +// +unsigned PromotionLiveness::GetSizeOfStructLocal(Statement* stmt, GenTreeLclVarCommon* lcl) +{ + if (lcl->OperIs(GT_LCL_ADDR)) + { + // Retbuf definition. Find the definition size from the + // containing call. + Compiler::FindLinkData data = m_compiler->gtFindLink(stmt, lcl); + assert((data.parent != nullptr) && data.parent->IsCall() && + (m_compiler->gtCallGetDefinedRetBufLclAddr(data.parent->AsCall()) == lcl)); + return m_compiler->typGetObjLayout(data.parent->AsCall()->gtRetClsHnd)->GetSize(); + } + + return lcl->GetLayout(m_compiler)->GetSize(); +} + //------------------------------------------------------------------------ // MarkIndex: // Mark specific bits in use/def bit vectors depending on whether this is a use def. @@ -430,7 +446,7 @@ void PromotionLiveness::FillInLiveness() { for (GenTree* cur = stmt->GetTreeListEnd(); cur != nullptr; cur = cur->gtPrev) { - FillInLiveness(life, volatileVars, cur->AsLclVarCommon()); + FillInLiveness(life, volatileVars, stmt, cur->AsLclVarCommon()); } } else @@ -440,7 +456,7 @@ void PromotionLiveness::FillInLiveness() // Skip liveness updates/marking for defs; they may be conditionally executed. if ((cur->gtFlags & GTF_VAR_DEF) == 0) { - FillInLiveness(life, volatileVars, cur->AsLclVarCommon()); + FillInLiveness(life, volatileVars, stmt, cur->AsLclVarCommon()); } } } @@ -462,9 +478,10 @@ void PromotionLiveness::FillInLiveness() // Parameters: // life - The current life set. Will be read and updated depending on 'lcl'. // volatileVars - Bit vector of variables that are live always. +// stmt - Statement containing the local // lcl - The IR node to process liveness for and to mark with liveness information. // -void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, GenTreeLclVarCommon* lcl) +void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, Statement* stmt, GenTreeLclVarCommon* lcl) { AggregateInfo* agg = m_aggregates.Lookup(lcl->GetLclNum()); if (agg == nullptr) @@ -478,7 +495,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, GenTre unsigned baseIndex = m_structLclToTrackedIndex[lcl->GetLclNum()]; var_types accessType = lcl->TypeGet(); - if (accessType == TYP_STRUCT) + if ((accessType == TYP_STRUCT) || lcl->OperIs(GT_LCL_ADDR)) { // We need an external bit set to represent dying fields/remainder on a struct use. BitVecTraits aggTraits(1 + (unsigned)agg->Replacements.size(), m_compiler); @@ -510,7 +527,7 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, GenTre else { unsigned offs = lcl->GetLclOffs(); - unsigned size = lcl->GetLayout(m_compiler)->GetSize(); + unsigned size = GetSizeOfStructLocal(stmt, lcl); size_t index = Promotion::BinarySearch(agg->Replacements, offs); if ((ssize_t)index < 0) @@ -574,25 +591,6 @@ void PromotionLiveness::FillInLiveness(BitVec& life, BitVec volatileVars, GenTre } else { - if (lcl->OperIs(GT_LCL_ADDR)) - { - // Retbuf -- these are definitions but we do not know of how much. - // We never treat them as killing anything, but we do store liveness information for them. - BitVecTraits aggTraits(1 + (unsigned)agg->Replacements.size(), m_compiler); - BitVec aggDeaths(BitVecOps::MakeEmpty(&aggTraits)); - // Copy preexisting liveness information. - for (size_t i = 0; i <= agg->Replacements.size(); i++) - { - unsigned varIndex = baseIndex + (unsigned)i; - if (!BitVecOps::IsMember(m_bvTraits, life, varIndex)) - { - BitVecOps::AddElemD(&aggTraits, aggDeaths, (unsigned)i); - } - } - m_aggDeaths.Set(lcl, aggDeaths); - return; - } - unsigned offs = lcl->GetLclOffs(); size_t index = Promotion::BinarySearch(agg->Replacements, offs); if ((ssize_t)index < 0) diff --git a/src/coreclr/nativeaot/nativeaot.sln b/src/coreclr/nativeaot/nativeaot.sln index 7812cd25d4925..b2aaf792bd935 100644 --- a/src/coreclr/nativeaot/nativeaot.sln +++ b/src/coreclr/nativeaot/nativeaot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30421.15 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35017.193 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "System.Private.CoreLib\src\System.Private.CoreLib.csproj", "{E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}" EndProject @@ -17,26 +17,63 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.CoreLib", "Test.CoreLi EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "System.Private.CoreLib.Shared", "..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.shproj", "{977524B8-92D8-4DFC-91E4-11A0582B81BF}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{2E156392-D514-42DE-9532-42D2A7F0B9FB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EC8F472E-5375-4962-9963-8B11F2924C2B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{DF7F14A3-3EB8-4B2C-AE04-678876997BA4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{B10E7FF9-AA48-4AF0-8242-EF5ED68846AD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{1BE6A0E4-9096-44DF-8C8C-33956BD0050F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{5FB0FB7F-BB7A-4E16-B834-82413FFA7C9D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{361ABA16-E054-4160-9998-A06BF377A82F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\libraries\System.Private.CoreLib\ref\System.Private.CoreLib.csproj", "{EEB35F24-4878-4417-BB54-86AB1206E8D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\..\libraries\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\..\libraries\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "..\..\libraries\System.Private.CoreLib\gen\System.Private.CoreLib.Generators.csproj", "{7B1980B2-F6AB-423A-A75F-41190570DE4D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.CodeFixProvider", "..\..\tools\illink\src\ILLink.CodeFix\ILLink.CodeFixProvider.csproj", "{735FEA0D-852A-47BD-B1FE-6B4D9C83F217}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.RoslynAnalyzer", "..\..\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj", "{D20FDE50-2841-46E9-B31A-6B145BFCB09E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\ref\Mono.Linker.csproj", "{5B302881-1226-4A80-BDC1-EE70FB283949}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\Mono.Linker.csproj", "{3E67A258-6F80-435C-B83C-61BE17B93155}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.Tasks", "..\..\tools\illink\src\ILLink.Tasks\ILLink.Tasks.csproj", "{8C7DAB59-A791-42BC-BBA4-194BF1293841}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.DependencyAnalysisFramework", "..\tools\aot\ILCompiler.DependencyAnalysisFramework\ILCompiler.DependencyAnalysisFramework.csproj", "{431A4C42-805F-40CD-9EEE-F794B6AF9B59}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ILLink.Shared", "..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.shproj", "{FF598E93-8E9E-4091-9F50-61A7572663AE}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{977524b8-92d8-4dfc-91e4-11a0582b81bf}*SharedItemsImports = 13 - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{e4bc768b-f97d-4a8f-9391-b65df3eb47c6}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|Any CPU = Checked|Any CPU Checked|arm = Checked|arm Checked|arm64 = Checked|arm64 Checked|x64 = Checked|x64 Checked|x86 = Checked|x86 + Debug|Any CPU = Debug|Any CPU Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU Release|arm = Release|arm Release|arm64 = Release|arm64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|Any CPU.ActiveCfg = Checked|x64 + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|Any CPU.Build.0 = Checked|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|arm.ActiveCfg = Checked|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|arm.Build.0 = Checked|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -45,6 +82,8 @@ Global {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|x64.Build.0 = Checked|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|x86.ActiveCfg = Checked|x86 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Checked|x86.Build.0 = Checked|x86 + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|Any CPU.ActiveCfg = Debug|x64 + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|Any CPU.Build.0 = Debug|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|arm.ActiveCfg = Debug|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|arm.Build.0 = Debug|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -53,6 +92,8 @@ Global {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|x64.Build.0 = Debug|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|x86.ActiveCfg = Debug|x86 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Debug|x86.Build.0 = Debug|x86 + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|Any CPU.ActiveCfg = Release|x64 + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|Any CPU.Build.0 = Release|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|arm.ActiveCfg = Release|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|arm.Build.0 = Release|arm {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|arm64.ActiveCfg = Release|arm64 @@ -61,6 +102,8 @@ Global {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x64.Build.0 = Release|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x86.ActiveCfg = Release|x86 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x86.Build.0 = Release|x86 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|Any CPU.ActiveCfg = Checked|x64 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|Any CPU.Build.0 = Checked|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm.ActiveCfg = Checked|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm.Build.0 = Checked|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -69,6 +112,8 @@ Global {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x64.Build.0 = Checked|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x86.ActiveCfg = Checked|x86 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x86.Build.0 = Checked|x86 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|Any CPU.ActiveCfg = Debug|x64 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|Any CPU.Build.0 = Debug|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm.ActiveCfg = Debug|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm.Build.0 = Debug|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -77,6 +122,8 @@ Global {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x64.Build.0 = Debug|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x86.ActiveCfg = Debug|x86 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x86.Build.0 = Debug|x86 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|Any CPU.ActiveCfg = Release|x64 + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|Any CPU.Build.0 = Release|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm.ActiveCfg = Release|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm.Build.0 = Release|arm {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm64.ActiveCfg = Release|arm64 @@ -85,54 +132,8 @@ Global {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x64.Build.0 = Release|x64 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x86.ActiveCfg = Release|x86 {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x86.Build.0 = Release|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|arm.ActiveCfg = Checked|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|arm.Build.0 = Checked|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|arm64.ActiveCfg = Checked|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|arm64.Build.0 = Checked|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|x64.ActiveCfg = Checked|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|x64.Build.0 = Checked|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|x86.ActiveCfg = Checked|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Checked|x86.Build.0 = Checked|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|arm.ActiveCfg = Debug|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|arm.Build.0 = Debug|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|arm64.ActiveCfg = Debug|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|arm64.Build.0 = Debug|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|x64.ActiveCfg = Debug|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|x64.Build.0 = Debug|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|x86.ActiveCfg = Debug|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Debug|x86.Build.0 = Debug|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|arm.ActiveCfg = Release|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|arm.Build.0 = Release|arm - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|arm64.ActiveCfg = Release|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|arm64.Build.0 = Release|arm64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|x64.ActiveCfg = Release|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|x64.Build.0 = Release|x64 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|x86.ActiveCfg = Release|x86 - {BAF9BBDF-0DFA-4E0D-AB3C-F07657B9EBB0}.Release|x86.Build.0 = Release|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|arm.ActiveCfg = Checked|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|arm.Build.0 = Checked|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|arm64.ActiveCfg = Checked|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|arm64.Build.0 = Checked|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|x64.ActiveCfg = Checked|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|x64.Build.0 = Checked|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|x86.ActiveCfg = Checked|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Checked|x86.Build.0 = Checked|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|arm.ActiveCfg = Debug|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|arm.Build.0 = Debug|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|arm64.ActiveCfg = Debug|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|arm64.Build.0 = Debug|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|x64.ActiveCfg = Debug|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|x64.Build.0 = Debug|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|x86.ActiveCfg = Debug|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Debug|x86.Build.0 = Debug|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|arm.ActiveCfg = Release|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Release|arm.Build.0 = Release|arm - {6147AF1A-5054-492A-9309-FA868A184414}.Release|arm64.ActiveCfg = Release|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|arm64.Build.0 = Release|arm64 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|x64.ActiveCfg = Release|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|x64.Build.0 = Release|x64 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|x86.ActiveCfg = Release|x86 - {6147AF1A-5054-492A-9309-FA868A184414}.Release|x86.Build.0 = Release|x86 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|Any CPU.ActiveCfg = Checked|x64 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|Any CPU.Build.0 = Checked|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|arm.ActiveCfg = Checked|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|arm.Build.0 = Checked|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -141,6 +142,8 @@ Global {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|x64.Build.0 = Checked|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|x86.ActiveCfg = Checked|x86 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|x86.Build.0 = Checked|x86 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|Any CPU.Build.0 = Debug|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|arm.ActiveCfg = Debug|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|arm.Build.0 = Debug|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -149,6 +152,8 @@ Global {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|x64.Build.0 = Debug|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|x86.ActiveCfg = Debug|x86 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Debug|x86.Build.0 = Debug|x86 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|Any CPU.ActiveCfg = Release|x64 + {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|Any CPU.Build.0 = Release|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|arm.ActiveCfg = Release|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|arm.Build.0 = Release|arm {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|arm64.ActiveCfg = Release|arm64 @@ -157,30 +162,8 @@ Global {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|x64.Build.0 = Release|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|x86.ActiveCfg = Release|x86 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Release|x86.Build.0 = Release|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|arm.ActiveCfg = Checked|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|arm.Build.0 = Checked|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|arm64.ActiveCfg = Checked|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|arm64.Build.0 = Checked|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|x64.ActiveCfg = Checked|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|x64.Build.0 = Checked|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|x86.ActiveCfg = Checked|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Checked|x86.Build.0 = Checked|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|arm.ActiveCfg = Debug|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|arm.Build.0 = Debug|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|arm64.ActiveCfg = Debug|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|arm64.Build.0 = Debug|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|x64.ActiveCfg = Debug|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|x64.Build.0 = Debug|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|x86.ActiveCfg = Debug|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Debug|x86.Build.0 = Debug|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|arm.ActiveCfg = Release|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|arm.Build.0 = Release|arm - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|arm64.ActiveCfg = Release|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|arm64.Build.0 = Release|arm64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|x64.ActiveCfg = Release|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|x64.Build.0 = Release|x64 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|x86.ActiveCfg = Release|x86 - {C0245BD9-6AE2-47A5-BC41-DB6F777423AF}.Release|x86.Build.0 = Release|x86 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|Any CPU.ActiveCfg = Checked|x64 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|Any CPU.Build.0 = Checked|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|arm.ActiveCfg = Checked|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|arm.Build.0 = Checked|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -189,6 +172,8 @@ Global {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|x64.Build.0 = Checked|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|x86.ActiveCfg = Checked|x86 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Checked|x86.Build.0 = Checked|x86 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|Any CPU.ActiveCfg = Debug|x64 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|Any CPU.Build.0 = Debug|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|arm.ActiveCfg = Debug|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|arm.Build.0 = Debug|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -197,6 +182,8 @@ Global {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|x64.Build.0 = Debug|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|x86.ActiveCfg = Debug|x86 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Debug|x86.Build.0 = Debug|x86 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|Any CPU.ActiveCfg = Release|x64 + {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|Any CPU.Build.0 = Release|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|arm.ActiveCfg = Release|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|arm.Build.0 = Release|arm {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|arm64.ActiveCfg = Release|arm64 @@ -205,6 +192,8 @@ Global {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|x64.Build.0 = Release|x64 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|x86.ActiveCfg = Release|x86 {33CAE331-16EE-443C-A0CC-4337B94A02AD}.Release|x86.Build.0 = Release|x86 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|Any CPU.ActiveCfg = Checked|x64 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|Any CPU.Build.0 = Checked|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|arm.ActiveCfg = Checked|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|arm.Build.0 = Checked|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -213,6 +202,8 @@ Global {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|x64.Build.0 = Checked|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|x86.ActiveCfg = Checked|x86 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Checked|x86.Build.0 = Checked|x86 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|Any CPU.ActiveCfg = Debug|x64 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|Any CPU.Build.0 = Debug|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|arm.ActiveCfg = Debug|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|arm.Build.0 = Debug|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -221,6 +212,8 @@ Global {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|x64.Build.0 = Debug|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|x86.ActiveCfg = Debug|x86 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Debug|x86.Build.0 = Debug|x86 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|Any CPU.ActiveCfg = Release|x64 + {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|Any CPU.Build.0 = Release|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|arm.ActiveCfg = Release|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|arm.Build.0 = Release|arm {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|arm64.ActiveCfg = Release|arm64 @@ -229,6 +222,8 @@ Global {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|x64.Build.0 = Release|x64 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|x86.ActiveCfg = Release|x86 {3E43ACA2-073E-4A66-BA9C-417C5F83D430}.Release|x86.Build.0 = Release|x86 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|Any CPU.ActiveCfg = Checked|x64 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|Any CPU.Build.0 = Checked|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|arm.ActiveCfg = Checked|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|arm.Build.0 = Checked|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|arm64.ActiveCfg = Checked|arm64 @@ -237,6 +232,8 @@ Global {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|x64.Build.0 = Checked|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|x86.ActiveCfg = Checked|x86 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Checked|x86.Build.0 = Checked|x86 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|Any CPU.ActiveCfg = Debug|x64 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|Any CPU.Build.0 = Debug|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|arm.ActiveCfg = Debug|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|arm.Build.0 = Debug|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|arm64.ActiveCfg = Debug|arm64 @@ -245,6 +242,8 @@ Global {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|x64.Build.0 = Debug|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|x86.ActiveCfg = Debug|x86 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Debug|x86.Build.0 = Debug|x86 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|Any CPU.ActiveCfg = Release|x64 + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|Any CPU.Build.0 = Release|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|arm.ActiveCfg = Release|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|arm.Build.0 = Release|arm {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|arm64.ActiveCfg = Release|arm64 @@ -253,11 +252,341 @@ Global {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|x64.Build.0 = Release|x64 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|x86.ActiveCfg = Release|x86 {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51}.Release|x86.Build.0 = Release|x86 + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|Any CPU.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|arm.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|arm.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|arm64.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|arm64.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|x64.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|x64.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|x86.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Checked|x86.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|arm.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|arm.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|arm64.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|arm64.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|x64.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Debug|x86.Build.0 = Debug|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|Any CPU.Build.0 = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|arm.ActiveCfg = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|arm.Build.0 = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|arm64.ActiveCfg = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|arm64.Build.0 = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|x64.ActiveCfg = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|x64.Build.0 = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|x86.ActiveCfg = Release|Any CPU + {EEB35F24-4878-4417-BB54-86AB1206E8D3}.Release|x86.Build.0 = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|Any CPU.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|arm.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|arm.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|arm64.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|arm64.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|x64.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|x64.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|x86.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Checked|x86.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|arm.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|arm.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|arm64.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|arm64.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|x64.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|x64.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|x86.ActiveCfg = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Debug|x86.Build.0 = Debug|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|Any CPU.Build.0 = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|arm.ActiveCfg = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|arm.Build.0 = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|arm64.ActiveCfg = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|arm64.Build.0 = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|x64.ActiveCfg = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|x64.Build.0 = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|x86.ActiveCfg = Release|Any CPU + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A}.Release|x86.Build.0 = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|Any CPU.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|arm.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|arm.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|arm64.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|arm64.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|x64.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|x64.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|x86.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Checked|x86.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|arm.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|arm.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|arm64.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|arm64.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|x64.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|x64.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|x86.ActiveCfg = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Debug|x86.Build.0 = Debug|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|Any CPU.Build.0 = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|arm.ActiveCfg = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|arm.Build.0 = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|arm64.ActiveCfg = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|arm64.Build.0 = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|x64.ActiveCfg = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|x64.Build.0 = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|x86.ActiveCfg = Release|Any CPU + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4}.Release|x86.Build.0 = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|Any CPU.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|arm.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|arm.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|arm64.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|arm64.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|x64.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|x64.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|x86.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Checked|x86.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|arm.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|arm.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|arm64.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|arm64.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|x64.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|x64.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|x86.ActiveCfg = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Debug|x86.Build.0 = Debug|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|Any CPU.Build.0 = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|arm.ActiveCfg = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|arm.Build.0 = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|arm64.ActiveCfg = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|arm64.Build.0 = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|x64.ActiveCfg = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|x64.Build.0 = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|x86.ActiveCfg = Release|Any CPU + {7B1980B2-F6AB-423A-A75F-41190570DE4D}.Release|x86.Build.0 = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|Any CPU.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|arm.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|arm.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|arm64.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|arm64.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|x64.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|x64.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|x86.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Checked|x86.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|Any CPU.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|arm.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|arm.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|arm64.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|arm64.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|x64.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|x64.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|x86.ActiveCfg = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Debug|x86.Build.0 = Debug|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|Any CPU.ActiveCfg = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|Any CPU.Build.0 = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|arm.ActiveCfg = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|arm.Build.0 = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|arm64.ActiveCfg = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|arm64.Build.0 = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|x64.ActiveCfg = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|x64.Build.0 = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|x86.ActiveCfg = Release|Any CPU + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217}.Release|x86.Build.0 = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|Any CPU.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|arm.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|arm.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|arm64.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|arm64.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|x64.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|x64.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|x86.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Checked|x86.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|arm.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|arm.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|arm64.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|arm64.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|x64.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|x64.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|x86.ActiveCfg = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Debug|x86.Build.0 = Debug|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|Any CPU.Build.0 = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|arm.ActiveCfg = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|arm.Build.0 = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|arm64.ActiveCfg = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|arm64.Build.0 = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|x64.ActiveCfg = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|x64.Build.0 = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|x86.ActiveCfg = Release|Any CPU + {D20FDE50-2841-46E9-B31A-6B145BFCB09E}.Release|x86.Build.0 = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|Any CPU.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|arm.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|arm.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|arm64.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|arm64.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|x64.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|x64.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|x86.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Checked|x86.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|arm.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|arm.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|arm64.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|arm64.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|x64.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|x64.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Debug|x86.Build.0 = Debug|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|Any CPU.Build.0 = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|arm.ActiveCfg = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|arm.Build.0 = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|arm64.ActiveCfg = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|arm64.Build.0 = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|x64.ActiveCfg = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|x64.Build.0 = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|x86.ActiveCfg = Release|Any CPU + {5B302881-1226-4A80-BDC1-EE70FB283949}.Release|x86.Build.0 = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|Any CPU.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|arm.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|arm.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|arm64.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|arm64.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|x64.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|x64.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|x86.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Checked|x86.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|arm.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|arm.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|arm64.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|arm64.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|x64.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|x64.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|x86.ActiveCfg = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Debug|x86.Build.0 = Debug|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|Any CPU.Build.0 = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|arm.ActiveCfg = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|arm.Build.0 = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|arm64.ActiveCfg = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|arm64.Build.0 = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|x64.ActiveCfg = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|x64.Build.0 = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|x86.ActiveCfg = Release|Any CPU + {3E67A258-6F80-435C-B83C-61BE17B93155}.Release|x86.Build.0 = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|Any CPU.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|arm.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|arm.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|arm64.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|arm64.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|x64.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|x64.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|x86.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Checked|x86.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|arm.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|arm.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|arm64.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|arm64.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|x64.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|x64.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|x86.ActiveCfg = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Debug|x86.Build.0 = Debug|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|Any CPU.Build.0 = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|arm.ActiveCfg = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|arm.Build.0 = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|arm64.ActiveCfg = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|arm64.Build.0 = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|x64.ActiveCfg = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|x64.Build.0 = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|x86.ActiveCfg = Release|Any CPU + {8C7DAB59-A791-42BC-BBA4-194BF1293841}.Release|x86.Build.0 = Release|Any CPU + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|Any CPU.ActiveCfg = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|Any CPU.Build.0 = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|arm.ActiveCfg = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|arm.Build.0 = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|arm64.ActiveCfg = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|arm64.Build.0 = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|x64.ActiveCfg = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|x64.Build.0 = Checked|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|x86.ActiveCfg = Checked|x86 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Checked|x86.Build.0 = Checked|x86 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|Any CPU.ActiveCfg = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|Any CPU.Build.0 = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|arm.ActiveCfg = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|arm.Build.0 = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|arm64.ActiveCfg = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|arm64.Build.0 = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|x64.ActiveCfg = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|x64.Build.0 = Debug|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|x86.ActiveCfg = Debug|x86 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Debug|x86.Build.0 = Debug|x86 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|Any CPU.ActiveCfg = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|Any CPU.Build.0 = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|arm.ActiveCfg = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|arm.Build.0 = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|arm64.ActiveCfg = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|arm64.Build.0 = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|x64.ActiveCfg = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|x64.Build.0 = Release|x64 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|x86.ActiveCfg = Release|x86 + {431A4C42-805F-40CD-9EEE-F794B6AF9B59}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {7498DD7C-76C1-4912-AF72-DA84E05B568F} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {33CAE331-16EE-443C-A0CC-4337B94A02AD} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {3E43ACA2-073E-4A66-BA9C-417C5F83D430} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {C3371E09-E8A6-4F9E-B4CB-B1CE3F4FCC51} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {977524B8-92D8-4DFC-91E4-11A0582B81BF} = {EC8F472E-5375-4962-9963-8B11F2924C2B} + {1BE6A0E4-9096-44DF-8C8C-33956BD0050F} = {B10E7FF9-AA48-4AF0-8242-EF5ED68846AD} + {5FB0FB7F-BB7A-4E16-B834-82413FFA7C9D} = {B10E7FF9-AA48-4AF0-8242-EF5ED68846AD} + {361ABA16-E054-4160-9998-A06BF377A82F} = {B10E7FF9-AA48-4AF0-8242-EF5ED68846AD} + {EEB35F24-4878-4417-BB54-86AB1206E8D3} = {DF7F14A3-3EB8-4B2C-AE04-678876997BA4} + {73A3DE01-9045-45CC-9BB5-21B0D1ABB46A} = {2E156392-D514-42DE-9532-42D2A7F0B9FB} + {795E1D25-FEA8-4556-B23C-1EE6A5A1CBC4} = {2E156392-D514-42DE-9532-42D2A7F0B9FB} + {7B1980B2-F6AB-423A-A75F-41190570DE4D} = {2E156392-D514-42DE-9532-42D2A7F0B9FB} + {735FEA0D-852A-47BD-B1FE-6B4D9C83F217} = {1BE6A0E4-9096-44DF-8C8C-33956BD0050F} + {D20FDE50-2841-46E9-B31A-6B145BFCB09E} = {1BE6A0E4-9096-44DF-8C8C-33956BD0050F} + {5B302881-1226-4A80-BDC1-EE70FB283949} = {5FB0FB7F-BB7A-4E16-B834-82413FFA7C9D} + {3E67A258-6F80-435C-B83C-61BE17B93155} = {361ABA16-E054-4160-9998-A06BF377A82F} + {8C7DAB59-A791-42BC-BBA4-194BF1293841} = {361ABA16-E054-4160-9998-A06BF377A82F} + {431A4C42-805F-40CD-9EEE-F794B6AF9B59} = {361ABA16-E054-4160-9998-A06BF377A82F} + {FF598E93-8E9E-4091-9F50-61A7572663AE} = {361ABA16-E054-4160-9998-A06BF377A82F} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {81B16D59-928B-49C1-839D-10E4747B0DC0} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{3e67a258-6f80-435c-b83c-61be17b93155}*SharedItemsImports = 5 + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{977524b8-92d8-4dfc-91e4-11a0582b81bf}*SharedItemsImports = 13 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{d20fde50-2841-46e9-b31a-6b145bfcb09e}*SharedItemsImports = 5 + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{e4bc768b-f97d-4a8f-9391-b65df3eb47c6}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 + EndGlobalSection EndGlobal diff --git a/src/coreclr/pal/src/exception/machexception.cpp b/src/coreclr/pal/src/exception/machexception.cpp index 8f58cd4d627b4..eaf783a233117 100644 --- a/src/coreclr/pal/src/exception/machexception.cpp +++ b/src/coreclr/pal/src/exception/machexception.cpp @@ -681,8 +681,8 @@ HijackFaultingThread( BuildExceptionRecord(exceptionInfo, &exceptionRecord); #if defined(HOST_AMD64) - threadContext.ContextFlags = CONTEXT_FLOATING_POINT; - CONTEXT_GetThreadContextFromThreadState(x86_FLOAT_STATE, (thread_state_t)&exceptionInfo.FloatState, &threadContext); + threadContext.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_XSTATE; + CONTEXT_GetThreadContextFromThreadState(x86_AVX512_STATE, (thread_state_t)&exceptionInfo.FloatState, &threadContext); threadContext.ContextFlags |= CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; CONTEXT_GetThreadContextFromThreadState(x86_THREAD_STATE, (thread_state_t)&exceptionInfo.ThreadState, &threadContext); @@ -1265,10 +1265,19 @@ MachExceptionInfo::MachExceptionInfo(mach_port_t thread, MachMessage& message) machret = thread_get_state(thread, x86_THREAD_STATE, (thread_state_t)&ThreadState, &count); CHECK_MACH("thread_get_state", machret); - count = x86_FLOAT_STATE_COUNT; - machret = thread_get_state(thread, x86_FLOAT_STATE, (thread_state_t)&FloatState, &count); - CHECK_MACH("thread_get_state(float)", machret); - + count = x86_AVX512_STATE_COUNT; + machret = thread_get_state(thread, x86_AVX512_STATE, (thread_state_t)&FloatState, &count); + if (machret != KERN_SUCCESS) + { + count = x86_AVX_STATE_COUNT; + machret = thread_get_state(thread, x86_AVX_STATE, (thread_state_t)&FloatState, &count); + if (machret != KERN_SUCCESS) + { + count = x86_FLOAT_STATE_COUNT; + machret = thread_get_state(thread, x86_FLOAT_STATE, (thread_state_t)&FloatState, &count); + CHECK_MACH("thread_get_state(float)", machret); + } + } count = x86_DEBUG_STATE_COUNT; machret = thread_get_state(thread, x86_DEBUG_STATE, (thread_state_t)&DebugState, &count); CHECK_MACH("thread_get_state(debug)", machret); diff --git a/src/coreclr/pal/src/exception/machmessage.h b/src/coreclr/pal/src/exception/machmessage.h index 4245d2b6fb0c6..194f066dce4cd 100644 --- a/src/coreclr/pal/src/exception/machmessage.h +++ b/src/coreclr/pal/src/exception/machmessage.h @@ -84,7 +84,7 @@ struct MachExceptionInfo mach_exception_data_type_t Subcodes[2]; #if defined(HOST_AMD64) x86_thread_state_t ThreadState; - x86_float_state_t FloatState; + x86_avx512_state_t FloatState; x86_debug_state_t DebugState; #elif defined(HOST_ARM64) arm_thread_state64_t ThreadState; diff --git a/src/coreclr/pal/src/thread/context.cpp b/src/coreclr/pal/src/thread/context.cpp index 48fd7e94d3c3d..5112d8469b098 100644 --- a/src/coreclr/pal/src/thread/context.cpp +++ b/src/coreclr/pal/src/thread/context.cpp @@ -1717,6 +1717,18 @@ CONTEXT_GetThreadContextFromThreadState( CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->fsh.flavor, (thread_state_t)&pState->ufs, lpContext); } break; + case x86_AVX_STATE: + { + x86_avx_state_t *pState = (x86_avx_state_t *)threadState; + CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->ash.flavor, (thread_state_t)&pState->ufs, lpContext); + } + break; + case x86_AVX512_STATE: + { + x86_avx512_state_t *pState = (x86_avx512_state_t *)threadState; + CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->ash.flavor, (thread_state_t)&pState->ufs, lpContext); + } + break; #elif defined(HOST_ARM64) case ARM_THREAD_STATE64: if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER) & CONTEXT_AREA_MASK) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs index 8dbc00caa7c46..80e094f5b3117 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExportsFileWriter.cs @@ -13,11 +13,11 @@ namespace ILCompiler public class ExportsFileWriter { private readonly string _exportsFile; - private readonly IEnumerable _exportSymbols; + private readonly string[] _exportSymbols; private readonly List _methods; private readonly TypeSystemContext _context; - public ExportsFileWriter(TypeSystemContext context, string exportsFile, IEnumerable exportSymbols) + public ExportsFileWriter(TypeSystemContext context, string exportsFile, string[] exportSymbols) { _exportsFile = exportsFile; _exportSymbols = exportSymbols; @@ -51,11 +51,14 @@ public void EmitExportedMethods() else { streamWriter.WriteLine("V1.0 {"); - streamWriter.WriteLine(" global:"); - foreach (string symbol in _exportSymbols) - streamWriter.WriteLine($" {symbol};"); - foreach (var method in _methods) - streamWriter.WriteLine($" {method.GetUnmanagedCallersOnlyExportName()};"); + if (_exportSymbols.Length != 0 || _methods.Count != 0) + { + streamWriter.WriteLine(" global:"); + foreach (string symbol in _exportSymbols) + streamWriter.WriteLine($" {symbol};"); + foreach (var method in _methods) + streamWriter.WriteLine($" {method.GetUnmanagedCallersOnlyExportName()};"); + } streamWriter.WriteLine(" local: *;"); streamWriter.WriteLine("};"); } diff --git a/src/coreclr/utilcode/check.cpp b/src/coreclr/utilcode/check.cpp index 617f0c3dd9836..6ca26099d4002 100644 --- a/src/coreclr/utilcode/check.cpp +++ b/src/coreclr/utilcode/check.cpp @@ -171,7 +171,7 @@ void CHECK::Setup(LPCSTR message, LPCSTR condition, LPCSTR file, INT line) // Try to build a stack of condition failures StackSString context; - context.Printf("%s\n\t%s%s FAILED: %s\n\t\t%s, line: %d", + context.Printf("%s\n\t%s%s FAILED: %s\n\t\t%s:%d", m_condition, message && *message ? message : "", message && *message ? ": " : "", diff --git a/src/coreclr/utilcode/debug.cpp b/src/coreclr/utilcode/debug.cpp index cc49e9bcfedc1..00866d255d7fd 100644 --- a/src/coreclr/utilcode/debug.cpp +++ b/src/coreclr/utilcode/debug.cpp @@ -156,7 +156,7 @@ VOID LogAssert( // Log asserts to the stress log. Note that we can't include the szExpr b/c that // may not be a string literal (particularly for formatt-able asserts). - STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s, line:%d\n", szFile, iLine); + STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s:%d\n", szFile, iLine); SYSTEMTIME st; #ifndef TARGET_UNIX diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 2b04bd530cf80..f8436aca04d5b 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -3946,7 +3946,7 @@ void AppDomain::ExceptionUnwind(Frame *pFrame) #ifndef DACCESS_COMPILE -DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef) +Assembly* AppDomain::RaiseTypeResolveEventThrowing(Assembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef) { CONTRACTL { @@ -3959,7 +3959,7 @@ DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssemb OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); - DomainAssembly* pResolvedAssembly = NULL; + Assembly* pResolvedAssembly = NULL; _ASSERTE(strcmp(szName, g_AppDomainClassName)); GCX_COOP(); @@ -3974,7 +3974,7 @@ DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssemb GCPROTECT_BEGIN(gc); if (pAssembly != NULL) - gc.AssemblyRef = pAssembly->GetExposedAssemblyObject(); + gc.AssemblyRef = pAssembly->GetExposedObject(); MethodDescCallSite onTypeResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_TYPE_RESOLVE); @@ -3988,7 +3988,7 @@ DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssemb if (ResultingAssemblyRef != NULL) { - pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly(); + pResolvedAssembly = ResultingAssemblyRef->GetAssembly(); if (pResultingAssemblyRef) *pResultingAssemblyRef = ResultingAssemblyRef; @@ -4006,7 +4006,7 @@ DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssemb } -Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName) +Assembly* AppDomain::RaiseResourceResolveEvent(Assembly* pAssembly, LPCSTR szName) { CONTRACT(Assembly*) { @@ -4032,7 +4032,7 @@ Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR GCPROTECT_BEGIN(gc); if (pAssembly != NULL) - gc.AssemblyRef=pAssembly->GetExposedAssemblyObject(); + gc.AssemblyRef=pAssembly->GetExposedObject(); MethodDescCallSite onResourceResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_RESOURCE_RESOLVE); gc.str = StringObject::NewString(szName); @@ -4095,7 +4095,7 @@ AppDomain::RaiseAssemblyResolveEvent( { if (pSpec->GetParentAssembly() != NULL) { - gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject(); + gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedObject(); } MethodDescCallSite onAssemblyResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_ASSEMBLY_RESOLVE); diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 5957aad24655e..7bf26952da867 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1517,8 +1517,8 @@ class AppDomain : public BaseDomain } static void RaiseExitProcessEvent(); - Assembly* RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName); - DomainAssembly* RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef); + Assembly* RaiseResourceResolveEvent(Assembly* pAssembly, LPCSTR szName); + Assembly* RaiseTypeResolveEventThrowing(Assembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef); Assembly* RaiseAssemblyResolveEvent(AssemblySpec *pSpec); private: diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index c7fb64b38158a..71482da1ed829 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -1590,9 +1590,8 @@ BOOL Assembly::FileNotFound(HRESULT hr) BOOL Assembly::GetResource(LPCSTR szName, DWORD *cbResource, - PBYTE *pbInMemoryResource, Assembly** pAssemblyRef, - LPCSTR *szFileName, DWORD *dwLocation, - BOOL fSkipRaiseResolveEvent) + PBYTE *pbInMemoryResource, Assembly** pAssemblyRef, + LPCSTR *szFileName, DWORD *dwLocation) { CONTRACTL { @@ -1602,13 +1601,10 @@ BOOL Assembly::GetResource(LPCSTR szName, DWORD *cbResource, } CONTRACTL_END; - DomainAssembly *pAssembly = NULL; - BOOL result = GetDomainAssembly()->GetResource(szName, cbResource, - pbInMemoryResource, &pAssembly, - szFileName, dwLocation, - fSkipRaiseResolveEvent); - if (result && pAssemblyRef != NULL && pAssembly != NULL) - *pAssemblyRef = pAssembly->GetAssembly(); + BOOL result = GetPEAssembly()->GetResource(szName, cbResource, + pbInMemoryResource, pAssemblyRef, + szFileName, dwLocation, + this); return result; } diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index 987b7231b0a40..617aa07676453 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -259,9 +259,8 @@ class Assembly ~Assembly(); BOOL GetResource(LPCSTR szName, DWORD *cbResource, - PBYTE *pbInMemoryResource, Assembly **pAssemblyRef, - LPCSTR *szFileName, DWORD *dwLocation, - BOOL fSkipRaiseResolveEvent = FALSE); + PBYTE *pbInMemoryResource, Assembly **pAssemblyRef, + LPCSTR *szFileName, DWORD *dwLocation); //**************************************************************************************** #ifdef DACCESS_COMPILE diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index ade4baf688f30..ca4820c405f61 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -63,10 +63,6 @@ extern "C" void QCALLTYPE AssemblyNative_InternalLoad(NativeAssemblyNameParts* p { pRefAssembly = SystemDomain::GetCallersAssembly(stackMark); } - if (pRefAssembly) - { - pParentAssembly = pRefAssembly->GetDomainAssembly(); - } } AssemblySpec spec; @@ -93,8 +89,8 @@ extern "C" void QCALLTYPE AssemblyNative_InternalLoad(NativeAssemblyNameParts* p spec.Init(ssName.GetUTF8(), &asmInfo, pAssemblyNameParts->_pPublicKeyOrToken, pAssemblyNameParts->_cbPublicKeyOrToken, pAssemblyNameParts->_flags); - if (pParentAssembly != NULL) - spec.SetParentAssembly(pParentAssembly); + if (pRefAssembly != NULL) + spec.SetParentAssembly(pRefAssembly); // Have we been passed the reference to the binder against which this load should be triggered? // If so, then use it to set the fallback load context binder. @@ -138,7 +134,7 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma ReleaseHolder pAssembly; // Set the caller's assembly to be CoreLib - DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly(); + Assembly *pCallersAssembly = SystemDomain::System()->SystemAssembly(); // Initialize the AssemblySpec AssemblySpec spec; @@ -650,9 +646,9 @@ extern "C" BYTE * QCALLTYPE AssemblyNative_GetResource(QCall::AssemblyHandle pAs if (*pNameUTF8 == '\0') COMPlusThrow(kArgumentException, W("Format_StringZeroLength")); - pAssembly->GetResource(pNameUTF8, length, + pAssembly->GetPEAssembly()->GetResource(pNameUTF8, length, &pbInMemoryResource, NULL, NULL, - NULL, FALSE); + NULL, pAssembly->GetAssembly()); END_QCALL; @@ -679,12 +675,12 @@ extern "C" INT32 QCALLTYPE AssemblyNative_GetManifestResourceInfo(QCall::Assembl if (*pNameUTF8 == '\0') COMPlusThrow(kArgumentException, W("Format_StringZeroLength")); - DomainAssembly * pReferencedAssembly = NULL; + Assembly * pReferencedAssembly = NULL; LPCSTR pFileName = NULL; DWORD dwLocation = 0; - if (pAssembly->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName, - &dwLocation, FALSE)) + if (pAssembly->GetPEAssembly()->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName, + &dwLocation, pAssembly->GetAssembly())) { if (pFileName) retFileName.Set(pFileName); @@ -692,7 +688,7 @@ extern "C" INT32 QCALLTYPE AssemblyNative_GetManifestResourceInfo(QCall::Assembl GCX_COOP(); if (pReferencedAssembly) - retAssembly.Set(pReferencedAssembly->GetExposedAssemblyObject()); + retAssembly.Set(pReferencedAssembly->GetExposedObject()); rv = dwLocation; } diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp index a4872b732097b..11a394f665c46 100644 --- a/src/coreclr/vm/assemblyspec.cpp +++ b/src/coreclr/vm/assemblyspec.cpp @@ -148,7 +148,7 @@ AssemblySpecHash::~AssemblySpecHash() HRESULT AssemblySpec::InitializeSpecInternal(mdToken kAssemblyToken, IMDInternalImport *pImport, - DomainAssembly *pStaticParent) + Assembly *pStaticParent) { CONTRACTL { @@ -325,12 +325,12 @@ AssemblyBinder* AssemblySpec::GetBinderFromParentAssembly(AppDomain *pDomain) CONTRACTL_END; AssemblyBinder *pParentAssemblyBinder = NULL; - DomainAssembly *pParentDomainAssembly = GetParentAssembly(); + Assembly *pParentAssembly = GetParentAssembly(); - if(pParentDomainAssembly != NULL) + if(pParentAssembly != NULL) { // Get the PEAssembly associated with the parent's domain assembly - PEAssembly *pParentPEAssembly = pParentDomainAssembly->GetPEAssembly(); + PEAssembly *pParentPEAssembly = pParentAssembly->GetPEAssembly(); pParentAssemblyBinder = pParentPEAssembly->GetAssemblyBinder(); } @@ -1121,7 +1121,7 @@ BOOL AssemblySpecBindingCache::CompareSpecs(UPTR u1, UPTR u2) return a1->CompareEx(a2); } -DomainAssembly * AssemblySpec::GetParentAssembly() +Assembly * AssemblySpec::GetParentAssembly() { LIMITED_METHOD_CONTRACT; return m_pParentAssembly; diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp index 23a7c96e64756..96b8e409d1d99 100644 --- a/src/coreclr/vm/assemblyspec.hpp +++ b/src/coreclr/vm/assemblyspec.hpp @@ -28,7 +28,7 @@ class AssemblySpec : public BaseAssemblySpec { private: AppDomain *m_pAppDomain; - DomainAssembly *m_pParentAssembly; + Assembly *m_pParentAssembly; // Contains the reference to the fallback load context associated with RefEmitted assembly requesting the load of another assembly (static or dynamic) AssemblyBinder *m_pFallbackBinder; @@ -38,7 +38,7 @@ class AssemblySpec : public BaseAssemblySpec HRESULT InitializeSpecInternal(mdToken kAssemblyRefOrDef, IMDInternalImport *pImport, - DomainAssembly *pStaticParent); + Assembly *pStaticParent); // InitializeSpecInternal should be used very carefully so it's made private. // functions that take special care (and thus are allowed to use the function) are listed below @@ -73,7 +73,7 @@ class AssemblySpec : public BaseAssemblySpec } - DomainAssembly* GetParentAssembly(); + Assembly* GetParentAssembly(); AssemblyBinder* GetBinderFromParentAssembly(AppDomain *pDomain); @@ -82,7 +82,7 @@ class AssemblySpec : public BaseAssemblySpec void InitializeSpec(mdToken kAssemblyRefOrDef, IMDInternalImport *pImport, - DomainAssembly *pStaticParent = NULL) + Assembly *pStaticParent = NULL) { CONTRACTL { @@ -92,7 +92,7 @@ class AssemblySpec : public BaseAssemblySpec MODE_ANY; } CONTRACTL_END; - HRESULT hr=InitializeSpecInternal(kAssemblyRefOrDef, pImport,pStaticParent); + HRESULT hr = InitializeSpecInternal(kAssemblyRefOrDef, pImport, pStaticParent); if(FAILED(hr)) EEFileLoadException::Throw(this,hr); }; @@ -102,7 +102,7 @@ class AssemblySpec : public BaseAssemblySpec void AssemblyNameInit(ASSEMBLYNAMEREF* pName); //[in,out] - void SetParentAssembly(DomainAssembly *pAssembly) + void SetParentAssembly(Assembly *pAssembly) { CONTRACTL { diff --git a/src/coreclr/vm/callconvbuilder.cpp b/src/coreclr/vm/callconvbuilder.cpp index af5d260afb082..d68ac7f023ec3 100644 --- a/src/coreclr/vm/callconvbuilder.cpp +++ b/src/coreclr/vm/callconvbuilder.cpp @@ -452,7 +452,7 @@ HRESULT CallConv::TryGetCallingConventionFromUnmanagedCallConv( callConvsArg.Init("CallConvs", SERIALIZATION_TYPE_SZARRAY, callConvsType); InlineFactory, 4> caValueArrayFactory; - DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); + Assembly* assembly = pMD->GetLoaderModule()->GetAssembly(); IfFailThrow(CustomAttribute::ParseArgumentValues( pData, cData, @@ -461,7 +461,7 @@ HRESULT CallConv::TryGetCallingConventionFromUnmanagedCallConv( 0, &callConvsArg, 1, - domainAssembly)); + assembly )); // Value isn't defined if (callConvsArg.val.type.tag == SERIALIZATION_TYPE_UNDEFINED) @@ -527,7 +527,7 @@ bool CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(_In_ MethodDesc* namedArgs[1].Init("EntryPoint", SERIALIZATION_TYPE_STRING, caEntryPoint); InlineFactory, 4> caValueArrayFactory; - DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); + Assembly* assembly = pMD->GetLoaderModule()->GetAssembly(); IfFailThrow(CustomAttribute::ParseArgumentValues( pData, cData, @@ -536,7 +536,7 @@ bool CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(_In_ MethodDesc* 0, namedArgs, ARRAY_SIZE(namedArgs), - domainAssembly)); + assembly)); // If the value isn't defined, then return without setting anything. if (namedArgs[0].val.type.tag == SERIALIZATION_TYPE_UNDEFINED) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 81d6f2347cd1b..eb49ed746edc2 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -406,11 +406,15 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) INSTANCE_CHECK; STANDARD_VM_CHECK; PRECONDITION(szName == NULL); + PRECONDITION(m_pPEAssembly->IsLoaded()); } CONTRACTL_END; m_loaderAllocator = GetAssembly()->GetLoaderAllocator(); m_pSimpleName = m_pPEAssembly->GetSimpleName(); + m_baseAddress = m_pPEAssembly->HasLoadedPEImage() ? m_pPEAssembly->GetLoadedLayout()->GetBase() : NULL; + if (m_pPEAssembly->IsReflectionEmit()) + m_dwTransientFlags |= IS_REFLECTION_EMIT; m_Crst.Init(CrstModule); m_LookupTableCrst.Init(CrstModuleLookupTable, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD)); @@ -2239,61 +2243,40 @@ Module::GetAssemblyIfLoaded( if ((pDomainAssembly == NULL) || !pDomainAssembly->IsLoaded()) pAssembly = NULL; } -#endif //!DACCESS_COMPILE if (pAssembly == NULL) { - do - { - AppDomain * pAppDomainExamine = AppDomain::GetCurrentDomain(); - - DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->GetDomainAssembly(); - if (pCurAssemblyInExamineDomain == NULL) - { - continue; - } + IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride); -#ifndef DACCESS_COMPILE - { - IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride); - - //we have to be very careful here. - //we are using InitializeSpecInternal so we need to make sure that under no condition - //the data we pass to it can outlive the assembly spec. - AssemblySpec spec; - if (FAILED(spec.InitializeSpecInternal(kAssemblyRef, - pMDImport, - pCurAssemblyInExamineDomain))) - { - continue; - } - - // If we have been passed the binding context for the loaded assembly that is being looked up in the - // cache, then set it up in the AssemblySpec for the cache lookup to use it below. - if (pBinderForLoadedAssembly != NULL) - { - _ASSERTE(spec.GetBinder() == NULL); - spec.SetBinder(pBinderForLoadedAssembly); - } - DomainAssembly * pDomainAssembly = nullptr; + //we have to be very careful here. + //we are using InitializeSpecInternal so we need to make sure that under no condition + //the data we pass to it can outlive the assembly spec. + AssemblySpec spec; + if (FAILED(spec.InitializeSpecInternal(kAssemblyRef, + pMDImport, + GetAssembly()))) + { + return NULL; + } - { - pDomainAssembly = pAppDomainExamine->FindCachedAssembly(&spec, FALSE /*fThrow*/); - } + // If we have been passed the binding context for the loaded assembly that is being looked up in the + // cache, then set it up in the AssemblySpec for the cache lookup to use it below. + if (pBinderForLoadedAssembly != NULL) + { + _ASSERTE(spec.GetBinder() == NULL); + spec.SetBinder(pBinderForLoadedAssembly); + } - if (pDomainAssembly && pDomainAssembly->IsLoaded()) - pAssembly = pDomainAssembly->GetAssembly(); + DomainAssembly * pDomainAssembly = AppDomain::GetCurrentDomain()->FindCachedAssembly(&spec, FALSE /*fThrow*/); - // Only store in the rid map if working with the current AppDomain. - if (fCanUseRidMap && pAssembly) - StoreAssemblyRef(kAssemblyRef, pAssembly); + if (pDomainAssembly && pDomainAssembly->IsLoaded()) + pAssembly = pDomainAssembly->GetAssembly(); - if (pAssembly != NULL) - break; - } -#endif //!DACCESS_COMPILE - } while (false); + // Only store in the rid map if working with the current AppDomain. + if (fCanUseRidMap && pAssembly) + StoreAssemblyRef(kAssemblyRef, pAssembly); } +#endif //!DACCESS_COMPILE // When walking the stack or computing GC information this function should never fail. _ASSERTE((pAssembly != NULL) || !(IsStackWalkerThread() || IsGCThread())); @@ -2372,9 +2355,9 @@ DomainAssembly * Module::LoadAssemblyImpl(mdAssemblyRef kAssemblyRef) } { - PEAssemblyHolder pPEAssembly = GetDomainAssembly()->GetPEAssembly()->LoadAssembly(kAssemblyRef); + PEAssemblyHolder pPEAssembly = GetPEAssembly()->LoadAssembly(kAssemblyRef); AssemblySpec spec; - spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainAssembly()); + spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetAssembly()); // Set the binding context in the AssemblySpec if one is available. This can happen if the LoadAssembly ended up // invoking the custom AssemblyLoadContext implementation that returned a reference to an assembly bound to a different // AssemblyLoadContext implementation. diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 2523ebf45c1a8..cb370bae893e0 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -603,6 +603,7 @@ class Module : public ModuleBase PTR_CUTF8 m_pSimpleName; // Cached simple name for better performance and easier diagnostics PTR_PEAssembly m_pPEAssembly; + PTR_VOID m_baseAddress; // Cached base address for easier diagnostics enum { // These are the values set in m_dwTransientFlags. @@ -615,6 +616,8 @@ class Module : public ModuleBase IS_PROFILER_NOTIFIED = 0x00000010, IS_ETW_NOTIFIED = 0x00000020, + IS_REFLECTION_EMIT = 0x00000040, + // // Note: The values below must match the ones defined in // cordbpriv.h for DebuggerAssemblyControlFlags when shifted @@ -886,7 +889,7 @@ class Module : public ModuleBase CodeVersionManager * GetCodeVersionManager(); #endif - BOOL IsReflectionEmit() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GetPEAssembly()->IsReflectionEmit(); } + BOOL IsReflectionEmit() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return (m_dwTransientFlags & IS_REFLECTION_EMIT) != 0; } BOOL IsSystem() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return m_pPEAssembly->IsSystem(); } // Returns true iff the debugger can see this module. BOOL IsVisibleToDebugger(); @@ -1602,6 +1605,26 @@ class Module : public ModuleBase uint32_t GetNativeMetadataAssemblyCount(); #endif // !defined(DACCESS_COMPILE) + + template friend struct ::cdac_offsets; +}; + +template<> +struct cdac_offsets +{ + static constexpr size_t Assembly = offsetof(Module, m_pAssembly); + static constexpr size_t Base = offsetof(Module, m_baseAddress); + static constexpr size_t Flags = offsetof(Module, m_dwTransientFlags); + static constexpr size_t LoaderAllocator = offsetof(Module, m_loaderAllocator); + static constexpr size_t ThunkHeap = offsetof(Module, m_pThunkHeap); + + // Lookup map pointers + static constexpr size_t FieldDefToDescMap = offsetof(Module, m_FieldDefToDescMap) + offsetof(LookupMap, pTable); + static constexpr size_t ManifestModuleReferencesMap = offsetof(Module, m_ManifestModuleReferencesMap) + offsetof(LookupMap, pTable); + static constexpr size_t MemberRefToDescMap = offsetof(Module, m_MemberRefMap) + offsetof(LookupMap, pTable); + static constexpr size_t MethodDefToDescMap = offsetof(Module, m_MethodDefToDescMap) + offsetof(LookupMap, pTable); + static constexpr size_t TypeDefToMethodTableMap = offsetof(Module, m_TypeDefToMethodTableMap) + offsetof(LookupMap, pTable); + static constexpr size_t TypeRefToMethodTableMap = offsetof(Module, m_TypeRefToMethodTableMap) + offsetof(LookupMap, pTable); }; // diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index a85db9e3b96d1..f694bce1ade52 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -1615,12 +1615,6 @@ TypeHandle ClassLoader::LookupTypeDefOrRefInModule(ModuleBase *pModule, mdToken RETURN(typeHandle); } -DomainAssembly *ClassLoader::GetDomainAssembly() -{ - WRAPPER_NO_CONTRACT; - return GetAssembly()->GetDomainAssembly(); -} - #ifndef DACCESS_COMPILE // @@ -1958,17 +1952,17 @@ TypeHandle ClassLoader::LoadTypeDefThrowing(Module *pModule, className); GCX_COOP(); ASSEMBLYREF asmRef = NULL; - DomainAssembly *pDomainAssembly = NULL; + Assembly* pAssembly = NULL; GCPROTECT_BEGIN(asmRef); - pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing( - pModule->GetAssembly()->GetDomainAssembly(), + pAssembly = pDomain->RaiseTypeResolveEventThrowing( + pModule->GetAssembly(), pszFullName, &asmRef); if (asmRef != NULL) { - _ASSERTE(pDomainAssembly != NULL); - if (pDomainAssembly->GetAssembly()->GetLoaderAllocator()->IsCollectible()) + _ASSERTE(pAssembly != NULL); + if (pAssembly->GetLoaderAllocator()->IsCollectible()) { if (!pModule->GetLoaderAllocator()->IsCollectible()) { @@ -1976,14 +1970,12 @@ TypeHandle ClassLoader::LoadTypeDefThrowing(Module *pModule, COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible")); } - pModule->GetLoaderAllocator()->EnsureReference(pDomainAssembly->GetAssembly()->GetLoaderAllocator()); + pModule->GetLoaderAllocator()->EnsureReference(pAssembly->GetLoaderAllocator()); } } GCPROTECT_END(); - if (pDomainAssembly != NULL) + if (pAssembly != NULL) { - Assembly *pAssembly = pDomainAssembly->GetAssembly(); - NameHandle name(nameSpace, className); name.SetTypeToken(pModule, typeDef); name.SetTokenNotToLoad(tdAllAssemblies); diff --git a/src/coreclr/vm/clsload.hpp b/src/coreclr/vm/clsload.hpp index fb79f0dfc810e..95afa2716ec9f 100644 --- a/src/coreclr/vm/clsload.hpp +++ b/src/coreclr/vm/clsload.hpp @@ -573,7 +573,6 @@ class ClassLoader void Init(AllocMemTracker *pamTracker); PTR_Assembly GetAssembly(); - DomainAssembly* GetDomainAssembly(); void FreeModules(); diff --git a/src/coreclr/vm/customattribute.cpp b/src/coreclr/vm/customattribute.cpp index 4386c74f1daae..e1bb562c5fe25 100644 --- a/src/coreclr/vm/customattribute.cpp +++ b/src/coreclr/vm/customattribute.cpp @@ -16,11 +16,11 @@ #include "runtimehandles.h" #include "typestring.h" -static TypeHandle GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, DomainAssembly* pDomainAssembly) +static TypeHandle GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, Assembly* pAssembly) { CONTRACTL { - PRECONDITION(CheckPointer(pDomainAssembly)); + PRECONDITION(CheckPointer(pAssembly)); PRECONDITION(CheckPointer(szEnumName)); PRECONDITION(cbEnumName); THROWS; @@ -30,13 +30,13 @@ static TypeHandle GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, DomainA CONTRACTL_END; StackSString sszEnumName(SString::Utf8, szEnumName, cbEnumName); - return TypeName::GetTypeReferencedByCustomAttribute(sszEnumName.GetUnicode(), pDomainAssembly->GetAssembly()); + return TypeName::GetTypeReferencedByCustomAttribute(sszEnumName.GetUnicode(), pAssembly); } static HRESULT ParseCaType( CustomAttributeParser &ca, CaType* pCaType, - DomainAssembly* pDomainAssembly, + Assembly* pAssembly, StackSString* ss = NULL) { WRAPPER_NO_CONTRACT; @@ -48,7 +48,7 @@ static HRESULT ParseCaType( if (pCaType->tag == SERIALIZATION_TYPE_ENUM || (pCaType->tag == SERIALIZATION_TYPE_SZARRAY && pCaType->arrayType == SERIALIZATION_TYPE_ENUM )) { - TypeHandle th = GetTypeForEnum(pCaType->szEnumName, pCaType->cEnumName, pDomainAssembly); + TypeHandle th = GetTypeForEnum(pCaType->szEnumName, pCaType->cEnumName, pAssembly); if (!th.IsNull() && th.IsEnum()) { @@ -83,7 +83,7 @@ static HRESULT ParseCaValue( CaValue* pCaArg, CaType* pCaParam, CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly) + Assembly* pAssembly) { CONTRACTL { @@ -99,7 +99,7 @@ static HRESULT ParseCaValue( CaType elementType; if (pCaParam->tag == SERIALIZATION_TYPE_TAGGED_OBJECT) - IfFailGo(ParseCaType(ca, &pCaArg->type, pDomainAssembly)); + IfFailGo(ParseCaType(ca, &pCaArg->type, pAssembly)); else pCaArg->type = *pCaParam; @@ -155,7 +155,7 @@ static HRESULT ParseCaValue( elementType.Init(pCaArg->type.arrayType, SERIALIZATION_TYPE_UNDEFINED, pCaArg->type.enumType, pCaArg->type.szEnumName, pCaArg->type.cEnumName); for (ULONG i = 0; i < pCaArg->arr.length; i++) - IfFailGo(ParseCaValue(ca, &*pCaArg->arr.pSArray->Append(), &elementType, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &*pCaArg->arr.pSArray->Append(), &elementType, pCaValueArrayFactory, pAssembly)); break; @@ -174,7 +174,7 @@ static HRESULT ParseCaCtorArgs( CaArg* pArgs, ULONG cArgs, CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly) + Assembly* pAssembly) { WRAPPER_NO_CONTRACT; @@ -191,7 +191,7 @@ static HRESULT ParseCaCtorArgs( for (ix=0; ixval, &pArg->type, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &pArg->val, &pArg->type, pCaValueArrayFactory, pAssembly)); } ErrExit: @@ -210,11 +210,11 @@ static HRESULT ParseCaNamedArgs( CaNamedArg *pNamedParams, ULONG cNamedParams, CaValueArrayFactory* pCaValueArrayFactory, - DomainAssembly* pDomainAssembly) + Assembly* pAssembly) { CONTRACTL { PRECONDITION(CheckPointer(pCaValueArrayFactory)); - PRECONDITION(CheckPointer(pDomainAssembly)); + PRECONDITION(CheckPointer(pAssembly)); THROWS; } CONTRACTL_END; @@ -243,7 +243,7 @@ static HRESULT ParseCaNamedArgs( // Get argument type information CaType* pNamedArgType = &namedArg.type; StackSString ss; - IfFailGo(ParseCaType(ca, pNamedArgType, pDomainAssembly, &ss)); + IfFailGo(ParseCaType(ca, pNamedArgType, pAssembly, &ss)); LPCSTR szLoadedEnumName = NULL; @@ -319,7 +319,7 @@ static HRESULT ParseCaNamedArgs( IfFailGo(PostError(META_E_CA_REPEATED_ARG, namedArg.cName, namedArg.szName)); } - IfFailGo(ParseCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type, pCaValueArrayFactory, pAssembly)); } ErrExit: @@ -334,15 +334,15 @@ HRESULT CustomAttribute::ParseArgumentValues( COUNT_T cArgs, CaNamedArg* pCaNamedArgs, COUNT_T cNamedArgs, - DomainAssembly* pDomainAssembly) + Assembly* pAssembly) { WRAPPER_NO_CONTRACT; HRESULT hr = S_OK; CustomAttributeParser cap(pCa, cCa); - IfFailGo(ParseCaCtorArgs(cap, pCaArgs, cArgs, pCaValueArrayFactory, pDomainAssembly)); - IfFailGo(ParseCaNamedArgs(cap, pCaNamedArgs, cNamedArgs, pCaValueArrayFactory, pDomainAssembly)); + IfFailGo(ParseCaCtorArgs(cap, pCaArgs, cArgs, pCaValueArrayFactory, pAssembly)); + IfFailGo(ParseCaNamedArgs(cap, pCaNamedArgs, cNamedArgs, pCaValueArrayFactory, pAssembly)); ErrExit: return hr; diff --git a/src/coreclr/vm/customattribute.h b/src/coreclr/vm/customattribute.h index b5074872f736b..2cbc846bff8f1 100644 --- a/src/coreclr/vm/customattribute.h +++ b/src/coreclr/vm/customattribute.h @@ -20,7 +20,7 @@ namespace CustomAttribute COUNT_T cArgs, CaNamedArg* pCaNamedArgs, COUNT_T cNamedArgs, - DomainAssembly* pDomainAssembly); + Assembly* pAssembly); } extern "C" BOOL QCALLTYPE CustomAttribute_ParseAttributeUsageAttribute( diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index 3c6c68de688e9..30dbe9207e630 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -815,42 +815,6 @@ void DomainAssembly::DeliverSyncEvents() #endif // DEBUGGING_SUPPORTED } -/* - // The enum for dwLocation from managed code: - public enum ResourceLocation - { - Embedded = 1, - ContainedInAnotherAssembly = 2, - ContainedInManifestFile = 4 - } -*/ - -BOOL DomainAssembly::GetResource(LPCSTR szName, DWORD *cbResource, - PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef, - LPCSTR *szFileName, DWORD *dwLocation, - BOOL fSkipRaiseResolveEvent) -{ - CONTRACTL - { - INSTANCE_CHECK; - THROWS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - return GetPEAssembly()->GetResource( szName, - cbResource, - pbInMemoryResource, - pAssemblyRef, - szFileName, - dwLocation, - fSkipRaiseResolveEvent, - this, - AppDomain::GetCurrentDomain() ); -} - - DWORD DomainAssembly::ComputeDebuggingConfig() { CONTRACTL diff --git a/src/coreclr/vm/domainassembly.h b/src/coreclr/vm/domainassembly.h index 40262412f4753..64b8c4a9fdf4e 100644 --- a/src/coreclr/vm/domainassembly.h +++ b/src/coreclr/vm/domainassembly.h @@ -290,15 +290,6 @@ class DomainAssembly final return m_pLoaderAllocator; } -// ------------------------------------------------------------ -// Resource access -// ------------------------------------------------------------ - - BOOL GetResource(LPCSTR szName, DWORD* cbResource, - PBYTE* pbInMemoryResource, DomainAssembly** pAssemblyRef, - LPCSTR* szFileName, DWORD* dwLocation, - BOOL fSkipRaiseResolveEvent); - private: // ------------------------------------------------------------ // Loader API diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index d2c515043a1ad..79c3043a24964 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -5517,7 +5517,7 @@ VOID ETW::EnumerationLog::IterateAssembly(Assembly *pAssembly, DWORD enumeration if((enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd) || (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCStart)) { - Module* pModule = pAssembly->GetDomainAssembly()->GetModule(); + Module* pModule = pAssembly->GetModule(); ETW::LoaderLog::SendModuleEvent(pModule, enumerationOptions, TRUE); } diff --git a/src/coreclr/vm/interoputil.cpp b/src/coreclr/vm/interoputil.cpp index 5b9224ce041f4..a96ced9828dfc 100644 --- a/src/coreclr/vm/interoputil.cpp +++ b/src/coreclr/vm/interoputil.cpp @@ -3082,6 +3082,7 @@ void IUInvokeDispMethod( DISPID MemberID = 0; ByrefArgumentInfo* aByrefArgInfos = NULL; BOOL bSomeArgsAreByref = FALSE; + SafeComHolder pUnk = NULL; SafeComHolder pDisp = NULL; SafeComHolder pDispEx = NULL; VariantPtrHolder pVarResult = NULL; @@ -3121,7 +3122,7 @@ void IUInvokeDispMethod( { CorIfaceAttr ifaceType = pInvokedMT->GetComInterfaceType(); if (!IsDispatchBasedItf(ifaceType)) - COMPlusThrow(kTargetInvocationException, IDS_EE_INTERFACE_NOT_DISPATCH_BASED); + COMPlusThrow(kTargetException, W("TargetInvocation_InterfaceNotIDispatch")); } // Validate that the target is a COM object. @@ -3156,7 +3157,10 @@ void IUInvokeDispMethod( { // The invoked type is a dispatch or dual interface so we will make the // invocation on it. - pDisp = (IDispatch *)ComObject::GetComIPFromRCWThrowing(pTarget, pInvokedMT); + pUnk = ComObject::GetComIPFromRCWThrowing(pTarget, pInvokedMT); + hr = SafeQueryInterface(pUnk, IID_IDispatch, (IUnknown**)&pDisp); + if (FAILED(hr)) + COMPlusThrow(kTargetException, W("TargetInvocation_TargetDoesNotImplementIDispatch")); } else { @@ -3167,9 +3171,9 @@ void IUInvokeDispMethod( RCWPROTECT_BEGIN(pRCW, *pTarget); // Retrieve the IDispatch pointer from the wrapper. - pDisp = (IDispatch*)pRCW->GetIDispatch(); + pDisp = pRCW->GetIDispatch(); if (!pDisp) - COMPlusThrow(kTargetInvocationException, IDS_EE_NO_IDISPATCH_ON_TARGET); + COMPlusThrow(kTargetException, W("TargetInvocation_TargetDoesNotImplementIDispatch")); // If we aren't ignoring case, then we need to try and QI for IDispatchEx to // be able to use IDispatchEx::GetDispID() which has a flag to control case diff --git a/src/coreclr/vm/nativeimage.cpp b/src/coreclr/vm/nativeimage.cpp index 49f797f896254..d68d031673f4e 100644 --- a/src/coreclr/vm/nativeimage.cpp +++ b/src/coreclr/vm/nativeimage.cpp @@ -261,7 +261,7 @@ NativeImage *NativeImage::Open( #endif #ifndef DACCESS_COMPILE -Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid, DomainAssembly *pParentAssembly) +Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid, Assembly *pParentAssembly) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/vm/nativeimage.h b/src/coreclr/vm/nativeimage.h index afbc1e32cd0ac..722a8f1aa6168 100644 --- a/src/coreclr/vm/nativeimage.h +++ b/src/coreclr/vm/nativeimage.h @@ -124,7 +124,7 @@ class NativeImage PTR_Assembly *GetManifestMetadataAssemblyRefMap() { return m_pNativeMetadataAssemblyRefMap; } AssemblyBinder *GetAssemblyBinder() const { return m_pAssemblyBinder; } - Assembly *LoadManifestAssembly(uint32_t rowid, DomainAssembly *pParentAssembly); + Assembly *LoadManifestAssembly(uint32_t rowid, Assembly *pParentAssembly); PTR_READYTORUN_CORE_HEADER GetComponentAssemblyHeader(LPCUTF8 assemblySimpleName); diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index 0c17bcbaa9b0a..4b9df2e18275f 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -2115,7 +2115,7 @@ class LoaderAllocatorObject : public Object INT32 GetSlotsUsed(); void SetSlotsUsed(INT32 newSlotsUsed); #endif // DACCESS_COMPILE - + void SetNativeLoaderAllocator(LoaderAllocator * pLoaderAllocator) { LIMITED_METHOD_CONTRACT; @@ -2355,6 +2355,21 @@ class ExceptionObject : public Object void* _xptrs; INT32 _xcode; INT32 _HResult; + + template friend struct ::cdac_offsets; +}; + +template<> +struct cdac_offsets +{ + static constexpr size_t _message = offsetof(ExceptionObject, _message); + static constexpr size_t _innerException = offsetof(ExceptionObject, _innerException); + static constexpr size_t _stackTrace = offsetof(ExceptionObject, _stackTrace); + static constexpr size_t _watsonBuckets = offsetof(ExceptionObject, _watsonBuckets); + static constexpr size_t _stackTraceString = offsetof(ExceptionObject, _stackTraceString); + static constexpr size_t _remoteStackTraceString = offsetof(ExceptionObject, _remoteStackTraceString); + static constexpr size_t _HResult = offsetof(ExceptionObject, _HResult); + static constexpr size_t _xcode = offsetof(ExceptionObject, _xcode); }; // Defined in Contracts.cs diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp index d6b49ee14cff2..3f54dbff556af 100644 --- a/src/coreclr/vm/peassembly.cpp +++ b/src/coreclr/vm/peassembly.cpp @@ -497,16 +497,16 @@ PEAssembly* PEAssembly::LoadAssembly(mdAssemblyRef kAssemblyRef) AssemblySpec spec; - spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(this)); + spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(this)->GetAssembly()); RETURN GetAppDomain()->BindAssemblySpec(&spec, TRUE); } - +// dwLocation maps to System.Reflection.ResourceLocation BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, - PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef, + PBYTE *pbInMemoryResource, Assembly** pAssemblyRef, LPCSTR *szFileName, DWORD *dwLocation, - BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, AppDomain* pAppDomain) + Assembly* pAssembly) { CONTRACTL { @@ -523,7 +523,6 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, DWORD dwResourceFlags; DWORD dwOffset; mdManifestResource mdResource; - Assembly* pAssembly = NULL; PEAssembly* pPEAssembly = NULL; IMDInternalImport* pImport = GetMDImport(); if (SUCCEEDED(pImport->FindManifestResourceByName(szName, &mdResource))) @@ -538,16 +537,12 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, } else { - if (fSkipRaiseResolveEvent || pAppDomain == NULL) - return FALSE; - - DomainAssembly* pParentAssembly = GetAppDomain()->FindAssembly(this); - pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly, szName); + AppDomain* pAppDomain = AppDomain::GetCurrentDomain(); + DomainAssembly* pParentAssembly = pAppDomain->FindAssembly(this); + pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly->GetAssembly(), szName); if (pAssembly == NULL) return FALSE; - - pDomainAssembly = pAssembly->GetDomainAssembly(); - pPEAssembly = pDomainAssembly->GetPEAssembly(); + pPEAssembly = pAssembly->GetPEAssembly(); if (FAILED(pAssembly->GetMDImport()->FindManifestResourceByName( szName, @@ -559,11 +554,11 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, if (dwLocation != 0) { if (pAssemblyRef != NULL) - *pAssemblyRef = pDomainAssembly; + *pAssemblyRef = pAssembly; *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly } - IfFailThrow(pPEAssembly->GetMDImport()->GetManifestResourceProps( + IfFailThrow(pAssembly->GetMDImport()->GetManifestResourceProps( mdResource, NULL, //&szName, &mdLinkRef, @@ -575,27 +570,27 @@ BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource, switch(TypeFromToken(mdLinkRef)) { case mdtAssemblyRef: { - if (pDomainAssembly == NULL) + if (pAssembly == NULL) return FALSE; AssemblySpec spec; - spec.InitializeSpec(mdLinkRef, GetMDImport(), pDomainAssembly); - pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); + spec.InitializeSpec(mdLinkRef, GetMDImport(), pAssembly); + DomainAssembly* pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); if (dwLocation) { if (pAssemblyRef) - *pAssemblyRef = pDomainAssembly; + *pAssemblyRef = pDomainAssembly->GetAssembly(); *dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly } - return pDomainAssembly->GetResource(szName, - cbResource, - pbInMemoryResource, - pAssemblyRef, - szFileName, - dwLocation, - fSkipRaiseResolveEvent); + return GetResource(szName, + cbResource, + pbInMemoryResource, + pAssemblyRef, + szFileName, + dwLocation, + pDomainAssembly->GetAssembly()); } case mdtFile: diff --git a/src/coreclr/vm/peassembly.h b/src/coreclr/vm/peassembly.h index f30ce986cb372..d1f7500790d9b 100644 --- a/src/coreclr/vm/peassembly.h +++ b/src/coreclr/vm/peassembly.h @@ -204,10 +204,9 @@ class PEAssembly final void *GetVTable(RVA rva); BOOL GetResource(LPCSTR szName, DWORD *cbResource, - PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef, + PBYTE *pbInMemoryResource, Assembly** pAssemblyRef, LPCSTR *szFileName, DWORD *dwLocation, - BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, - AppDomain* pAppDomain); + Assembly* pAssembly); #ifndef DACCESS_COMPILE PTR_CVOID GetMetadata(COUNT_T *pSize); @@ -434,7 +433,6 @@ class PEAssembly final // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback // load context would be propagated to the assembly being dynamically generated. PTR_AssemblyBinder m_pFallbackBinder; - }; // class PEAssembly typedef ReleaseHolder PEAssemblyHolder; diff --git a/src/coreclr/vm/typeparse.cpp b/src/coreclr/vm/typeparse.cpp index 5a9947042928c..e66d3baef9d24 100644 --- a/src/coreclr/vm/typeparse.cpp +++ b/src/coreclr/vm/typeparse.cpp @@ -26,7 +26,7 @@ static TypeHandle GetTypeHelper(LPCWSTR szTypeName, Assembly* pRequestingAssembl if (pRequestingAssembly != NULL) { - objRequestingAssembly = pRequestingAssembly->GetDomainAssembly()->GetExposedAssemblyObject(); + objRequestingAssembly = pRequestingAssembly->GetExposedObject(); } OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); diff --git a/src/coreclr/vm/zapsig.cpp b/src/coreclr/vm/zapsig.cpp index 28216cb27d1b8..87d679e34b4d0 100644 --- a/src/coreclr/vm/zapsig.cpp +++ b/src/coreclr/vm/zapsig.cpp @@ -599,7 +599,7 @@ ModuleBase *ZapSig::DecodeModuleFromIndex(Module *fromModule, if(pAssembly == NULL) { - DomainAssembly *pParentAssembly = fromModule->GetDomainAssembly(); + Assembly *pParentAssembly = fromModule->GetAssembly(); if (nativeImage != NULL) { pAssembly = nativeImage->LoadManifestAssembly(index, pParentAssembly); diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index c86711beee406..88c93310bb1c9 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -573,6 +573,16 @@ internal static SecurityStatusPalErrorCode DoSslHandshake(SafeSslHandle context, throw handshakeException; } + // in case of TLS 1.3 post-handshake authentication, SslDoHandhaske + // may return SSL_ERROR_NONE while still expecting more data from + // the client. Attempts to send app data in this state would result + // in SSL_ERROR_WANT_READ from SslWrite, override the return status + // to continue waiting for the rest of the TLS frames + if (context.IsServer && token.Size == 0 && errorCode == Ssl.SslErrorCode.SSL_ERROR_NONE && Ssl.IsSslRenegotiatePending(context)) + { + return SecurityStatusPalErrorCode.ContinueNeeded; + } + bool stateOk = Ssl.IsSslStateOK(context); if (stateOk) { diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs index f504e175cfdc7..616fcfc9c1391 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs @@ -15,8 +15,8 @@ internal interface ISSPIInterface unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, Interop.SspiCli.SCHANNEL_CRED* authdata, out SafeFreeCredentials outCredential); unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, Interop.SspiCli.SCH_CREDENTIALS* authdata, out SafeFreeCredentials outCredential); int AcquireDefaultCredential(string moduleName, Interop.SspiCli.CredentialUse usage, out SafeFreeCredentials outCredential); - int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags); - int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags); + int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, ref InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags); + int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags); int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint qop); int DecryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, out uint qop); diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs index 2f24afa114b0b..3111a0c6b76b5 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs @@ -50,14 +50,14 @@ public unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.Cr return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, authdata, out outCredential); } - public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, ref InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { - return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outToken, ref outFlags); + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, ref inputBuffers, ref outToken, ref outFlags); } - public int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + public int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { - return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffers, ref outToken, ref outFlags); + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, ref inputBuffers, ref outToken, ref outFlags); } public int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint qop) diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs index 90e40a5dc0556..5744783264af9 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs @@ -49,14 +49,14 @@ public unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.Cr return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, authdata, out outCredential); } - public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, ref InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { - return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outToken, ref outFlags); + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, ref inputBuffers, ref outToken, ref outFlags); } - public int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + public int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { - return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffers, ref outToken, ref outFlags); + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, ref inputBuffers, ref outToken, ref outFlags); } public int EncryptMessage(SafeDeleteContext context, ref Interop.SspiCli.SecBufferDesc inputOutput, uint qop) diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs index b41a8b3ce20ea..93f92ac3897e0 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs @@ -141,22 +141,22 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface return outCredential; } - internal static int InitializeSecurityContext(ISSPIInterface secModule, ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + internal static int InitializeSecurityContext(ISSPIInterface secModule, ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, ref InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.InitializeSecurityContext(credential, context, targetName, inFlags); - int errorCode = secModule.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, datarep, inputBuffers, ref outToken, ref outFlags); + int errorCode = secModule.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, datarep, ref inputBuffers, ref outToken, ref outFlags); if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.SecurityContextInputBuffers(nameof(InitializeSecurityContext), inputBuffers.Count, outToken.Size, (Interop.SECURITY_STATUS)errorCode); return errorCode; } - internal static int AcceptSecurityContext(ISSPIInterface secModule, SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) + internal static int AcceptSecurityContext(ISSPIInterface secModule, SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, ref InputSecurityBuffers inputBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.AcceptSecurityContext(credential, context, inFlags); - int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, ref outToken, ref outFlags); + int errorCode = secModule.AcceptSecurityContext(credential, ref context, ref inputBuffers, inFlags, datarep, ref outToken, ref outFlags); if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.SecurityContextInputBuffers(nameof(AcceptSecurityContext), inputBuffers.Count, outToken.Size, (Interop.SECURITY_STATUS)errorCode); diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs index fb276985709ff..18d981174c713 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs @@ -364,7 +364,7 @@ internal static unsafe int InitializeSecurityContext( string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, - InputSecurityBuffers inSecBuffers, + ref InputSecurityBuffers inSecBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { @@ -503,60 +503,15 @@ internal static unsafe int InitializeSecurityContext( // In some cases schannel may not process all the given data. // and it will return them back as SECBUFFER_EXTRA, expecting caller to - // feed them in again. Since we don't have good way how to flow the input back, - // we will try it again as separate call and we will return combined output from first and second try. - // That makes processing of outBuffer somewhat complicated. + // feed them in again. Propagate this information back up. if (inSecBuffers.Count > 1 && inUnmanagedBuffer[1].BufferType == SecurityBufferType.SECBUFFER_EXTRA && inSecBuffers._item1.Type == SecurityBufferType.SECBUFFER_EMPTY) { - // OS function did not use all provided data and turned EMPTY to EXTRA - // https://learn.microsoft.com/windows/win32/secauthn/extra-buffers-returned-by-schannel + inSecBuffers._item1.Type = inUnmanagedBuffer[1].BufferType; - int leftover = inUnmanagedBuffer[1].cbBuffer; - int processed = inSecBuffers._item0.Token.Length - inUnmanagedBuffer[1].cbBuffer; - - /* skip over processed data and try it again. */ - inUnmanagedBuffer[0].cbBuffer = leftover; - inUnmanagedBuffer[0].pvBuffer = inUnmanagedBuffer[0].pvBuffer + processed; - inUnmanagedBuffer[1].BufferType = SecurityBufferType.SECBUFFER_EMPTY; - inUnmanagedBuffer[1].cbBuffer = 0; - - outUnmanagedBuffer.cbBuffer = 0; - - if (outoutBuffer != IntPtr.Zero) - { - Interop.SspiCli.FreeContextBuffer(outoutBuffer); - outoutBuffer = IntPtr.Zero; - } - - errorCode = MustRunInitializeSecurityContext( - ref inCredentials, - isContextAbsent, - (byte*)namePtr, - inFlags, - endianness, - &inSecurityBufferDescriptor, - refContext!, - ref outSecurityBufferDescriptor, - ref outFlags, - null); - - if (isSspiAllocated) - { - outoutBuffer = outUnmanagedBuffer.pvBuffer; - - if (outUnmanagedBuffer.cbBuffer > 0) - { - outToken.EnsureAvailableSpace(outUnmanagedBuffer.cbBuffer); - new Span((byte*)outUnmanagedBuffer.pvBuffer, outUnmanagedBuffer.cbBuffer).CopyTo(outToken.AvailableSpan); - outToken.Size += outUnmanagedBuffer.cbBuffer; - } - } - - if (inUnmanagedBuffer[1].BufferType == SecurityBufferType.SECBUFFER_EXTRA) - { - // we are left with unprocessed data again. fail with SEC_E_INCOMPLETE_MESSAGE hResult. - errorCode = unchecked((int)0x80090318); - } + // since SecurityBuffer type does not have separate Length field, + // we point to the unused portion of the input buffer. + Debug.Assert(inSecBuffers._item0.Token.Length > inUnmanagedBuffer[1].cbBuffer); + inSecBuffers._item1.Token = inSecBuffers._item0.Token.Slice(inSecBuffers._item0.Token.Length - inUnmanagedBuffer[1].cbBuffer); } } } @@ -676,7 +631,7 @@ internal static unsafe int AcceptSecurityContext( ref SafeDeleteSslContext? refContext, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, - InputSecurityBuffers inSecBuffers, + ref InputSecurityBuffers inSecBuffers, ref ProtocolToken outToken, ref Interop.SspiCli.ContextFlags outFlags) { @@ -807,51 +762,17 @@ internal static unsafe int AcceptSecurityContext( } outToken.Size = length; + // In some cases schannel may not process all the given data. + // and it will return them back as SECBUFFER_EXTRA, expecting caller to + // feed them in again. Propagate this information back up. if (inSecBuffers.Count > 1 && inUnmanagedBuffer[1].BufferType == SecurityBufferType.SECBUFFER_EXTRA && inSecBuffers._item1.Type == SecurityBufferType.SECBUFFER_EMPTY) { - // OS function did not use all provided data and turned EMPTY to EXTRA - // https://learn.microsoft.com/windows/win32/secauthn/extra-buffers-returned-by-schannel - - int leftover = inUnmanagedBuffer[1].cbBuffer; - int processed = inSecBuffers._item0.Token.Length - inUnmanagedBuffer[1].cbBuffer; - - /* skip over processed data and try it again. */ - inUnmanagedBuffer[0].cbBuffer = leftover; - inUnmanagedBuffer[0].pvBuffer = inUnmanagedBuffer[0].pvBuffer + processed; - inUnmanagedBuffer[1].BufferType = SecurityBufferType.SECBUFFER_EMPTY; - inUnmanagedBuffer[1].cbBuffer = 0; - - outUnmanagedBuffer[0].cbBuffer = 0; - if (isSspiAllocated && outUnmanagedBuffer[0].pvBuffer != IntPtr.Zero) - { - Interop.SspiCli.FreeContextBuffer(outUnmanagedBuffer[0].pvBuffer); - outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero; - } + inSecBuffers._item1.Type = inUnmanagedBuffer[1].BufferType; - errorCode = MustRunAcceptSecurityContext_SECURITY( - ref inCredentials, - isContextAbsent, - &inSecurityBufferDescriptor, - inFlags, - endianness, - refContext!, - ref outSecurityBufferDescriptor, - ref outFlags, - null); - - index = outUnmanagedBuffer[0].cbBuffer == 0 && outUnmanagedBuffer[1].cbBuffer > 0 ? 1 : 0; - if (outUnmanagedBuffer[index].cbBuffer > 0) - { - outToken.EnsureAvailableSpace(outUnmanagedBuffer[index].cbBuffer); - new Span((byte*)outUnmanagedBuffer[index].pvBuffer, outUnmanagedBuffer[index].cbBuffer).CopyTo(outToken.AvailableSpan); - outToken.Size += outUnmanagedBuffer[index].cbBuffer; - } - - if (inUnmanagedBuffer[1].BufferType == SecurityBufferType.SECBUFFER_EXTRA) - { - // we are left with unprocessed data again. fail with SEC_E_INCOMPLETE_MESSAGE hResult. - errorCode = unchecked((int)0x80090318); - } + // since SecurityBuffer type does not have separate Length field, + // we point to the unused portion of the input buffer. + Debug.Assert(inSecBuffers._item0.Token.Length > inUnmanagedBuffer[1].cbBuffer); + inSecBuffers._item1.Token = inSecBuffers._item0.Token.Slice(inSecBuffers._item0.Token.Length - inUnmanagedBuffer[1].cbBuffer); } } } diff --git a/src/libraries/Common/src/System/Net/Security/SecurityBuffer.Windows.cs b/src/libraries/Common/src/System/Net/Security/SecurityBuffer.Windows.cs index 1866eae805fde..d1e35fbb39e1e 100644 --- a/src/libraries/Common/src/System/Net/Security/SecurityBuffer.Windows.cs +++ b/src/libraries/Common/src/System/Net/Security/SecurityBuffer.Windows.cs @@ -36,11 +36,11 @@ internal void SetNextBuffer(InputSecurityBuffer buffer) } [StructLayout(LayoutKind.Auto)] - internal readonly ref struct InputSecurityBuffer + internal ref struct InputSecurityBuffer { - public readonly SecurityBufferType Type; - public readonly ReadOnlySpan Token; - public readonly SafeHandle? UnmanagedToken; + public SecurityBufferType Type; + public ReadOnlySpan Token; + public SafeHandle? UnmanagedToken; public InputSecurityBuffer(ReadOnlySpan data, SecurityBufferType tokentype) { diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/config.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/config.ps1 deleted file mode 100644 index 6a07fe355a53d..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/config.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -# -# Libraries - Net configuration -# - -# -- Machine Information - -# You can find the host name by logging on to the target machine and typing "hostname" in a cmd console. -# You can find the IP address by logging on to the target machine and typing "ipconfig" in a cmd console. -# Requirements: -# - The machines below should be within the same LAN network. -# - All machines must have Powershell >3.0 installed. - -# IMPORTANT: -# The state for the following machines will be changed irreversably. -# The uninstall step will remove the installed components regardless if it existed before the deployment or -# was altered/customized after deployment. -# - -# A Windows Server SKU hosting Active Directory services. This machine will become the Domain Controller: -$LIBRARIES_NET_AD_MACHINE = "" #Example: "TESTAD" -$LIBRARIES_NET_AD_MACHINEIP = "" #Example: "192.168.0.1" - must be a Static IPv4 address. - -# A Windows Client or Server SKU hosting the IIS Server. This machine will be joined to the Domain. -$LIBRARIES_NET_IISSERVER_MACHINE = "" #Example: "TESTIIS" -$LIBRARIES_NET_IISSERVER_MACHINEIP = "" #Example: "192.168.0.1" - must be a Static IPv4 address. - -# A Windows Client or Server SKU hosting the runtime repo. This machine will be joined to the Domain. -$LIBRARIES_NET_CLIENT_MACHINE = "" #Example: "TESTCLIENT" - -# -- Test Parameters - -# For security reasons, it's advisable that the default username/password pairs below are changed regularly. - -$script:domainName = "corp.contoso.com" -$script:domainNetbios = "libraries-net-ad" - -$script:domainUserName = "testaduser" -$script:domainUserPassword = "Test-ADPassword" - -$script:basicUserName = "testbasic" -$script:basicUserPassword = "Test-Basic" - -# Changing the IISServer FQDN may require changing certificates. -$script:iisServerFQDN = "testserver.contoso.com" - -$script:PreRebootRoles = @( - @{Name = "LIBRARIES_NET_AD_CLIENT"; Script = "setup_activedirectory_client.ps1"; MachineName = $LIBRARIES_NET_IISSERVER_MACHINE}, - @{Name = "LIBRARIES_NET_AD_CLIENT"; Script = "setup_activedirectory_client.ps1"; MachineName = $LIBRARIES_NET_CLIENT_MACHINE}, - @{Name = "LIBRARIES_NET_AD_DC"; Script = "setup_activedirectory_domaincontroller.ps1"; MachineName = $LIBRARIES_NET_AD_MACHINE; MachineIP = $LIBRARIES_NET_AD_MACHINEIP} -) - -$script:Roles = @( - @{Name = "LIBRARIES_NET_IISSERVER"; Script = "setup_iisserver.ps1"; MachineName = $LIBRARIES_NET_IISSERVER_MACHINE; MachineIP = $LIBRARIES_NET_IISSERVER_MACHINEIP}, - @{Name = "LIBRARIES_NET_CLIENT"; Script = "setup_client.ps1"; MachineName = $LIBRARIES_NET_CLIENT_MACHINE}, - @{Name = "LIBRARIES_NET_AD_DC"; Script = "setup_activedirectory_domaincontroller.ps1"; MachineName = $LIBRARIES_NET_AD_MACHINE; MachineIP = $LIBRARIES_NET_AD_MACHINEIP} -) diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup.ps1 deleted file mode 100644 index 26544c6ba0ae0..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup.ps1 +++ /dev/null @@ -1,225 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -Param ( - [switch] $uninstall=$false -) - -# Import configuration. -. .\setup_common.ps1 - -Function TestMachineStatus($role) -{ - try - { - $status = Invoke-Command -ComputerName $role.MachineName -ArgumentList $role.Name -ErrorAction Stop { [Environment]::GetEnvironmentVariable($args[0], "Machine") } - - $role.Reachable = $true - if ($status -eq "Installed") - { - $role.Installed = $true - } - else - { - if (-not [string]::IsNullOrWhiteSpace($status)) - { - Write-Warning "Role $($role.Name) found to have status of: $status." - Write-Warning "The script will try to resume the installation. To manually resume installation, manually run the $($role.Script) on $($role.MachineName) as Administrator." - } - } - } - catch [System.Exception] - { - $role.Reachable = $false - } -} - -Function CheckRoles -{ - Write-Host "Verifying server applications:" - $iisApplications = GetIISCodePath - if (-not (Test-Path (Join-Path $iisApplications "index.html"))) - { - throw "Cannot find index.html within the $iisApplications path. Make sure that you have built and copied the Server code before running this script." - } - - Write-Host "Verifying roles:" - foreach ($role in ($script:Roles + $script:PreRebootRoles)) - { - Write-Host -ForegroundColor DarkGray "`t" $role.Name - if (-not (Test-Path $role.Script)) - { - throw "Cannot find installation script for $($role.Name): $($role.Script)" - } - - if ([string]::IsNullOrWhiteSpace($role.MachineName)) - { - throw "Please edit config.ps1 and set a valid value name for $($role.Name)_Machine." - } - - TestMachineStatus $role - } - - Write-Host "OK." -} - -Function EnsurePreRebootForCurrentMachine -{ - $machineInfo = Get-WmiObject win32_computersystem - $currentRole = GetPreRebootRoleForMachine($Env:COMPUTERNAME) - - if (($machineInfo.PartOfDomain -eq $true) -and ` - ($machineInfo.Domain -eq $script:domainName) -and ` - ($currentRole.Installed -eq $true)) - { - return $true - } - elseif (($machineInfo.PartOfDomain -eq $true) -and ` - ($machineInfo.Domain -ne $script:domainName)) - { - Write-Error "The current machine is already joiend to the $($machineInfo.Domain) domain." - Write-Error "Either change config.ps1 to use the correct domain information, select a different machine or remove the machine from the current domain." - throw "Cannot use the current machine: already joined to a domain." - } - - & (".\" + $currentRole.Script) -} - -Function CreateDestinationPath($s) -{ - return Invoke-Command -Session $s ` - { - $destPath = Join-Path $env:SystemDrive "LIBRARIES_NET_SCRIPTS" - mkdir $destPath -ErrorAction SilentlyContinue | Out-Null - return $destPath - } -} - -Function CopyScripts($s, $remotePath) -{ - Copy-Item -Recurse -Force -Path ".\*" -Destination $remotePath -ToSession $s -ErrorAction Stop -} - -Function InstallRoles -{ - Write-Host -ForegroundColor Cyan "Remotely installing all roles." - - foreach ($role in $script:Roles) - { - Write-Host -ForegroundColor DarkCyan "Installing role [$($role.Name)]: $($role.MachineName)" - - Write-Host -ForegroundColor DarkGray "`tConnecting" - $s = New-PSSession -ComputerName $role.MachineName - - Write-Host -ForegroundColor DarkGray "`tCopying scripts" - # Copy scripts - $remotePath = CreateDestinationPath $s - CopyScripts $s $remotePath - - Write-Host -ForegroundColor DarkGray "`tInstalling" - # Run remote scripts - Invoke-Command -Session $s -ArgumentList $remotePath, $role.Script ` - { - $path = $args[0] - $script = $args[1] - - cd $path - & (".\" + $script) - } - - Write-Host -ForegroundColor DarkCyan "Role [$($role.Name)]: $($role.MachineName) installation complete." - Write-Host - Write-Host - } -} - -Function Install -{ - Write-Host -ForegroundColor Cyan "Install/Update Libraries Networking multi-machine prerequisites" - Write-Host - CheckRoles - - EnsurePreRebootForCurrentMachine - - if (($script:Roles | where {$_.Reachable -ne $true}).Count -ne 0) - { - Write-Warning "Not all roles are reachable from this host." - Write-Host "- If all machines are joined to the Domain, make sure you are logged on as $($script:domainNetbios)\Administrator and not as a local Administrator." - Write-Host "- If not all machines are joined to the Domain: Log-on to the following machines, copy all scripts and run .\setup.ps1 as Administrator:" - $script:Roles | where {$_.Reachable -ne $true} - Write-Host -ForegroundColor Cyan "Rerun this command after all machines have been started and joined to the $($script:domainNetBios) domain." - return - } - - InstallRoles - - Write-Host -ForegroundColor Cyan "Role installation complete." -} - -Function UnistallMachines -{ - Write-Host -ForegroundColor Cyan "Remotely uninstalling roles." - - foreach ($role in $script:Roles) - { - Write-Host -ForegroundColor DarkCyan "Uninstalling role [$($role.Name)]: $($role.MachineName)" - - Write-Host -ForegroundColor DarkGray "`tConnecting" - $s = New-PSSession -ComputerName $role.MachineName - - Write-Host -ForegroundColor DarkGray "`tCopying scripts" - # Copy scripts - $remotePath = CreateDestinationPath $s - CopyScripts $s $remotePath - - $preRebootRole = GetPreRebootRoleForMachine $role.MachineName - - Write-Host -ForegroundColor DarkGray "`tUninstalling" - # Run remote scripts - Invoke-Command -Session $s -ArgumentList $remotePath, $role.Script, $preRebootRole.Script ` - { - $path = $args[0] - $script = $args[1] - $preRebootScript = $args[2] - - cd $path - & (".\" + $script) -uninstall - & (".\" + $preRebootScript) -uninstall - } - - Write-Host -ForegroundColor DarkCyan "Role [$($role.Name)]: $($role.MachineName) uninstall complete." - Write-Host - Write-Host - } -} - -Function Uninstall -{ - Write-Host -ForegroundColor Cyan "Uninstall Libraries Networking multi-machine prerequisites" - Write-Host - CheckRoles - Write-Host - - Write-Warning "Some of the installed components may have existed before or got changes outside of this setup script." - Write-Warning "The scripts will attempt to remove all components regardless of these changes." - $continue = Read-Host "Do you want to continue? [Y/N]" - - if ($continue.ToUpper() -ne "Y") - { - Write-Warning "Aborted by user." - return - } - - UnistallMachines -} - -if ($uninstall) -{ - Uninstall -} -else -{ - Install -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_client.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_client.ps1 deleted file mode 100644 index 7a7df93b18517..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_client.ps1 +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -# -# Run this script on all Active Directory client machines. -# Tested on Windows 2016 TP5 and Windows 10. -# -Param ( - [switch] $uninstall=$false -) - -# Imports: -. .\setup_common.ps1 - -$script:LIBRARIES_ROLE_NAME = "LIBRARIES_NET_AD_CLIENT" - -Function ConfigureDNS -{ - Write-Host -ForegroundColor Cyan "Configuring DNS" - - $dcRole = GetRole "LIBRARIES_NET_AD_DC" - - if (-not (Test-Connection $dcRole.MachineIP)) - { - throw "The local machine cannot ping the Domain Controller/DNS Server at $($dcRole.MachineIP).`n" + ` - "Ensure that the setup was completed on the machine then try re-running the script on this machine again." - } - - $ipv4DnsInterfaces = Get-DnsClientServerAddress | where {($_.AddressFamily -eq 2) -and ($_.InterfaceAlias -eq "Ethernet")} - if ($ipv4DnsInterfaces.Count -eq 0) - { - throw "The setup script cannot find a network adapter named 'Ethernet' that has IPv4 configured." - } - - $ifIndex = $ipv4DnsInterfaces[0].InterfaceIndex - - Set-DnsClientServerAddress -InterfaceIndex $ifIndex -ServerAddresses ($dcRole.MachineIP) -} - -Function EnableAD -{ - Write-Host -ForegroundColor Cyan "Adding computer to domain. Please use the domain administrator password for the $($script:domainNetbios) domain." - Add-Computer -DomainName $script:domainNetbios -} - -Function Install -{ - Write-Host -ForegroundColor Cyan "Installing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)" - - CheckPreRebootMachineInfo - ConfigureDNS - EnableAD - Enable-PSRemoting - EnvironmentSetRebootPendingRoleStatus - Write-Host -ForegroundColor Cyan "Please re-start one instance of the script on any of the machines after reboot to resume the installation." - Read-Host "[Press ENTER to reboot.]" - Restart-Computer - EnvironmentSetInstalledRoleStatus -} - -Function Uninstall -{ - Write-Host -ForegroundColor Cyan "Removing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)." - - EnvironmentCheckUninstallRoleStatus - - Remove-Computer - EnvironmentRemoveRoleStatus - - Write-Warning "Current DNS configuration:" - Get-DnsClientServerAddress - Write-Warning "To complete the uninstallation, you may need to change the DNS client address configuration." - Read-Host "[Press ENTER to reboot.]" - Restart-Computer -} - -if ($uninstall) -{ - Uninstall -} -else -{ - Install -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_domaincontroller.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_domaincontroller.ps1 deleted file mode 100644 index 2687ea5fb27b1..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_activedirectory_domaincontroller.ps1 +++ /dev/null @@ -1,94 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -# -# Run this script on the Active Directory Domain Controller machine. -# Tested on Windows 2016 TP5 -# - -Param ( - [switch] $uninstall=$false -) - -# Import configuration. -. .\setup_common.ps1 - -$script:LIBRARIES_ROLE_NAME = "LIBRARIES_NET_AD_DC" - -Function EnableAD -{ - Write-Host -ForegroundColor Cyan "Installing Active Directory." - CheckPreRebootMachineInfo - - # From https://technet.microsoft.com/en-us/library/hh472162.aspx - Install-Windowsfeature -name AD-Domain-Services -IncludeManagementTools - - # Will prompt for SafeModeAdministratorPassword: - Install-ADDSForest -domainname $script:domainName -DomainNetbiosName $script:domainNetbios -NoRebootOnCompletion -} - -Function AddUser -{ - Write-Host -ForegroundColor Cyan "Creating domain user." - Remove-ADUser $script:domainUserName -Confirm:$false -ErrorAction SilentlyContinue | Out-Null - New-ADUser $script:domainUserName -Enabled $true -PasswordNeverExpires $true -AccountPassword (ConvertTo-SecureString $script:domainUserPassword -AsPlainText -force) -} - -Function ConfigureDNS -{ - Write-Host -ForegroundColor Cyan "Configuring DNS." - - $iisServer = GetRole "LIBRARIES_NET_IISSERVER" - - $serverName = ($script:iisServerFQDN).Split('.')[0]; - $zoneName = ($script:iisServerFQDN).Substring($serverName.Length + 1) - - Remove-DnsServerZone -Name $zoneName -Force -ErrorAction SilentlyContinue | Out-Null - Add-DnsServerPrimaryZone -Name $zoneName -ReplicationScope "Forest" - Add-DnsServerResourceRecordA -Name $serverName -ZoneName $zoneName -AllowUpdateAny -IPv4Address $iisServer.MachineIP -TimeToLive 01:00:00 -} - -Function Install -{ - Write-Host -ForegroundColor Cyan "Installing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)." - - if ((-not (EnvironmentIsRoleInstalled)) -and (-not (EnvironmentIsRoleRebootPending))) - { - EnableAD - EnvironmentSetRebootPendingRoleStatus - Write-Host -ForegroundColor Cyan "Please re-start the script after the machine reboots." - Read-Host "[Press ENTER to reboot.]" - Restart-Computer - } - else - { - AddUser - ConfigureDNS - Enable-PSRemoting - EnvironmentSetInstalledRoleStatus - Write-Host -ForegroundColor Cyan "Prerequisites installed for $($script:LIBRARIES_ROLE_NAME)." - Write-Host - } -} - -Function Uninstall -{ - Write-Host -ForegroundColor Cyan "Removing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)." - - EnvironmentCheckUninstallRoleStatus - EnvironmentRemoveRoleStatus - - # Will reboot. - Uninstall-ADDSDomainController -LastDomainControllerInDomain -RemoveApplicationPartitions -IgnoreLastDNSServerForZone -} - -if ($uninstall) -{ - Uninstall -} -else -{ - Install -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_certificates.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_certificates.ps1 deleted file mode 100644 index 3a52a66720e43..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_certificates.ps1 +++ /dev/null @@ -1,128 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -# Certificate configuration - -$script:testDataUri = "https://github.com/dotnet/runtime-assets/archive/main.zip" -$script:testData = "runtime-assets" -$script:certificatePath = "$($script:testData)\src\System.Net.TestData\TestDataCertificates" - -$script:clientPrivateKeyPath = Join-Path $script:certificatePath "testclient1_at_contoso.com.pfx" -$script:clientPrivateKeyPassword = "PLACEHOLDER" - -$script:serverPrivateKeyPath = Join-Path $script:certificatePath "contoso.com.pfx" -$script:serverPrivateKeyPassword = "PLACEHOLDER" - -Function GetFullPath($relativePath) -{ - return (Get-Item $relativePath).FullName -} - -Function DeleteTestData -{ - if (Test-Path $script:testData) - { - rmdir $script:testData -Recurse -Force - } - - del ($testData + ".zip") -ErrorAction SilentlyContinue -} - -Function DownloadTestData -{ - DeleteTestData - DownloadFile $script:testDataUri ($testData + ".zip") - Expand-Archive ($testData + ".zip") -} - -Function LoadCertificateAndRoot($fileName, $password) -{ - $privateCerts = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection - $fullPath = GetFullPath $fileName - - $privateCerts.Import($fullPath, $password, ("MachineKeySet", "PersistKeySet", "Exportable")) - - $privateKeyCert = $null - foreach ($cert in $privateCerts) - { - if ($privateKeyCert -eq $null -and $cert.HasPrivateKey) - { - $privateKeyCert = $cert - } - } - - $rootCACert = $privateCerts | where {$_.Subject -eq $privateKeyCert.Issuer} - - return ($privateKeyCert, $rootCACert) -} - -Function AddCertificateToStore($certificate, $storeName, $storeLocation) -{ - $rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store($storeName, $storeLocation) - $rootStore.Open("ReadWrite") - $rootStore.Add($certificate) - $rootStore.Close() -} - -Function InstallCertificates($fileName, $password) -{ - Write-Host "Acquiring test data." - DownloadTestData - - Write-Host "Adding certificates" - ($private, $root) = LoadCertificateAndRoot $fileName $password - - Write-Host -ForegroundColor DarkGray "`tAdding root certificate: $($root.Subject)" - AddCertificateToStore $root "Root" "LocalMachine" - - Write-Host -ForegroundColor DarkGray "`tAdding private key certificate: $($private.Subject)" - AddCertificateToStore $private "My" "LocalMachine" - - Write-Host "Removing temporary files" - DeleteTestData -} - -Function InstallClientCertificates -{ - Write-Host -ForegroundColor Cyan "Installing Client Certificates" - InstallCertificates $script:clientPrivateKeyPath $script:clientPrivateKeyPassword -} - -Function InstallServerCertificates -{ - Write-Host -ForegroundColor Cyan "Installing Server Certificates" - InstallCertificates $script:serverPrivateKeyPath $script:serverPrivateKeyPassword -} - -Function GetServerCertificate -{ - return dir Cert:\LocalMachine\My | where { $_.DnsNameList | where{$_.Punycode -eq $script:iisServerFQDN} } -} - -Function RemoveCertificates($filename, $password) -{ - Write-Host "Acquiring test data." - DownloadTestData - ($private, $root) = LoadCertificateAndRoot $fileName $password - - Write-Host -ForegroundColor DarkGray "`tRemoving root certificate: $($root.Subject)" - dir Cert:\LocalMachine\Root | where {$_.Subject -eq $root.Subject} | foreach { rm (Join-Path Cert:\LocalMachine\Root $_.Thumbprint) } - Write-Host -ForegroundColor DarkGray "`tRemoving private key certificate: $($private.Subject)" - dir Cert:\LocalMachine\My | where {$_.Subject -eq $private.Subject} | foreach { rm (Join-Path Cert:\LocalMachine\My $_.Thumbprint) -DeleteKey } - - DeleteTestData -} - -Function RemoveClientCertificates -{ - Write-Host -ForegroundColor Cyan "Removing Client Certificates" - RemoveCertificates $script:clientPrivateKeyPath $script:clientPrivateKeyPassword -} - -Function RemoveServerCertificates -{ - Write-Host -ForegroundColor Cyan "Removing Server Certificates" - RemoveCertificates $script:serverPrivateKeyPath $script:serverPrivateKeyPassword -} \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_client.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_client.ps1 deleted file mode 100644 index d605ca59ab287..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_client.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -Param ( - [switch] $uninstall=$false -) - -# Imports: -. .\setup_common.ps1 -. .\setup_certificates.ps1 - -$script:LIBRARIES_ROLE_NAME = "LIBRARIES_NET_CLIENT" - -Function InstallClientEnvironmentConfiguration -{ - Write-Host -ForegroundColor Cyan "Installing client configuration." - - foreach ($configEntry in $script:ClientConfiguration) - { - [Environment]::SetEnvironmentVariable($configEntry.Name, $configEntry.Value, "Machine") - } -} - -Function UninstallClientEnvironmentConfiguration -{ - Write-Host -ForegroundColor Cyan "Removing client configuration." - - foreach ($configEntry in $script:ClientConfiguration) - { - [Environment]::SetEnvironmentVariable($configEntry.Name, $null, "Machine") - } -} - -Function Install -{ - Write-Host -ForegroundColor Cyan "Installing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)." - CheckMachineInfo - - InstallClientCertificates - InstallClientEnvironmentConfiguration - - EnvironmentSetInstalledRoleStatus -} - -Function Uninstall -{ - Write-Host -ForegroundColor Cyan "Removing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)." - EnvironmentCheckUninstallRoleStatus - - RemoveClientCertificates - UninstallClientEnvironmentConfiguration - - EnvironmentRemoveRoleStatus -} - -if ($uninstall) -{ - Uninstall -} -else -{ - Install -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_common.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_common.ps1 deleted file mode 100644 index 995b931581567..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_common.ps1 +++ /dev/null @@ -1,149 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -. .\config.ps1 - -# The following variable names should match the ones read by Configuration.*.cs code. -$script:ClientConfiguration = @( - - # Configuration.Http: - @{Name = "DOTNET_TEST_HTTPHOST"; Value = $script:iisServerFQDN}, - @{Name = "DOTNET_TEST_SECUREHTTPHOST"; Value = $script:iisServerFQDN}, - @{Name = "DOTNET_TEST_HTTP2HOST"; Value = $script:iisServerFQDN}, # Requires Windows 10 and above. - @{Name = "DOTNET_TEST_DOMAINJOINED_HTTPHOST"; Value = $script:iisServerFQDN}, - @{Name = "DOTNET_TEST_DOMAINJOINED_PROXYHOST"; Value = $null}, - @{Name = "DOTNET_TEST_DOMAINJOINED_PROXYPORT"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_SSL2"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_SSL3"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_TLS10"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_TLS11"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_TLS12"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_EXPIREDCERT"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_WRONGHOSTNAME"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_SELFSIGNEDCERT"; Value = $null}, - @{Name = "DOTNET_TEST_HTTPHOST_REVOKEDCERT"; Value = $null}, - @{Name = "DOTNET_TEST_STRESS_HTTP"; Value = "1"}, - - # Configuration.WebSockets: - @{Name = "DOTNET_TEST_WEBSOCKETHOST"; Value = $script:iisServerFQDN}, - @{Name = "DOTNET_TEST_SECUREWEBSOCKETHOST"; Value = $script:iisServerFQDN}, - - # Configuration.Security: - @{Name = "DOTNET_TEST_NET_AD_DOMAINNAME"; Value = $script:domainNetbios}, - @{Name = "DOTNET_TEST_NET_AD_USERNAME"; Value = $script:domainUserName}, - @{Name = "DOTNET_TEST_NET_AD_PASSWORD"; Value = $script:domainUserPassword}, - @{Name = "DOTNET_TEST_NET_SECURITY_NEGOSERVERURI"; Value = "http://$($script:iisServerFQDN)"}, - @{Name = "DOTNET_TEST_NET_SECURITY_TLSSERVERURI"; Value = "https://$($script:iisServerFQDN)"}, - - @{Name = "DOTNET_TEST_NET_SOCKETS_SERVERURI"; Value = "http://$($script:iisServerFQDN)"} -) - -Function GetRoleForMachine($machineName) -{ - return $script:Roles | where {$_.MachineName.ToUpper() -eq $machineName.ToUpper()} -} - -Function GetPreRebootRoleForMachine($machineName) -{ - return $script:PreRebootRoles | where {$_.MachineName.ToUpper() -eq $machineName.ToUpper()} -} - -Function GetRole($roleName) -{ - return $script:Roles | where {$_.Name.ToUpper() -eq $roleName.ToUpper()} -} - -Function CheckPreRebootMachineInfo -{ - $role = GetPreRebootRoleForMachine $Env:COMPUTERNAME - - if ($role.Name -ne $script:DOTNET_TEST_ROLE_NAME) - { - throw "This script needs to run on machines part of the $($role.Name) role." - } - - if ((-not [string]::IsNullOrWhiteSpace($role.MachineIP)) -and ((Get-NetIPAddress | where {$_.IPAddress -eq $role.MachineIP}).Count -eq 0)) - { - throw "The current machine doesn't have the expected Static IP address: $($role.MachineIP)" - } -} - -Function CheckMachineInfo -{ - $role = GetRoleForMachine $Env:COMPUTERNAME - - if ($role.Name -ne $script:DOTNET_TEST_ROLE_NAME) - { - throw "This script needs to run on machines part of the $($role.Name) role." - } - - if ((-not [string]::IsNullOrWhiteSpace($role.MachineIP)) -and ((Get-NetIPAddress | where {$_.IPAddress -eq $role.MachineIP}).Count -eq 0)) - { - throw "The current machine doesn't have the expected Static IP address: $($role.MachineIP)" - } -} - -Function EnvironmentAddRoleStatus($status) -{ - [Environment]::SetEnvironmentVariable($script:DOTNET_TEST_ROLE_NAME, $status, "Machine") -} - -Function EnvironmentSetInstalledRoleStatus -{ - EnvironmentAddRoleStatus "Installed" -} - -Function EnvironmentSetRebootPendingRoleStatus -{ - EnvironmentAddRoleStatus "PendingReboot" -} - -Function EnvironmentRemoveRoleStatus -{ - [Environment]::SetEnvironmentVariable($script:DOTNET_TEST_ROLE_NAME, $null, "Machine") -} - -Function EnvironmentCheckUninstallRoleStatus -{ - if ([Environment]::GetEnvironmentVariable($script:DOTNET_TEST_ROLE_NAME, "Machine") -ne "Installed") - { - Write-Warning "The machine doesn't appear to be in the $($script:DOTNET_TEST_ROLE_NAME) role." - $continue = Read-Host "Do you want to continue? [Y/N]" - if ($continue.ToUpper() -ne "Y") - { - Write-Warning "Aborted by user." - exit - } - } -} - -Function EnvironmentIsRoleRebootPending -{ - return [Environment]::GetEnvironmentVariable($script:DOTNET_TEST_ROLE_NAME, "Machine") -eq "PendingReboot" -} - -Function EnvironmentIsRoleInstalled -{ - return [Environment]::GetEnvironmentVariable($script:DOTNET_TEST_ROLE_NAME, "Machine") -eq "Installed" -} - -Function DownloadFile($source, $destination) -{ - # BITS remoting doesn't work on systems <= TH2. - if ([System.Environment]::OSVersion.Version -gt (new-object 'Version' 10,0,10586,0)) - { - Start-BitsTransfer -Source $source -Destination $destination - } - else - { - # BUG: taking very long: Invoke-WebRequest $source -OutFile $destination - $fqDestination = Join-Path (pwd) $destination - $wc = New-Object System.Net.WebClient - $wc.Downloadfile($source, $fqDestination.ToString()) - } -} - -Function GetIISCodePath -{ - return ".\IISApplications" -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_firewall.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_firewall.ps1 deleted file mode 100644 index a1db4f5fad21e..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_firewall.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -# Firewall configuration -$script:firewallGroup = "Libraries Testing" -$script:firewallRules = @( - @{Name = "LibrariesNet - HTTP 80"; Port = 80}, - @{Name = "LibrariesNet - HTTP 443"; Port = 443} -) - -Function InstallServerFirewall -{ - Write-Host -ForegroundColor Cyan "Installing Firewall rules." - foreach ($rule in $script:firewallRules) - { - Write-Host -ForegroundColor DarkGray "`t" $rule.Name - New-NetFirewallRule -DisplayName $rule.Name -Group $script:firewallGroup -Direction Inbound -Protocol TCP -LocalPort $rule.Port -Action Allow | Out-Null - } -} - -Function RemoveServerFirewall -{ - Write-Host -ForegroundColor Cyan "Removing Firewall rules." - foreach ($rule in $script:firewallRules) - { - Write-Host -ForegroundColor DarkGray "`t" $rule.Name - Remove-NetFirewallRule -DisplayName $rule.Name | Out-Null - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_iisserver.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_iisserver.ps1 deleted file mode 100644 index 07a4dcbb4011f..0000000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Deployment/setup_iisserver.ps1 +++ /dev/null @@ -1,199 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -#Requires -RunAsAdministrator - -# -# Run this script on the IIS server machine. -# Tested on Windows 2016 TP5 -# - -Param ( - [switch] $uninstall=$false -) - -# Imports: -. .\setup_common.ps1 -. .\setup_certificates.ps1 -. .\setup_firewall.ps1 - -# Server application configuration -$script:iisWwwRoot = "$env:systemdrive\inetpub\wwwroot" -$script:defaultWebSite = "Default Web Site" - -$script:webApps = @( - @{Name = "NoAuth"; - IISRelativePath = ""; - SourceRelativePath = ".\"; - - Configuration = @() - }, - - @{Name = "BasicAuth"; - IISRelativePath = "BasicAuth"; - SourceRelativePath = "\"; - Configuration = @( - @{ Path = "/system.webServer/security/authentication/anonymousAuthentication"; Name = "Enabled"; Value = "False" } - @{ Path = "/system.webServer/security/authentication/basicAuthentication"; Name = "Enabled"; Value = "True" } - ); - UserAccess = @( $script:basicUserName ) - }, - - @{Name = "DigestAuth"; - IISRelativePath = "DigestAuth"; - SourceRelativePath = "\"; - Configuration = @( - @{ Path = "/system.webServer/security/authentication/anonymousAuthentication"; Name = "Enabled"; Value = "False" } - @{ Path = "/system.webServer/security/authentication/digestAuthentication"; Name = "Enabled"; Value = "True" } - ); - UserAccess = @( $script:basicUserName ) - }, - - @{Name = "WindowsAuth"; - IISRelativePath = "WindowsAuth"; - SourceRelativePath = "\"; - Configuration = @( - @{ Path = "/system.webServer/security/authentication/anonymousAuthentication"; Name = "Enabled"; Value = "False" } - @{ Path = "/system.webServer/security/authentication/windowsAuthentication"; Name = "Enabled"; Value = "True" } - ); - UserAccess = @( "$($script:domainNetbios)\$($script:domainUserName)" ) - } -) - -$script:LIBRARIES_ROLE_NAME = "LIBRARIES_NET_IISSERVER" - -Function InstallIIS -{ - Write-Host -ForegroundColor Cyan "Installing IIS components." - Install-WindowsFeature -Name Web-Server,Web-Basic-Auth,Web-Digest-Auth,Web-Windows-Auth,Web-Cert-Auth,Web-Asp-Net45,Web-WebSockets -IncludeManagementTools -ErrorAction Stop | Out-Null -} - -Function RemoveIIS -{ - Write-Host -ForegroundColor Cyan "Removing IIS components." - Uninstall-WindowsFeature -Name Web-Server -IncludeManagementTools -} - -Function CreateLocalUser -{ - # A local user is required to allow Basic and Digest authentication. (WDigest not supported.) - Write-Host -ForegroundColor Cyan "Creating local user account." - Remove-LocalUser $script:basicUserName -Confirm:$false -ErrorAction SilentlyContinue - New-LocalUser $script:basicUserName -PasswordNeverExpires -Password (ConvertTo-SecureString $script:basicUserPassword -AsPlainText -force) | Out-Null -} - -Function RemoveLocalUser -{ - Write-Host -ForegroundColor Cyan "Removing local user account." - Remove-LocalUser $script:basicUserName -Confirm:$false -} - -Function ConfigureWebSites -{ - Write-Host -ForegroundColor Cyan "Configuring IIS websites." - - # SSL Bindings - $sslCert = GetServerCertificate - - Get-WebBinding -Port 443 -Name $script:defaultWebSite | Remove-WebBinding - New-WebBinding -Name $script:defaultWebSite -Protocol https -Port 443 - - Remove-Item -Path "IIS:\SslBindings\*" - New-Item -Path "IIS:\SslBindings\0.0.0.0!443" -Value $sslCert -Force | Out-Null -} - -Function GrantUserAccess($path, $userAccess) -{ - foreach ($user in $userAccess) - { - $acl = Get-Acl $path - $ar = New-Object System.Security.AccessControl.FileSystemAccessRule($user, "ReadAndExecute", "Allow") - $acl.SetAccessRule($ar) - Set-Acl $path $acl - } -} - -Function InstallServerCode -{ - Write-Host -ForegroundColor Cyan "Installing applications." - $serverCodeRootPath = GetIISCodePath - - foreach ($app in $script:webApps) - { - Write-Host -ForegroundColor DarkGray "`tInstalling webApp: $($app.Name)" - - $appPath = Join-Path $script:iisWwwRoot $app.IISRelativePath - - if ($(Get-WebApplication $app.Name) -ne $null) - { - Write-Host "`tRemoving $($app.Name)" - Remove-WebApplication -Site $script:defaultWebSite -Name $app.Name - Remove-Item ($appPath + "\*") -Recurse -Force -ErrorAction SilentlyContinue - } - - Write-Host "`tAdding $($app.Name)" - - $tempPath = Join-Path $serverCodeRootPath $app.SourceRelativePath - mkdir $appPath -ErrorAction SilentlyContinue | Out-Null - Copy-Item ($tempPath + "\*") $appPath -Recurse -ErrorAction Stop - - New-WebApplication -Site $script:defaultWebSite -Name $app.Name -PhysicalPath $appPath | Out-Null - - foreach ($config in $app.Configuration) - { - Set-WebConfigurationProperty -Filter $config.Path -Name $config.Name -Value $config.Value -PSPath IIS:\ -location "$($script:defaultWebSite)/$($app.Name)" -ErrorAction Stop - } - - GrantUserAccess $appPath $app.UserAccess - } -} - -Function RemoveServerCode -{ - Write-Host -ForegroundColor Cyan "Removing server code." - foreach ($app in $script:webApps) - { - Write-Host -ForegroundColor DarkGray "`tRemoving webApp files: $($app.Name)" - $appPath = Join-Path $script:iisWwwRoot $app.IISRelativePath - rmdir -Recurse -Force $appPath -ErrorAction SilentlyContinue - } -} - -Function Install -{ - Write-Host -ForegroundColor Cyan "Installing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)" - CheckMachineInfo - - InstallIIS - InstallServerCertificates - CreateLocalUser - ConfigureWebSites - InstallServerCode - InstallServerFirewall - - EnvironmentSetInstalledRoleStatus -} - -Function Uninstall -{ - Write-Host -ForegroundColor Cyan "Removing prerequisites for test role: $($script:LIBRARIES_ROLE_NAME)" - - EnvironmentCheckUninstallRoleStatus - - RemoveServerFirewall - RemoveIIS - RemoveServerCertificates - RemoveLocalUser - RemoveServerCode - - EnvironmentRemoveRoleStatus -} - -if ($uninstall) -{ - Uninstall -} -else -{ - Install -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/README.md b/src/libraries/Common/tests/System/Net/Prerequisites/README.md index a1f766b07fe55..7b0eff9c89e99 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/README.md +++ b/src/libraries/Common/tests/System/Net/Prerequisites/README.md @@ -1,40 +1,2 @@ # System.Net Test Prerequisites Contains source files for the networking test servers in Azure or a private IIS deployment. - -## Deployment Instructions for a private multi-machine environment - -### Configuration - -1. Open .\Deployment\config.ps1 in an editor. -2. Fill in the _Machine Selection_ section with the names and IP addresses of the target machines. In most cases the default options for _Test Parameters_ should be enough. - -Note: the `config.ps1` file has been added to .gitignore to prevent it being updated in the main branch. - -### Build the server applications - -Prepare the $DOTNET_TEST_NET_CLIENT_Machine as any Dev station following the instructions at https://github.com/dotnet/runtime/blob/main/docs/workflow/requirements/windows-requirements.md. Ensure that you can build and test CoreFX on this machine. -In addition, you will also need to install the _Azure development_ workload for Visual Studio 2017. - -From a Visual Studio command prompt: - -``` - powershell - cd .\Servers - .\buildAndPackage.ps1 -``` - -You should now find a folder named `IISApplications` within the Deployment folder. - -### (only once) Create the Active Directory and join all machines - -Skip this step if previously completed and all machines are already part of a domain to which you have Administrator rights. -This will join all machines to a test Active Directory and enable Windows Remoting. - -1. Copy the Deployment folder to each of the machines. -2. Run the .\setup.ps1 script on the machine designated to become the Domain Controller. Once complete, the machine will reboot. -3. Run the .\setup.ps1 script on all other domain joined machines. Once complete, the machines will reboot. - -### Install or Update the environment - -Running as the Active Directory Administrator, run .\setup.ps1 from any of the machines within the environment. -The script will use WinRM to connect and update all other roles. diff --git a/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs b/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs index 0c1418f4443e3..e0d1e4c77de86 100644 --- a/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs +++ b/src/libraries/Common/tests/System/Net/SslProtocolSupport.cs @@ -59,18 +59,42 @@ public static SslProtocols SupportedSslProtocols } } + public static IEnumerable EnumerateSupportedProtocols() + { + foreach (SslProtocols protocol in Enum.GetValues(typeof(SslProtocols))) + { +#pragma warning disable 0618 // SSL2/3 are deprecated + if (protocol != SslProtocols.None && protocol != SslProtocols.Default && (protocol & SupportedSslProtocols) == protocol) + { + yield return protocol; + } +#pragma warning restore 0618 + } + } + + public static IEnumerable EnumerateSupportedProtocols(SslProtocols mask, bool includeNone = false) + { + if (includeNone) + { + yield return SslProtocols.None; + } + + foreach (SslProtocols protocol in EnumerateSupportedProtocols()) + { + if ((protocol & mask) == protocol) + { + yield return protocol; + } + } + } + public class SupportedSslProtocolsTestData : IEnumerable { public IEnumerator GetEnumerator() { - foreach (SslProtocols protocol in Enum.GetValues(typeof(SslProtocols))) + foreach (SslProtocols protocol in SslProtocolSupport.EnumerateSupportedProtocols()) { -#pragma warning disable 0618 // SSL2/3 are deprecated - if (protocol != SslProtocols.None && protocol != SslProtocols.Default && (protocol & SupportedSslProtocols) == protocol) - { - yield return new object[] { protocol }; - } -#pragma warning restore 0618 + yield return new object[] { protocol }; } } diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs index 64662bfa21560..3be8bcce1fa0b 100644 --- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs +++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs @@ -35,7 +35,7 @@ public static partial class ZipFile /// that is not supported. /// /// The path to the archive on the file system that is to be extracted. - /// The path to the directory on the file system. The directory specified must not exist, but the directory that it is contained in must exist. + /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName) => ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName, entryNameEncoding: null, overwriteFiles: false); @@ -67,7 +67,7 @@ public static void ExtractToDirectory(string sourceArchiveFileName, string desti /// that is not supported. /// /// The path to the archive on the file system that is to be extracted. - /// The path to the directory on the file system. The directory specified must not exist, but the directory that it is contained in must exist. + /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. /// True to indicate overwrite. public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, bool overwriteFiles) => ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName, entryNameEncoding: null, overwriteFiles: overwriteFiles); @@ -154,7 +154,7 @@ public static void ExtractToDirectory(string sourceArchiveFileName, string desti /// that is not supported. /// /// The path to the archive on the file system that is to be extracted. - /// The path to the directory on the file system. The directory specified must not exist, but the directory that it is contained in must exist. + /// The path to the directory in which to place the extracted files, specified as a relative or absolute path. A relative path is interpreted as relative to the current working directory. /// True to indicate overwrite. /// The encoding to use when reading or writing entry names in this ZipArchive. /// /// NOTE: Specifying this parameter to values other than null is discouraged. diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index dfb002eb6b0e5..f1a64dd5bd299 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -37,8 +37,8 @@ - + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs index dbfcf3974d4c2..f191fa5f89d06 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs @@ -53,20 +53,19 @@ private static bool IsEnabled() s_diagnosticListener.IsEnabled(); } - private static Activity? CreateActivity(HttpRequestMessage requestMessage) + private static Activity? StartActivity(HttpRequestMessage request) { Activity? activity = null; if (s_activitySource.HasListeners()) { - activity = s_activitySource.CreateActivity(DiagnosticsHandlerLoggingStrings.RequestActivityName, ActivityKind.Client); + activity = s_activitySource.StartActivity(DiagnosticsHandlerLoggingStrings.RequestActivityName, ActivityKind.Client); } - if (activity is null) + if (activity is null && + (Activity.Current is not null || + s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityName, request))) { - if (Activity.Current is not null || s_diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityName, requestMessage)) - { - activity = new Activity(DiagnosticsHandlerLoggingStrings.RequestActivityName); - } + activity = new Activity(DiagnosticsHandlerLoggingStrings.RequestActivityName).Start(); } return activity; @@ -109,12 +108,30 @@ private async ValueTask SendAsyncCore(HttpRequestMessage re DiagnosticListener diagnosticListener = s_diagnosticListener; Guid loggingRequestId = Guid.Empty; - Activity? activity = CreateActivity(request); + Activity? activity = StartActivity(request); - // Start activity anyway if it was created. if (activity is not null) { - activity.Start(); + // https://github.com/open-telemetry/semantic-conventions/blob/release/v1.23.x/docs/http/http-spans.md#name + activity.DisplayName = HttpMethod.GetKnownMethod(request.Method.Method)?.Method ?? "HTTP"; + + if (activity.IsAllDataRequested) + { + // Add standard tags known before sending the request. + KeyValuePair methodTag = DiagnosticsHelper.GetMethodTag(request.Method, out bool isUnknownMethod); + activity.SetTag(methodTag.Key, methodTag.Value); + if (isUnknownMethod) + { + activity.SetTag("http.request.method_original", request.Method.Method); + } + + if (request.RequestUri is Uri requestUri && requestUri.IsAbsoluteUri) + { + activity.SetTag("server.address", requestUri.Host); + activity.SetTag("server.port", requestUri.Port); + activity.SetTag("url.full", DiagnosticsHelper.GetRedactedUriString(requestUri)); + } + } // Only send start event to users who subscribed for it. if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityStartName)) @@ -141,6 +158,7 @@ private async ValueTask SendAsyncCore(HttpRequestMessage re } HttpResponseMessage? response = null; + Exception? exception = null; TaskStatus taskStatus = TaskStatus.RanToCompletion; try { @@ -159,6 +177,7 @@ await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false) catch (Exception ex) { taskStatus = TaskStatus.Faulted; + exception = ex; if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ExceptionEventName)) { @@ -176,6 +195,25 @@ await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false) { activity.SetEndTime(DateTime.UtcNow); + if (activity.IsAllDataRequested) + { + // Add standard tags known at request completion. + if (response is not null) + { + activity.SetTag("http.response.status_code", DiagnosticsHelper.GetBoxedStatusCode((int)response.StatusCode)); + activity.SetTag("network.protocol.version", DiagnosticsHelper.GetProtocolVersionString(response.Version)); + } + + if (DiagnosticsHelper.TryGetErrorType(response, exception, out string? errorType)) + { + activity.SetTag("error.type", errorType); + + // The presence of error.type indicates that the conditions for setting Error status are also met. + // https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#status + activity.SetStatus(ActivityStatusCode.Error); + } + } + // Only send stop event to users who subscribed for it. if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestActivityStopName)) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs index 60d2b90da7f06..3acb10de9478a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs @@ -9,6 +9,47 @@ namespace System.Net.Http { internal static class DiagnosticsHelper { + internal static string GetRedactedUriString(Uri uri) + { + Debug.Assert(uri.IsAbsoluteUri); + + if (GlobalHttpSettings.DiagnosticsHandler.DisableUriRedaction) + { + return uri.AbsoluteUri; + } + + string pathAndQuery = uri.PathAndQuery; + int queryIndex = pathAndQuery.IndexOf('?'); + + bool redactQuery = queryIndex >= 0 && // Query is present. + queryIndex < pathAndQuery.Length - 1; // Query is not empty. + + return (redactQuery, uri.IsDefaultPort) switch + { + (true, true) => $"{uri.Scheme}://{uri.Host}{pathAndQuery.AsSpan(0, queryIndex + 1)}*", + (true, false) => $"{uri.Scheme}://{uri.Host}:{uri.Port}{pathAndQuery.AsSpan(0, queryIndex + 1)}*", + (false, true) => $"{uri.Scheme}://{uri.Host}{pathAndQuery}", + (false, false) => $"{uri.Scheme}://{uri.Host}:{uri.Port}{pathAndQuery}" + }; + } + + internal static KeyValuePair GetMethodTag(HttpMethod method, out bool isUnknownMethod) + { + // Return canonical names for known methods and "_OTHER" for unknown ones. + HttpMethod? known = HttpMethod.GetKnownMethod(method.Method); + isUnknownMethod = known is null; + return new KeyValuePair("http.request.method", isUnknownMethod ? "_OTHER" : known!.Method); + } + + internal static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch + { + (1, 0) => "1.0", + (1, 1) => "1.1", + (2, 0) => "2", + (3, 0) => "3", + _ => httpVersion.ToString() + }; + public static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) { if (response is not null) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs index afeac67e38a5d..72c9a4a3fc52e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs @@ -14,6 +14,11 @@ internal static class DiagnosticsHandler "System.Net.Http.EnableActivityPropagation", "DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION", true); + + public static bool DisableUriRedaction { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch( + "System.Net.Http.DisableUriRedaction", + "DOTNET_SYSTEM_NET_HTTP_DISABLEURIREDACTION", + false); } internal static class SocketsHttpHandler diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs index da42316b5ab98..152ad063a5b8a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs @@ -110,7 +110,7 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon if (response is not null) { tags.Add("http.response.status_code", DiagnosticsHelper.GetBoxedStatusCode((int)response.StatusCode)); - tags.Add("network.protocol.version", GetProtocolVersionString(response.Version)); + tags.Add("network.protocol.version", DiagnosticsHelper.GetProtocolVersionString(response.Version)); } if (DiagnosticsHelper.TryGetErrorType(response, exception, out string? errorType)) @@ -131,15 +131,6 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon } } - private static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch - { - (1, 0) => "1.0", - (1, 1) => "1.1", - (2, 0) => "2", - (3, 0) => "3", - _ => httpVersion.ToString() - }; - private static TagList InitializeCommonTags(HttpRequestMessage request) { TagList tags = default; @@ -154,18 +145,11 @@ private static TagList InitializeCommonTags(HttpRequestMessage request) tags.Add("server.port", requestUri.Port); } } - tags.Add(GetMethodTag(request.Method)); + tags.Add(DiagnosticsHelper.GetMethodTag(request.Method, out _)); return tags; } - internal static KeyValuePair GetMethodTag(HttpMethod method) - { - // Return canonical names for known methods and "_OTHER" for unknown ones. - HttpMethod? known = HttpMethod.GetKnownMethod(method.Method); - return new KeyValuePair("http.request.method", known?.Method ?? "_OTHER"); - } - private sealed class SharedMeter : Meter { public static Meter Instance { get; } = new SharedMeter(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/SocketsHttpHandlerMetrics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/SocketsHttpHandlerMetrics.cs index bd37b3f66b805..f654136a1001c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/SocketsHttpHandlerMetrics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/SocketsHttpHandlerMetrics.cs @@ -47,7 +47,7 @@ public void RequestLeftQueue(HttpRequestMessage request, HttpConnectionPool pool tags.Add("server.port", pool.OriginAuthority.Port); } - tags.Add(MetricsHandler.GetMethodTag(request.Method)); + tags.Add(DiagnosticsHelper.GetMethodTag(request.Method, out _)); RequestsQueueDuration.Record(duration.TotalSeconds, tags); } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 57e28e79193ec..c9534586f5dfe 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -19,7 +19,7 @@ namespace System.Net.Http.Functional.Tests { - public abstract class DiagnosticsTest : HttpClientHandlerTestBase + public abstract class DiagnosticsTest : DiagnosticsTestBase { private const string EnableActivityPropagationEnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION"; private const string EnableActivityPropagationAppCtxSettingName = "System.Net.Http.EnableActivityPropagation"; @@ -378,6 +378,204 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( }, UseVersion.ToString(), TestAsync.ToString(), idFormat.ToString()).DisposeAsync(); } + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(200, "GET")] + [InlineData(404, "GET")] + [InlineData(200, "CUSTOM")] + public async Task SendAsync_DiagnosticListener_ExpectedTagsRecorded(int statusCode, string method) + { + await RemoteExecutor.Invoke(static async (useVersion, testAsync, statusCodeStr, method) => + { + TaskCompletionSource activityStopTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Activity parentActivity = new Activity("parent"); + parentActivity.Start(); + + Uri? currentUri = null; + string? expectedUriFull = null; + + var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(kvp => + { + Assert.NotNull(currentUri); + + if (!kvp.Key.StartsWith("System.Net.Http.HttpRequestOut")) + { + return; + } + Activity activity = Activity.Current; + Assert.NotNull(activity); + Assert.Equal(parentActivity, Activity.Current.Parent); + IEnumerable> tags = activity.TagObjects; + Assert.Equal(method is "CUSTOM" ? "HTTP" : method, activity.DisplayName); + VerifyRequestTags(tags, currentUri, expectedUriFull, expectedMethodTag: method is "CUSTOM" ? "_OTHER" : method); + VerifyTag(tags, "http.request.method_original", method is "CUSTOM" ? method : null); + + if (kvp.Key.EndsWith(".Stop")) + { + VerifyTag(tags, "network.protocol.version", GetVersionString(Version.Parse(useVersion))); + VerifyTag(tags, "http.response.status_code", int.Parse(statusCodeStr)); + + if (statusCodeStr != "200") + { + string errorType = (string)tags.Single(t => t.Key == "error.type").Value; + Assert.Equal(ActivityStatusCode.Error, activity.Status); + Assert.Equal(statusCodeStr, errorType); + } + else + { + Assert.Equal(ActivityStatusCode.Unset, activity.Status); + Assert.DoesNotContain(tags, t => t.Key == "error.type"); + } + + activityStopTcs.SetResult(); + } + }); + + using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver)) + { + diagnosticListenerObserver.Enable(s => s.Contains("HttpRequestOut")); + + await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( + async uri => + { + uri = new Uri($"{uri.Scheme}://user:pass@{uri.Authority}/1/2/?a=1&b=2"); + expectedUriFull = $"{uri.Scheme}://{uri.Authority}{uri.AbsolutePath}?*"; + currentUri = uri; + + using HttpClient client = new(CreateHttpClientHandler(allowAllCertificates: true)); + using HttpRequestMessage request = CreateRequest(HttpMethod.Parse(method), uri, Version.Parse(useVersion), exactVersion: true); + await client.SendAsync(bool.Parse(testAsync), request); + await activityStopTcs.Task; + }, + async server => + { + HttpRequestData requestData = await server.AcceptConnectionSendResponseAndCloseAsync( + statusCode: (HttpStatusCode)int.Parse(statusCodeStr)); + AssertHeadersAreInjected(requestData, parentActivity); + }); + } + }, UseVersion.ToString(), TestAsync.ToString(), statusCode.ToString(), method).DisposeAsync(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(200, "GET")] + [InlineData(404, "GET")] + [InlineData(200, "CUSTOM")] + public async Task SendAsync_ActivitySource_ExpectedTagsRecorded(int statusCode, string method) + { + await RemoteExecutor.Invoke(static async (useVersion, testAsync, statusCodeStr, method) => + { + TaskCompletionSource activityStopTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); + Activity? activity = null; + Uri? currentUri = null; + string? expectedUriFull = null; + + using ActivityListener listener = new ActivityListener() + { + ShouldListenTo = s => s.Name is "System.Net.Http", + Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllData, + ActivityStopped = a => + { + activity = a; + var tags = activity.TagObjects; + VerifyRequestTags(a.TagObjects, currentUri, expectedUriFull, expectedMethodTag: method is "CUSTOM" ? "_OTHER" : method); + VerifyTag(tags, "http.request.method_original", method is "CUSTOM" ? method : null); + VerifyTag(tags, "network.protocol.version", GetVersionString(Version.Parse(useVersion))); + VerifyTag(tags, "http.response.status_code", int.Parse(statusCodeStr)); + + if (statusCodeStr != "200") + { + string errorType = (string)tags.Single(t => t.Key == "error.type").Value; + Assert.Equal(ActivityStatusCode.Error, activity.Status); + Assert.Equal(statusCodeStr, errorType); + } + else + { + Assert.Equal(ActivityStatusCode.Unset, activity.Status); + Assert.DoesNotContain(tags, t => t.Key == "error.type"); + } + + activityStopTcs.SetResult(); + } + }; + ActivitySource.AddActivityListener(listener); + + await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( + async uri => + { + uri = new Uri($"{uri.Scheme}://user:pass@{uri.Authority}/1/2/?a=1&b=2"); + expectedUriFull = $"{uri.Scheme}://{uri.Authority}{uri.AbsolutePath}?*"; + currentUri = uri; + + using HttpClient client = new(CreateHttpClientHandler(allowAllCertificates: true)); + using HttpRequestMessage request = CreateRequest(HttpMethod.Parse(method), uri, Version.Parse(useVersion), exactVersion: true); + await client.SendAsync(bool.Parse(testAsync), request); + await activityStopTcs.Task; + }, + async server => + { + await server.AcceptConnectionSendResponseAndCloseAsync(statusCode: (HttpStatusCode)int.Parse(statusCodeStr)); + }); + + Assert.NotNull(activity); + }, UseVersion.ToString(), TestAsync.ToString(), statusCode.ToString(), method).DisposeAsync(); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public async Task SendAsync_DoNotSampleAllData_NoTagsRecorded() + { + await RemoteExecutor.Invoke(static async (useVersion, testAsync) => + { + TaskCompletionSource activityStopTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); + Activity? activity = null; + using ActivityListener listener = new ActivityListener() + { + ShouldListenTo = s => s.Name is "System.Net.Http", + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.PropagationData, + ActivityStopped = a => + { + activity = a; + activityStopTcs.SetResult(); + } + }; + ActivitySource.AddActivityListener(listener); + + await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( + async uri => + { + + await GetAsync(useVersion, testAsync, uri); + await activityStopTcs.Task; + }, + async server => + { + _ = await server.AcceptConnectionSendResponseAndCloseAsync(); + }); + + Assert.NotNull(activity); + Assert.Empty(activity.TagObjects); + }, UseVersion.ToString(), TestAsync.ToString()).DisposeAsync(); + } + + protected static void VerifyRequestTags(IEnumerable> tags, Uri uri, string expectedUriFull, string expectedMethodTag = "GET") + { + VerifyTag(tags, "server.address", uri.Host); + VerifyTag(tags, "server.port", uri.Port); + VerifyTag(tags, "http.request.method", expectedMethodTag); + VerifyTag(tags, "url.full", expectedUriFull); + } + + protected static void VerifyTag(KeyValuePair[] tags, string name, T value) + { + if (value is null) + { + Assert.DoesNotContain(tags, t => t.Key == name); + } + else + { + Assert.Equal(value, (T)tags.Single(t => t.Key == name).Value); + } + } [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(false)] diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index 773fa142a1c7d..b8dc01e63fdb7 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -19,23 +19,13 @@ namespace System.Net.Http.Functional.Tests { - public abstract class HttpMetricsTestBase : HttpClientHandlerTestBase + public abstract class DiagnosticsTestBase : HttpClientHandlerTestBase { - protected static class InstrumentNames - { - public const string RequestDuration = "http.client.request.duration"; - public const string ActiveRequests = "http.client.active_requests"; - public const string OpenConnections = "http.client.open_connections"; - public const string IdleConnections = "http-client-current-idle-connections"; - public const string ConnectionDuration = "http.client.connection.duration"; - public const string TimeInQueue = "http.client.request.time_in_queue"; - } - - protected HttpMetricsTestBase(ITestOutputHelper output) : base(output) + protected DiagnosticsTestBase(ITestOutputHelper output) : base(output) { } - protected static void VerifyTag(KeyValuePair[] tags, string name, T value) + protected static void VerifyTag(IEnumerable> tags, string name, T value) { if (value is null) { @@ -43,32 +33,53 @@ protected static void VerifyTag(KeyValuePair[] tags, string } else { - Assert.Equal(value, (T)tags.Single(t => t.Key == name).Value); + object? actualValue = tags.Single(t => t.Key == name).Value; + Assert.Equal(value, (T)actualValue); } } - private static void VerifyPeerAddress(KeyValuePair[] tags) - { - string ipString = (string)tags.Single(t => t.Key == "network.peer.address").Value; - IPAddress ip = IPAddress.Parse(ipString); - Assert.True(ip.Equals(IPAddress.Loopback.MapToIPv6()) || - ip.Equals(IPAddress.Loopback) || - ip.Equals(IPAddress.IPv6Loopback)); - } - private static void VerifySchemeHostPortTags(KeyValuePair[] tags, Uri uri) + protected static void VerifySchemeHostPortTags(IEnumerable> tags, Uri uri) { VerifyTag(tags, "url.scheme", uri.Scheme); VerifyTag(tags, "server.address", uri.Host); VerifyTag(tags, "server.port", uri.Port); } - private static string? GetVersionString(Version? version) => version == null ? null : version.Major switch + protected static string? GetVersionString(Version? version) => version == null ? null : version.Major switch { 1 => "1.1", 2 => "2", _ => "3" }; + } + + public abstract class HttpMetricsTestBase : DiagnosticsTestBase + { + protected static class InstrumentNames + { + public const string RequestDuration = "http.client.request.duration"; + public const string ActiveRequests = "http.client.active_requests"; + public const string OpenConnections = "http.client.open_connections"; + public const string IdleConnections = "http-client-current-idle-connections"; + public const string ConnectionDuration = "http.client.connection.duration"; + public const string TimeInQueue = "http.client.request.time_in_queue"; + } + + protected HttpMetricsTestBase(ITestOutputHelper output) : base(output) + { + } + + + private static void VerifyPeerAddress(KeyValuePair[] tags) + { + string ipString = (string)tags.Single(t => t.Key == "network.peer.address").Value; + IPAddress ip = IPAddress.Parse(ipString); + Assert.True(ip.Equals(IPAddress.Loopback.MapToIPv6()) || + ip.Equals(IPAddress.Loopback) || + ip.Equals(IPAddress.IPv6Loopback)); + } + protected static void VerifyRequestDuration(Measurement measurement, Uri uri, diff --git a/src/libraries/System.Net.Http/tests/UnitTests/DiagnosticsHelperTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/DiagnosticsHelperTest.cs new file mode 100644 index 0000000000000..24567e47cd9d3 --- /dev/null +++ b/src/libraries/System.Net.Http/tests/UnitTests/DiagnosticsHelperTest.cs @@ -0,0 +1,116 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Diagnostics.Runtime.Utilities; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.Net.Http.Tests +{ + public class DiagnosticsHelperTest + { + public static readonly TheoryData GetRedactedUriString_Data = new TheoryData() + { + { "http://q.app/foo", "http://q.app/foo" }, + { "http://q.app:123/foo", "http://q.app:123/foo" }, + { "http://user:xxx@q.app/foo", "http://q.app/foo" }, // has user info + { "http://q.app/foo?", "http://q.app/foo?" }, + { "http://q.app/foo?XXX", "http://q.app/foo?*" }, + { "http://q.app/a/b/c?a=b%20c&x=1", "http://q.app/a/b/c?*" }, + { "http://q.app:4242/a/b/c?a=b%20c&x=1", "http://q.app:4242/a/b/c?*" }, + }; + + [Theory] + [MemberData(nameof(GetRedactedUriString_Data))] + public void GetRedactedUriString_RedactsUriByDefault(string original, string expected) + { + string redacted = DiagnosticsHelper.GetRedactedUriString(new Uri(original)); + Assert.Equal(expected, redacted); + } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public async Task GetRedactedUriString_DisableUriRedaction_DoesNotRedactUri() + { + await RemoteExecutor.Invoke(() => + { + AppContext.SetSwitch("System.Net.Http.DisableUriRedaction", true); + + Uri[] uris = GetRedactedUriString_Data.Select(a => a[0] == null ? null : new Uri((string)a[0], UriKind.RelativeOrAbsolute)).ToArray(); + + foreach (Uri uri in uris) + { + string actual = DiagnosticsHelper.GetRedactedUriString(uri); + Assert.Equal(uri.AbsoluteUri, actual); + } + }).DisposeAsync(); + } + + [Fact] + public void TryGetErrorType_NoError_ReturnsFalse() + { + HttpResponseMessage response = new(HttpStatusCode.OK); + Assert.False(DiagnosticsHelper.TryGetErrorType(response, null, out _)); + } + + [Theory] + [InlineData(HttpStatusCode.NotFound)] + [InlineData(HttpStatusCode.InternalServerError)] + public void TryGetErrorType_ErrorStatus_OutputsStatusCodeString(HttpStatusCode statusCode) + { + HttpResponseMessage response = new(statusCode); + Assert.True(DiagnosticsHelper.TryGetErrorType(response, null, out string errorType)); + } + + + public static TheoryData TryGetErrorType_HttpRequestError_Data() + { + TheoryData result = new(); + foreach (var e in Enum.GetValues(typeof(HttpRequestError))) + { + result.Add((HttpRequestError)e); + } + return result; + } + + [Theory] + [MemberData(nameof(TryGetErrorType_HttpRequestError_Data))] + public void TryGetErrorType_HttpRequestError(HttpRequestError error) + { + HttpRequestException exception = new(error); + + Assert.True(DiagnosticsHelper.TryGetErrorType(null, exception, out string errorType)); + Assert.Equal(GetExpectedErrorType(error), errorType); + + Assert.True(DiagnosticsHelper.TryGetErrorType(new HttpResponseMessage(HttpStatusCode.OK), exception, out errorType)); + Assert.Equal(GetExpectedErrorType(error), errorType); + + static string GetExpectedErrorType(HttpRequestError error) + { + if (error == HttpRequestError.Unknown) + { + return typeof(HttpRequestException).FullName; + } + + string s = error.ToString(); + StringBuilder bld = new(); + bld.Append(char.ToLower(s[0])); + for (int i = 1; i < s.Length; i++) + { + bld.Append(char.IsUpper(s[i]) ? $"_{char.ToLower(s[i])}" : s[i]); + } + return bld.ToString(); + } + } + + [Fact] + public void TryGetErrorType_OperationCanceledException() + { + OperationCanceledException ex = new(); + Assert.True(DiagnosticsHelper.TryGetErrorType(null, ex, out string errorType)); + Assert.Equal(ex.GetType().FullName, errorType); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index f0f23f16ccb3c..4483fe2bf0e47 100755 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -183,6 +183,8 @@ Link="ProductionCode\System\Net\Http\Headers\ViaHeaderValue.cs" /> + + diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs index 8b15670ee88a2..333be4e4a8138 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicCipherSuitesPolicyTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Net.Security; +using System.Security.Authentication; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -48,7 +49,7 @@ public Task SupportedCipher_Success() [Theory] [InlineData(new TlsCipherSuite[] { })] [InlineData(new[] { TlsCipherSuite.TLS_AES_128_CCM_8_SHA256 })] - public void NoSupportedCiphers_ThrowsArgumentException(TlsCipherSuite[] ciphers) + public async Task NoSupportedCiphers_ThrowsArgumentException(TlsCipherSuite[] ciphers) { CipherSuitesPolicy policy = new CipherSuitesPolicy(ciphers); var listenerOptions = new QuicListenerOptions() @@ -62,11 +63,16 @@ public void NoSupportedCiphers_ThrowsArgumentException(TlsCipherSuite[] ciphers) return ValueTask.FromResult(serverOptions); } }; - Assert.ThrowsAsync(async () => await CreateQuicListener(listenerOptions)); + await using var listener = await CreateQuicListener(listenerOptions); - var clientOptions = CreateQuicClientOptions(new IPEndPoint(IPAddress.Loopback, 5000)); + // Creating a connection with incompatible ciphers. + var clientOptions = CreateQuicClientOptions(listener.LocalEndPoint); clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = policy; - Assert.ThrowsAsync(async () => await CreateQuicConnection(clientOptions)); + await Assert.ThrowsAsync(async () => await CreateQuicConnection(clientOptions)); + + // Creating a connection to a server configured with incompatible ciphers. + await Assert.ThrowsAsync(async () => await CreateQuicConnection(listener.LocalEndPoint)); + await Assert.ThrowsAsync(async () => await listener.AcceptConnectionAsync()); } [Fact] diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index 098b022f22636..bcfa3202708bb 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -153,7 +153,8 @@ public async Task QuicRootedConnectionGetsReleased_ConnectFails() }; QuicListener listener = await CreateQuicListener(listenerOptions); - await Assert.ThrowsAsync(async () => await CreateConnectedQuicConnection(listener)); + await Assert.ThrowsAsync(async () => await CreateQuicConnection(listener.LocalEndPoint)); + await Assert.ThrowsAsync(async () => await listener.AcceptConnectionAsync()); // Dispose everything and check if all weak references are dead. await listener.DisposeAsync(); @@ -867,10 +868,13 @@ public async Task OpenStreamAsync_BlocksUntilAvailable_PeerClosesWritingUnidirec // Open one stream, second call should block await using var stream = await clientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional); await stream.WriteAsync(new byte[64 * 1024], completeWrites: true); - await Assert.ThrowsAsync(() => clientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional).AsTask().WaitAsync(TimeSpan.FromSeconds(1))); + var pendingOpenStreamTask = clientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional); + Assert.False(pendingOpenStreamTask.IsCompleted); await clientConnection.DisposeAsync(); await serverConnection.DisposeAsync(); + + await Assert.ThrowsAsync(async () => await pendingOpenStreamTask); } [Theory] diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs index 6e3971764d18f..c65b38c73c746 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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; @@ -73,6 +73,7 @@ public async Task AcceptConnectionAsync_InvalidConnectionOptions_Throws() ValueTask connectTask = CreateQuicConnection(listener.LocalEndPoint); await Assert.ThrowsAnyAsync(async () => await listener.AcceptConnectionAsync()); + await Assert.ThrowsAnyAsync(async () => await connectTask); } [Fact] diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs index 8f455d61f6a7c..164a4817a2fe3 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicStreamTests.cs @@ -1452,7 +1452,7 @@ await RunClientServer( } else { - await WaitingSide(stream, tcs.Task, DefaultStreamErrorCodeClient); + await WaitingSide(stream, tcs.Task, true); } }, clientFunction: async connection => @@ -1465,7 +1465,7 @@ await RunClientServer( if (disposeServer) { - await WaitingSide(stream, tcs.Task, DefaultStreamErrorCodeServer); + await WaitingSide(stream, tcs.Task, false); } else { @@ -1493,10 +1493,6 @@ async ValueTask DisposeSide(QuicStream stream, TaskCompletionSource tcs) await stream.DisposeAsync(); - // Reads should be aborted as we didn't consume the data. - var readEx = await AssertThrowsQuicExceptionAsync(QuicError.OperationAborted, () => stream.ReadsClosed); - Assert.Null(readEx.ApplicationErrorCode); - // Writes should be aborted as we aborted them. if (abortCode.HasValue) { @@ -1509,29 +1505,21 @@ async ValueTask DisposeSide(QuicStream stream, TaskCompletionSource tcs) Assert.True(stream.WritesClosed.IsCompletedSuccessfully); } + // Reads should be aborted as we didn't consume the data. + var readEx = await AssertThrowsQuicExceptionAsync(QuicError.OperationAborted, () => stream.ReadsClosed); + Assert.Null(readEx.ApplicationErrorCode); + tcs.SetResult(abortCode); } - async ValueTask WaitingSide(QuicStream stream, Task task, long errorCode) + async ValueTask WaitingSide(QuicStream stream, Task task, bool server) { long? abortCode = await task; - // Reads will be aborted by the peer as we didn't consume them all. - if (abortCode.HasValue) - { - var readEx = await AssertThrowsQuicExceptionAsync(QuicError.StreamAborted, () => stream.ReadsClosed); - Assert.Equal(abortCode.Value, readEx.ApplicationErrorCode); - } - // Reads should be still open as the peer closed gracefully and we are keeping the data in buffer. - else - { - Assert.False(stream.ReadsClosed.IsCompleted); - } - if (!completeWrites) { // Writes must be aborted by the peer as we didn't complete them. var writeEx = await AssertThrowsQuicExceptionAsync(QuicError.StreamAborted, () => stream.WritesClosed); - Assert.Equal(errorCode, writeEx.ApplicationErrorCode); + Assert.Equal(server ? DefaultStreamErrorCodeClient : DefaultStreamErrorCodeServer, writeEx.ApplicationErrorCode); } else { @@ -1545,9 +1533,25 @@ async ValueTask WaitingSide(QuicStream stream, Task task, long errorCode) { QuicException qe = Assert.IsType(ex); Assert.Equal(QuicError.StreamAborted, qe.QuicError); - Assert.Equal(errorCode, qe.ApplicationErrorCode); + Assert.Equal(server ? DefaultStreamErrorCodeClient : DefaultStreamErrorCodeServer, qe.ApplicationErrorCode); } } + + // Reads will be aborted by the peer as we didn't consume them all. + if (abortCode.HasValue) + { + var readEx = await AssertThrowsQuicExceptionAsync(QuicError.StreamAborted, () => stream.ReadsClosed); + Assert.Equal(abortCode.Value, readEx.ApplicationErrorCode); + } + // Reads should be still open as the peer closed gracefully and we are keeping the data in buffer. + else + { + Assert.False(stream.ReadsClosed.IsCompleted); + + // Dispose will abort reading from this side. + await stream.DisposeAsync(); + await AssertThrowsQuicExceptionAsync(QuicError.OperationAborted, () => stream.ReadsClosed); + } } } } diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs index 5125c72e0ca8d..699a41fcd1042 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicTestCollection.cs @@ -1,16 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.DotNet.XUnitExtensions; -using System; -using System.Net.Quic; +using Microsoft.Quic; using System.Reflection; using System.Text; using System.Linq; +using System.Threading.Tasks; +using System.Threading; +using System.Collections.Generic; using Xunit; -using Xunit.Abstractions; -using Microsoft.Quic; using static Microsoft.Quic.MsQuic; namespace System.Net.Quic.Tests; @@ -22,6 +21,8 @@ public unsafe class QuicTestCollection : ICollectionFixture, public static Version MsQuicVersion { get; } = GetMsQuicVersion(); + private static readonly Dictionary s_unobservedExceptions = new Dictionary(); + public QuicTestCollection() { string msQuicLibraryVersion = GetMsQuicLibraryVersion(); @@ -33,11 +34,21 @@ public QuicTestCollection() QUIC_SETTINGS settings = default(QUIC_SETTINGS); settings.IsSet.MaxWorkerQueueDelayUs = 1; settings.MaxWorkerQueueDelayUs = 2_500_000u; // 2.5s, 10x the default - if (MsQuic.StatusFailed(GetApiTable()->SetParam(null, MsQuic.QUIC_PARAM_GLOBAL_SETTINGS, (uint)sizeof(QUIC_SETTINGS), (byte*)&settings))) + if (StatusFailed(GetApiTable()->SetParam(null, QUIC_PARAM_GLOBAL_SETTINGS, (uint)sizeof(QUIC_SETTINGS), (byte*)&settings))) { Console.WriteLine($"Unable to set MsQuic MaxWorkerQueueDelayUs."); } } + + EventHandler eventHandler = (_, e) => + { + lock (s_unobservedExceptions) + { + string text = e.Exception.ToString(); + s_unobservedExceptions[text] = s_unobservedExceptions.GetValueOrDefault(text) + 1; + } + }; + TaskScheduler.UnobservedTaskException += eventHandler; } public unsafe void Dispose() @@ -60,7 +71,7 @@ public unsafe void Dispose() if (StatusFailed(status)) { - System.Console.WriteLine($"Failed to read MsQuic counters: {status}"); + Console.WriteLine($"Failed to read MsQuic counters: {status}"); return; } @@ -81,7 +92,9 @@ void DumpCounter(QUIC_PERFORMANCE_COUNTERS counter) DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_APP_REJECT); DumpCounter(QUIC_PERFORMANCE_COUNTERS.CONN_LOAD_REJECT); - System.Console.WriteLine(sb.ToString()); + Console.WriteLine(sb.ToString()); + + Console.WriteLine($"Unobserved exceptions of {s_unobservedExceptions.Count} different types: {Environment.NewLine}{string.Join(Environment.NewLine + new string('=', 120) + Environment.NewLine, s_unobservedExceptions.Select(pair => $"Count {pair.Value}: {pair.Key}"))}"); } private static Version GetMsQuicVersion() @@ -102,6 +115,6 @@ private static Version GetMsQuicVersion() { Type msQuicApiType = Type.GetType("System.Net.Quic.MsQuicApi, System.Net.Quic"); object msQuicApiInstance = msQuicApiType.GetProperty("Api", BindingFlags.NonPublic | BindingFlags.Static).GetGetMethod(true).Invoke(null, Array.Empty()); - return (QUIC_API_TABLE*)(Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty()))); + return (QUIC_API_TABLE*)Pointer.Unbox(msQuicApiType.GetProperty("ApiTable").GetGetMethod().Invoke(msQuicApiInstance, Array.Empty())); } } diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs index cbabb8898eeca..226b57ef3e0d5 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs @@ -737,7 +737,7 @@ private static SecurityStatusPal InitializeSecurityContext( spn, requestedContextFlags, Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, - inputBuffers, + ref inputBuffers, ref token, ref contextFlags); securityContext = sslContext; @@ -799,7 +799,7 @@ private static SecurityStatusPal AcceptSecurityContext( ref sslContext, requestedContextFlags, Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, - inputBuffers, + ref inputBuffers, ref token, ref contextFlags); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 270808e438d7a..e5a7315b70f2c 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -339,7 +339,8 @@ private async Task ForceAuthenticationAsync(bool receiveFirst, byte[ { if (!receiveFirst) { - token = NextMessage(reAuthenticationData); + token = NextMessage(reAuthenticationData, out int consumed); + Debug.Assert(consumed == (reAuthenticationData?.Length ?? 0)); if (token.Size > 0) { @@ -530,16 +531,13 @@ private ProtocolToken ProcessTlsFrame(int frameSize) int chunkSize = frameSize; ReadOnlySpan availableData = _buffer.EncryptedReadOnlySpan; - // DiscardEncrypted() does not touch data, it just increases start index so next - // EncryptedSpan will exclude the "discarded" data. - _buffer.DiscardEncrypted(frameSize); // Often more TLS messages fit into same packet. Get as many complete frames as we can. - while (_buffer.EncryptedLength > TlsFrameHelper.HeaderSize) + while (_buffer.EncryptedLength - chunkSize > TlsFrameHelper.HeaderSize) { TlsFrameHeader nextHeader = default; - if (!TlsFrameHelper.TryGetFrameHeader(_buffer.EncryptedReadOnlySpan, ref nextHeader)) + if (!TlsFrameHelper.TryGetFrameHeader(_buffer.EncryptedReadOnlySpan.Slice(chunkSize), ref nextHeader)) { break; } @@ -555,10 +553,11 @@ private ProtocolToken ProcessTlsFrame(int frameSize) } chunkSize += frameSize; - _buffer.DiscardEncrypted(frameSize); } - return NextMessage(availableData.Slice(0, chunkSize)); + ProtocolToken token = NextMessage(availableData.Slice(0, chunkSize), out int consumed); + _buffer.DiscardEncrypted(consumed); + return token; } // diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs index 1fee2be053af5..0d9a0e0ef7842 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs @@ -814,9 +814,9 @@ static DateTime GetExpiryTimestamp(SslStreamCertificateContext certificateContex } // - internal ProtocolToken NextMessage(ReadOnlySpan incomingBuffer) + internal ProtocolToken NextMessage(ReadOnlySpan incomingBuffer, out int consumed) { - ProtocolToken token = GenerateToken(incomingBuffer); + ProtocolToken token = GenerateToken(incomingBuffer, out consumed); if (NetEventSource.Log.IsEnabled()) { if (token.Failed) @@ -841,7 +841,7 @@ generates a set of bytes that will be sent next to Return: token - ProtocolToken with status and optionally buffer. --*/ - private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer) + private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer, out int consumed) { bool cachedCreds = false; bool sendTrustList = false; @@ -875,10 +875,10 @@ private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer) sendTrustList = _sslAuthenticationOptions.CertificateContext?.Trust?._sendTrustInHandshake ?? false; token = SslStreamPal.AcceptSecurityContext( - ref _credentialsHandle!, ref _securityContext, inputBuffer, + out consumed, _sslAuthenticationOptions); if (token.Status.ErrorCode == SecurityStatusPalErrorCode.HandshakeStarted) { @@ -894,6 +894,7 @@ private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer) ref _credentialsHandle!, ref _securityContext, ReadOnlySpan.Empty, + out _, _sslAuthenticationOptions); } } @@ -906,6 +907,7 @@ private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer) ref _securityContext, hostName, inputBuffer, + out consumed, _sslAuthenticationOptions); if (token.Status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded) @@ -921,6 +923,7 @@ private ProtocolToken GenerateToken(ReadOnlySpan inputBuffer) ref _securityContext, hostName, ReadOnlySpan.Empty, + out _, _sslAuthenticationOptions); } } @@ -1211,12 +1214,12 @@ private ProtocolToken CreateShutdownToken() return default; } - return GenerateToken(default); + return GenerateToken(default, out _); } private ProtocolToken GenerateAlertToken() { - return GenerateToken(default); + return GenerateToken(default, out _); } private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs index 212e7f210b68d..4a5de17a2a221 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Android.cs @@ -39,9 +39,10 @@ public static ProtocolToken AcceptSecurityContext( ref SafeFreeCredentials credential, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(credential, ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(credential, ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static ProtocolToken InitializeSecurityContext( @@ -49,9 +50,10 @@ public static ProtocolToken InitializeSecurityContext( ref SafeDeleteSslContext? context, string? targetName, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(credential, ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(credential, ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static ProtocolToken Renegotiate( @@ -177,9 +179,12 @@ private static ProtocolToken HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { ProtocolToken token = default; + consumed = 0; + try { SafeDeleteSslContext? sslContext = ((SafeDeleteSslContext?)context); @@ -194,6 +199,7 @@ private static ProtocolToken HandshakeInternal( { sslContext!.Write(inputBuffer); } + consumed = inputBuffer.Length; SafeSslHandle sslHandle = sslContext!.SslContext; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs index e79cb3c88100e..add3454a6f14e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs @@ -90,9 +90,10 @@ public static ProtocolToken AcceptSecurityContext( ref SafeFreeCredentials credential, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static ProtocolToken InitializeSecurityContext( @@ -100,9 +101,10 @@ public static ProtocolToken InitializeSecurityContext( ref SafeDeleteSslContext? context, string? _ /*targetName*/, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static ProtocolToken Renegotiate( @@ -283,9 +285,12 @@ public static bool TryUpdateClintCertificate( private static ProtocolToken HandshakeInternal( ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { ProtocolToken token = default; + consumed = 0; + try { SafeDeleteSslContext? sslContext = ((SafeDeleteSslContext?)context); @@ -301,6 +306,8 @@ private static ProtocolToken HandshakeInternal( sslContext!.Write(inputBuffer); } + consumed = inputBuffer.Length; + SafeSslHandle sslHandle = sslContext!.SslContext; token.Status = PerformHandshake(sslHandle); diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index 0aa6238c84751..700531aa49d35 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -38,9 +38,10 @@ public static ProtocolToken AcceptSecurityContext( ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static ProtocolToken InitializeSecurityContext( @@ -48,9 +49,10 @@ public static ProtocolToken InitializeSecurityContext( ref SafeDeleteSslContext? context, string? _ /*targetName*/, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { - return HandshakeInternal(ref context, inputBuffer, sslAuthenticationOptions); + return HandshakeInternal(ref context, inputBuffer, out consumed, sslAuthenticationOptions); } public static SafeFreeCredentials? AcquireCredentialsHandle(SslAuthenticationOptions _1, bool _2) @@ -145,7 +147,7 @@ public static ProtocolToken Renegotiate( { return default; } - return HandshakeInternal(ref context!, null, sslAuthenticationOptions); + return HandshakeInternal(ref context!, null, out _, sslAuthenticationOptions); } public static void QueryContextStreamSizes(SafeDeleteContext? _ /*securityContext*/, out StreamSizes streamSizes) @@ -169,10 +171,12 @@ public static bool TryUpdateClintCertificate( } private static ProtocolToken HandshakeInternal(ref SafeDeleteSslContext? context, - ReadOnlySpan inputBuffer, SslAuthenticationOptions sslAuthenticationOptions) + ReadOnlySpan inputBuffer, out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { ProtocolToken token = default; token.RentBuffer = true; + consumed = 0; + try { if ((null == context) || context.IsInvalid) @@ -181,6 +185,7 @@ private static ProtocolToken HandshakeInternal(ref SafeDeleteSslContext? context } SecurityStatusPalErrorCode errorCode = Interop.OpenSsl.DoSslHandshake((SafeSslHandle)context, inputBuffer, ref token); + consumed = inputBuffer.Length; if (errorCode == SecurityStatusPalErrorCode.CredentialsNeeded) { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 615ccd01167e3..5ec6a51707678 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -105,6 +105,7 @@ public static ProtocolToken AcceptSecurityContext( ref SafeFreeCredentials? credentialsHandle, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { Interop.SspiCli.ContextFlags unusedAttributes = default; @@ -127,10 +128,17 @@ public static ProtocolToken AcceptSecurityContext( ref context, ServerRequiredFlags | (sslAuthenticationOptions.RemoteCertRequired ? Interop.SspiCli.ContextFlags.MutualAuth : Interop.SspiCli.ContextFlags.Zero), Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP, - inputBuffers, + ref inputBuffers, ref token, ref unusedAttributes); + consumed = inputBuffer.Length; + if (inputBuffers._item1.Type == SecurityBufferType.SECBUFFER_EXTRA) + { + // not all data were consumed + consumed -= inputBuffers._item1.Token.Length; + } + token.Status = SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode); return token; } @@ -149,6 +157,7 @@ public static ProtocolToken InitializeSecurityContext( ref SafeDeleteSslContext? context, string? targetName, ReadOnlySpan inputBuffer, + out int consumed, SslAuthenticationOptions sslAuthenticationOptions) { bool newContext = context == null; @@ -172,12 +181,19 @@ public static ProtocolToken InitializeSecurityContext( targetName, RequiredFlags | Interop.SspiCli.ContextFlags.InitManualCredValidation, Interop.SspiCli.Endianness.SECURITY_NATIVE_DREP, - inputBuffers, + ref inputBuffers, ref token, ref unusedAttributes); token.Status = SecurityStatusAdapterPal.GetSecurityStatusPalFromNativeInt(errorCode); + consumed = inputBuffer.Length; + if (inputBuffers._item1.Type == SecurityBufferType.SECBUFFER_EXTRA) + { + // not all data were consumed + consumed -= inputBuffers._item1.Token.Length; + } + bool allowTlsResume = sslAuthenticationOptions.AllowTlsResume && !SslStream.DisableTlsResume; if (!allowTlsResume && newContext && context != null) @@ -204,7 +220,7 @@ public static ProtocolToken Renegotiate( ref SafeDeleteSslContext? context, SslAuthenticationOptions sslAuthenticationOptions) { - return AcceptSecurityContext(ref credentialsHandle, ref context, Span.Empty, sslAuthenticationOptions); + return AcceptSecurityContext(ref credentialsHandle, ref context, Span.Empty, out _, sslAuthenticationOptions); } public static SafeFreeCredentials AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions, bool newCredentialsRequested) diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowTlsResumeTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowTlsResumeTests.cs index 3bc91b5d53ade..4a0e8c2162093 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowTlsResumeTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowTlsResumeTests.cs @@ -160,16 +160,9 @@ public static TheoryData SslProtocolsData() { var data = new TheoryData(); - data.Add(SslProtocols.None); - - if (PlatformDetection.SupportsTls12) - { - data.Add(SslProtocols.Tls12); - } - - if (PlatformDetection.SupportsTls13) + foreach (SslProtocols protocol in SslProtocolSupport.EnumerateSupportedProtocols(SslProtocols.Tls12 | SslProtocols.Tls13, true)) { - data.Add(SslProtocols.Tls13); + data.Add(protocol); } return data; @@ -186,7 +179,7 @@ public static TheoryData ClientCertTestDat { var data = new TheoryData(); - foreach (SslProtocols protocol in SslProtocolsData().Select(x => x[0])) + foreach (SslProtocols protocol in SslProtocolSupport.EnumerateSupportedProtocols(SslProtocols.Tls12 | SslProtocols.Tls13, true)) foreach (bool certRequired in new[] { true, false }) foreach (ClientCertSource source in Enum.GetValues(typeof(ClientCertSource))) { diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamFramingTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamFramingTest.cs new file mode 100644 index 0000000000000..efc405da00eb7 --- /dev/null +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamFramingTest.cs @@ -0,0 +1,207 @@ +// 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.IO; +using System.Linq; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Security.Authentication; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.XUnitExtensions; +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Security.Tests +{ + using Configuration = System.Net.Test.Common.Configuration; + + // These tests target framing detection in SslStream by manipulating chunking of the data sent between client and server. + public class SslStreamFramingTests : IClassFixture + { + private static bool SupportsRenegotiation => TestConfiguration.SupportsRenegotiation; + + readonly ITestOutputHelper _output; + readonly CertificateSetup _certificates; + + public SslStreamFramingTests(ITestOutputHelper output, CertificateSetup setup) + { + _output = output; + _certificates = setup; + } + + public enum FramingType + { + // 1 byte reads + ByteByByte, + + // coalesce reads to biggest chunks possible + Coalescing + } + + public enum ClientCertScenario + { + None, + InHandshake, + PostHandshake + } + + public static TheoryData HandshakeScenarioData() + { + var data = new TheoryData(); + + foreach (FramingType framingType in Enum.GetValues(typeof(FramingType))) + { + foreach (SslProtocols sslProtocol in SslProtocolSupport.EnumerateSupportedProtocols(SslProtocols.Tls12 | SslProtocols.Tls13, true)) + { + foreach (ClientCertScenario clientCertScenario in Enum.GetValues(typeof(ClientCertScenario))) + { + if (clientCertScenario == ClientCertScenario.PostHandshake && !TestConfiguration.SupportsRenegotiation) + { + continue; + } + + data.Add(framingType, sslProtocol, clientCertScenario); + } + } + } + + return data; + } + + [Theory] + [MemberData(nameof(HandshakeScenarioData))] + public async Task Handshake_Success(FramingType framingType, SslProtocols sslProtocol, ClientCertScenario clientCertScenario) + { + (Stream stream1, Stream stream2) = TestHelper.GetConnectedStreams(); + + ConfigurableReadStream clientStream = new(stream1, framingType); + ConfigurableReadStream serverStream = new(stream2, framingType); + using SslStream client = new SslStream(clientStream); + using SslStream server = new SslStream(serverStream); + + SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions + { + EnabledSslProtocols = sslProtocol, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, + ServerCertificateContext = SslStreamCertificateContext.Create(_certificates.serverCert, _certificates.serverChain), + RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true, + ClientCertificateRequired = clientCertScenario == ClientCertScenario.InHandshake, + }; + + SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions + { + TargetHost = Guid.NewGuid().ToString("N"), + EnabledSslProtocols = sslProtocol, + CertificateRevocationCheckMode = X509RevocationMode.NoCheck, + ClientCertificates = clientCertScenario != ClientCertScenario.None + ? new X509CertificateCollection { _certificates.serverCert } + : new X509CertificateCollection(), + RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true, + }; + + Task clientTask = Task.Run(async () => + { + await client.AuthenticateAsClientAsync(clientOptions); + + // reading triggers potential post-handshake authentication + await client.ReadExactlyAsync(new byte[13]); + }); + Task serverTask = Task.Run(async () => + { + await server.AuthenticateAsServerAsync(serverOptions); + if (clientCertScenario == ClientCertScenario.PostHandshake) + { + await server.NegotiateClientCertificateAsync(); + } + + await server.WriteAsync(Encoding.UTF8.GetBytes("Hello, world!")); + }); + + await TestConfiguration.WhenAllOrAnyFailedWithTimeout(clientTask, serverTask); + + // verify that we used the mocked read method + Assert.True(clientStream.ReadCalled, "Mocked read method was not used"); + Assert.True(serverStream.ReadCalled, "Mocked read method was not used"); + + await TestHelper.PingPong(client, server); + + } + + internal class ConfigurableReadStream : Stream + { + private readonly Stream _stream; + private readonly FramingType _framingType; + + public bool ReadCalled { get; private set; } + + public ConfigurableReadStream(Stream stream, FramingType framingType) + { + _stream = stream; + _framingType = framingType; + } + + public override bool CanRead => _stream.CanRead; + + public override bool CanSeek => _stream.CanSeek; + + public override bool CanWrite => _stream.CanWrite; + + public override long Length => _stream.Length; + + public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public override void Flush() + { + _stream.Flush(); + } + + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + ReadCalled = true; + + switch (_framingType) + { + case FramingType.ByteByByte: + return await _stream.ReadAsync(buffer.Length > 0 ? buffer.Slice(0, 1) : buffer, cancellationToken); + case FramingType.Coalescing: + { + if (buffer.Length > 0) + { + // wait 10ms, this should be enough for the other side to write as much data + // as it will ever write before receiving something back. + await Task.Delay(10); + } + return await _stream.ReadAsync(buffer, cancellationToken); + } + default: + throw new NotImplementedException(); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return ReadAsync(new Memory(buffer, offset, count)).AsTask().GetAwaiter().GetResult(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _stream.Write(buffer, offset, count); + } + } + } +} diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index c1a6fa3108624..3d55a2c888a26 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -33,6 +33,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 964449ddbd611..ad6476701c339 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3494,6 +3494,12 @@ Method cannot be invoked. + + COM target does not implement IDispatch. + + + The interface does not support late bound calls since it does not derive from IDispatch. + The specified TaskContinuationOptions combined LongRunning and ExecuteSynchronously. Synchronous continuations should not be long running. diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 241c1c39e71d5..7a69db71674f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -425,7 +425,7 @@ public static explicit operator checked ulong(Int128 value) /// The value to convert. /// converted to a . [CLSCompliant(false)] - public static explicit operator UInt128(Int128 value) => new UInt128(value._upper, value._lower); + public static explicit operator UInt128(Int128 value) => Unsafe.BitCast(value); /// Explicitly converts a 128-bit signed integer to a value, throwing an overflow exception for any values that fall outside the representable range. /// The value to convert. @@ -438,7 +438,7 @@ public static explicit operator checked UInt128(Int128 value) { ThrowHelper.ThrowOverflowException(); } - return new UInt128(value._upper, value._lower); + return Unsafe.BitCast(value); } /// Explicitly converts a 128-bit signed integer to a value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 365a68c4489ac..d870c60648c6a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -381,6 +381,17 @@ public int Count } } +#if CORECLR + // This config var can be used to enable an experimental mode that may reduce the effects of some priority inversion + // issues seen in cases involving a lot of sync-over-async. See EnqueueForPrioritizationExperiment() for more + // information. The mode is experimental and may change in the future. + internal static readonly bool s_prioritizationExperiment = + AppContextConfigHelper.GetBooleanConfig( + "System.Threading.ThreadPool.PrioritizationExperiment", + "DOTNET_ThreadPool_PrioritizationExperiment", + defaultValue: false); +#endif + private const int ProcessorsPerAssignableWorkItemQueue = 16; private static readonly int s_assignableWorkItemQueueCount = Environment.ProcessorCount <= 32 ? 0 : @@ -394,6 +405,11 @@ public int Count internal readonly ConcurrentQueue workItems = new ConcurrentQueue(); internal readonly ConcurrentQueue highPriorityWorkItems = new ConcurrentQueue(); +#if CORECLR + internal readonly ConcurrentQueue lowPriorityWorkItems = + s_prioritizationExperiment ? new ConcurrentQueue() : null!; +#endif + // SOS's ThreadPool command depends on the following name. The global queue doesn't scale well beyond a point of // concurrency. Some additional queues may be added and assigned to a limited number of worker threads if necessary to // help with limiting the concurrency level. @@ -608,23 +624,68 @@ public void Enqueue(object callback, bool forceGlobal) if (_loggingEnabled && FrameworkEventSource.Log.IsEnabled()) FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject(callback); - ThreadPoolWorkQueueThreadLocals? tl; - if (!forceGlobal && (tl = ThreadPoolWorkQueueThreadLocals.threadLocals) != null) +#if CORECLR + if (s_prioritizationExperiment) { - tl.workStealingQueue.LocalPush(callback); + EnqueueForPrioritizationExperiment(callback, forceGlobal); } else +#endif { - ConcurrentQueue queue = - s_assignableWorkItemQueueCount > 0 && (tl = ThreadPoolWorkQueueThreadLocals.threadLocals) != null - ? tl.assignedGlobalWorkItemQueue - : workItems; - queue.Enqueue(callback); + ThreadPoolWorkQueueThreadLocals? tl; + if (!forceGlobal && (tl = ThreadPoolWorkQueueThreadLocals.threadLocals) != null) + { + tl.workStealingQueue.LocalPush(callback); + } + else + { + ConcurrentQueue queue = + s_assignableWorkItemQueueCount > 0 && (tl = ThreadPoolWorkQueueThreadLocals.threadLocals) != null + ? tl.assignedGlobalWorkItemQueue + : workItems; + queue.Enqueue(callback); + } } EnsureThreadRequested(); } +#if CORECLR + [MethodImpl(MethodImplOptions.NoInlining)] + private void EnqueueForPrioritizationExperiment(object callback, bool forceGlobal) + { + ThreadPoolWorkQueueThreadLocals? tl = ThreadPoolWorkQueueThreadLocals.threadLocals; + if (!forceGlobal && tl != null) + { + tl.workStealingQueue.LocalPush(callback); + return; + } + + ConcurrentQueue queue; + + // This is a rough and experimental attempt at identifying work items that should be lower priority than other + // global work items (even ones that haven't been queued yet), and to queue them to a low-priority global queue that + // is checked after all other global queues. In some cases, a work item may queue another work item that is part of + // the same set of work. For global work items, the second work item would typically get queued behind other global + // work items. In some cases involving a lot of sync-over-async, that can significantly delay worker threads from + // getting unblocked. + if (tl == null && callback is QueueUserWorkItemCallbackBase) + { + queue = lowPriorityWorkItems; + } + else if (s_assignableWorkItemQueueCount > 0 && tl != null) + { + queue = tl.assignedGlobalWorkItemQueue; + } + else + { + queue = workItems; + } + + queue.Enqueue(callback); + } +#endif + public void EnqueueAtHighPriority(object workItem) { Debug.Assert((workItem is IThreadPoolWorkItem) ^ (workItem is Task)); @@ -710,6 +771,14 @@ internal static bool LocalFindAndPop(object callback) } } +#if CORECLR + // Check for low-priority work items + if (s_prioritizationExperiment && lowPriorityWorkItems.TryDequeue(out workItem)) + { + return workItem; + } +#endif + // Try to steal from other threads' local work items { WorkStealingQueue localWsq = tl.workStealingQueue; @@ -769,6 +838,13 @@ public long GlobalCount get { long count = (long)highPriorityWorkItems.Count + workItems.Count; +#if CORECLR + if (s_prioritizationExperiment) + { + count += lowPriorityWorkItems.Count; + } +#endif + for (int i = 0; i < s_assignableWorkItemQueueCount; i++) { count += _assignableWorkItemQueues[i].Count; @@ -1803,6 +1879,17 @@ internal static IEnumerable GetQueuedWorkItems() yield return workItem; } +#if CORECLR + if (ThreadPoolWorkQueue.s_prioritizationExperiment) + { + // Enumerate low-priority global queue + foreach (object workItem in s_workQueue.lowPriorityWorkItems) + { + yield return workItem; + } + } +#endif + // Enumerate each local queue foreach (ThreadPoolWorkQueue.WorkStealingQueue wsq in ThreadPoolWorkQueue.WorkStealingQueueList.Queues) { diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index e9add25bcc9a1..a85edd205d6bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -344,7 +344,7 @@ public static explicit operator checked long(UInt128 value) /// The value to convert. /// converted to a . [CLSCompliant(false)] - public static explicit operator Int128(UInt128 value) => new Int128(value._upper, value._lower); + public static explicit operator Int128(UInt128 value) => Unsafe.BitCast(value); /// Explicitly converts a 128-bit unsigned integer to a value, throwing an overflow exception for any values that fall outside the representable range. /// The value to convert. @@ -357,7 +357,7 @@ public static explicit operator checked Int128(UInt128 value) { ThrowHelper.ThrowOverflowException(); } - return new Int128(value._upper, value._lower); + return Unsafe.BitCast(value); } /// Explicitly converts a 128-bit unsigned integer to a value. diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index a6322854be790..1c05bf37fde45 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -352,7 +352,8 @@ private XmlElement ExportGenericInfo(Type clrType, string elementName, string el ignoreExtensionDataObject: false, preserveObjectReferences: true); serializer.WriteObject(xmlWriter, surrogateData); xmlWriter.Flush(); - return (XmlElement?)XmlDoc.ReadNode(XmlReader.Create(new StringReader(stringWriter.ToString()))); + using var xmlReader = XmlReader.Create(new StringReader(stringWriter.ToString())); + return (XmlElement?)XmlDoc.ReadNode(xmlReader); } [RequiresDynamicCode(DataContract.SerializerAOTWarning)] diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/GetObjectForIUnknownTests.Windows.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/GetObjectForIUnknownTests.Windows.cs index 1c35391fb2e7f..9ae76a7a0c5ff 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/GetObjectForIUnknownTests.Windows.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/GetObjectForIUnknownTests.Windows.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.InteropServices.Tests.Common; using Xunit; @@ -33,5 +35,73 @@ public void GetObjectForIUnknown_ComObject_ReturnsExpected(object o) { GetObjectForIUnknown_ValidPointer_ReturnsExpected(o); } + + [ComImport] + [ComVisible(true)] + [Guid("20d5e748-3e41-414f-ba43-542c6c47bd21")] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface ICallback + { + void M(); + } + + class Callback : ICallback + { + public void M() { } + } + + [GeneratedComInterface] + [Guid("20d5e748-3e41-414f-ba43-542c6c47bd21")] + public partial interface ICallbackWrapper + { + void M(); + } + + // Notice this class doesn't implement IDispatch nor it is specified on + // the Callback class. The user workaround would be to mark the + // Callback class as ComVisible(true) and public. We wrap the input + // to avoid the automatic detection the runtime does on COM objects. + // This simulates the failure mode we are trying to detect. + [GeneratedComClass] + public partial class CallbackWrapper : ICallbackWrapper + { + private IntPtr _wrapper; + public CallbackWrapper(IntPtr wrapper) + { + _wrapper = wrapper; + Marshal.AddRef(_wrapper); + } + + ~CallbackWrapper() + { + Marshal.Release(_wrapper); + } + + public void M() => throw new NotImplementedException(); + } + + [UnmanagedCallersOnly] + private static unsafe IntPtr WrapCallback(IntPtr p) + { + // See CallbackWrapper for why we wrap the input. + var wrapper = new CallbackWrapper(p); + return (IntPtr)ComInterfaceMarshaller.ConvertToUnmanaged(wrapper); + } + + private delegate ICallback WrapDelegate(ICallback cb); + + // This test is validating a niche case is detected where a class implementing COM "callback" + // interface is marshalled but fails to indicate it is COM visible and thus IDispatch isn't + // provided by the runtime. This most often occurs in out-of-proc COM scenarios. + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltInComEnabled))] + public unsafe void GetObjectForIUnknown_ComObject_MissingIDispatchOnTarget() + { + // Use a delegate to trigger COM interop marshalling. + var fptr = Marshal.GetDelegateForFunctionPointer((IntPtr)(delegate* unmanaged)&WrapCallback); + ICallback icb = fptr(new Callback()); + + Exception ex = Assert.Throws(() => icb.M()); + Assert.Equal("COM target does not implement IDispatch.", ex.Message); + } } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index bd3c5ef819c35..e4d8845dd05e8 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -637,15 +637,10 @@ public bool IsPowerOfTwo if (_sign != 1) return false; + int iu = _bits.Length - 1; - if (!BitOperations.IsPow2(_bits[iu])) - return false; - while (--iu >= 0) - { - if (_bits[iu] != 0) - return false; - } - return true; + + return BitOperations.IsPow2(_bits[iu]) && !_bits.AsSpan(0, iu).ContainsAnyExcept(0u); } } diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs index 695cd6abb1714..579662f96dc1f 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs @@ -295,6 +295,7 @@ public static async Task Task_WhenAny_TwoTasks_WakesOnFirstCompletion() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99500", TestPlatforms.Browser)] public static void CancellationTokenRegitration() { ManualResetEvent mre = new ManualResetEvent(false); @@ -312,6 +313,7 @@ public static void CancellationTokenRegitration() /// verify that the taskawaiter.UnsafeOnCompleted is invoked /// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99500", TestPlatforms.Browser)] public static void TaskAwaiter() { ManualResetEvent mre = new ManualResetEvent(false); diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/AsyncEnumerableToBlockingEnumerableTests.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/AsyncEnumerableToBlockingEnumerableTests.cs index 0692aedb514f9..048025c5c947a 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/AsyncEnumerableToBlockingEnumerableTests.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/AsyncEnumerableToBlockingEnumerableTests.cs @@ -70,6 +70,7 @@ static async IAsyncEnumerable CreateSourceEnumerable() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void AsyncEnumerableWithDelays() { var source = new InstrumentedAsyncEnumerable(CreateSourceEnumerable()); @@ -104,6 +105,7 @@ static async IAsyncEnumerable CreateSourceEnumerable() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void AsyncEnumerableWithException() { var source = new InstrumentedAsyncEnumerable(CreateSourceEnumerable()); @@ -132,6 +134,7 @@ static async IAsyncEnumerable CreateSourceEnumerable() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void AsyncEnumerableWithCancellation() { var source = new InstrumentedAsyncEnumerable(CreateSourceEnumerable()); diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskContinueWithTests.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskContinueWithTests.cs index 2800a5e9e24c4..4cb9d47ca4ec8 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskContinueWithTests.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskContinueWithTests.cs @@ -1076,6 +1076,7 @@ public static void RunContinuationCancelTest_State() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void TestNoDeadlockOnContinueWith() { Debug.WriteLine("TestNoDeadlockOnContinueWith: shouldn't deadlock if it passes."); @@ -1255,6 +1256,7 @@ public static void LongContinuationChain_Unwrap_DoesNotStackOverflow() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void LongContinuationChain_Await_DoesNotStackOverflow() { const int DiveDepth = 12_000; diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 99d7be45b1077..27f776a8d3c6f 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -914,6 +914,7 @@ public readonly partial struct JsonSchemaExporterContext { private readonly object _dummy; private readonly int _dummyPrimitive; + public System.Text.Json.Serialization.Metadata.JsonTypeInfo? BaseTypeInfo { get { throw null; } } public System.Text.Json.Serialization.Metadata.JsonPropertyInfo? PropertyInfo { get { throw null; } } public System.ReadOnlySpan Path { get { throw null; } } public System.Text.Json.Serialization.Metadata.JsonTypeInfo TypeInfo { get { throw null; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index a4f9cd3594a47..692a34b3e89d9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -68,7 +68,7 @@ private static JsonSchema MapJsonSchemaCore( JsonPropertyInfo? propertyInfo = null, JsonConverter? customConverter = null, JsonNumberHandling? customNumberHandling = null, - Type? parentPolymorphicType = null, + JsonTypeInfo? parentPolymorphicTypeInfo = null, bool parentPolymorphicTypeContainsTypesWithoutDiscriminator = false, bool parentPolymorphicTypeIsNonNullable = false, KeyValuePair? typeDiscriminator = null, @@ -90,7 +90,7 @@ private static JsonSchema MapJsonSchemaCore( return CompleteSchema(ref state, schema); } - if (parentPolymorphicType is null && typeInfo.PolymorphismOptions is { DerivedTypes.Count: > 0 } polyOptions) + if (parentPolymorphicTypeInfo is null && typeInfo.PolymorphismOptions is { DerivedTypes.Count: > 0 } polyOptions) { // This is the base type of a polymorphic type hierarchy. The schema for this type // will include an "anyOf" property with the schemas for all derived types. @@ -133,7 +133,7 @@ private static JsonSchema MapJsonSchemaCore( JsonSchema derivedSchema = MapJsonSchemaCore( ref state, derivedTypeInfo, - parentPolymorphicType: typeInfo.Type, + parentPolymorphicTypeInfo: typeInfo, typeDiscriminator: derivedTypeDiscriminator, parentPolymorphicTypeContainsTypesWithoutDiscriminator: containsTypesWithoutDiscriminator, parentPolymorphicTypeIsNonNullable: propertyInfo is { IsGetNullable: false, IsSetNullable: false }, @@ -372,7 +372,7 @@ JsonSchema CompleteSchema(ref GenerationState state, JsonSchema schema) if (state.ExporterOptions.TransformSchemaNode != null) { // Prime the schema for invocation by the JsonNode transformer. - schema.ExporterContext = state.CreateContext(typeInfo, propertyInfo); + schema.ExporterContext = state.CreateContext(typeInfo, propertyInfo, parentPolymorphicTypeInfo); } return schema; @@ -454,9 +454,9 @@ public void PopGeneratedType() _generationStack.RemoveAt(_generationStack.Count - 1); } - public JsonSchemaExporterContext CreateContext(JsonTypeInfo typeInfo, JsonPropertyInfo? propertyInfo) + public JsonSchemaExporterContext CreateContext(JsonTypeInfo typeInfo, JsonPropertyInfo? propertyInfo, JsonTypeInfo? baseTypeInfo) { - return new JsonSchemaExporterContext(typeInfo, propertyInfo, _currentPath.ToArray()); + return new JsonSchemaExporterContext(typeInfo, propertyInfo, baseTypeInfo, _currentPath.ToArray()); } private static string FormatJsonPointer(List currentPathList, int depth) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporterContext.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporterContext.cs index f8143e347656c..fc9a0c0be97dd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporterContext.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporterContext.cs @@ -12,10 +12,15 @@ public readonly struct JsonSchemaExporterContext { private readonly string[] _path; - internal JsonSchemaExporterContext(JsonTypeInfo typeInfo, JsonPropertyInfo? propertyInfo, string[] path) + internal JsonSchemaExporterContext( + JsonTypeInfo typeInfo, + JsonPropertyInfo? propertyInfo, + JsonTypeInfo? baseTypeInfo, + string[] path) { TypeInfo = typeInfo; PropertyInfo = propertyInfo; + BaseTypeInfo = baseTypeInfo; _path = path; } @@ -29,6 +34,11 @@ internal JsonSchemaExporterContext(JsonTypeInfo typeInfo, JsonPropertyInfo? prop /// public JsonPropertyInfo? PropertyInfo { get; } + /// + /// Gets the for polymorphic base type if the schema is being generated for a derived type. + /// + public JsonTypeInfo? BaseTypeInfo { get; } + /// /// The path to the current node in the generated JSON schema. /// diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.cs index 042e78ad2bd6e..6dcdd1e89edd5 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.cs @@ -112,6 +112,39 @@ public void JsonSerializerOptions_SmallMaxDepth_ThrowsInvalidOperationException( Assert.Contains("depth", ex.Message); } + [Theory] + [InlineData(typeof(int))] + [InlineData(typeof(string))] + [InlineData(typeof(SimplePoco))] + [InlineData(typeof(DiscriminatedUnion))] + public void JsonSchemaExporterContext_BaseTypeInfo_ReturnsExpectedValue(Type type) + { + bool isCallbackInvoked = false; + JsonSerializerOptions options = Serializer.DefaultOptions; + JsonSchemaExporterOptions exporterOptions = new() + { + TransformSchemaNode = (ctx, node) => + { + if (typeof(DiscriminatedUnion).IsAssignableFrom(ctx.TypeInfo.Type) && + typeof(DiscriminatedUnion) != ctx.TypeInfo.Type) + { + Assert.NotNull(ctx.BaseTypeInfo); + Assert.Equal(typeof(DiscriminatedUnion), ctx.BaseTypeInfo.Type); + } + else + { + Assert.Null(ctx.BaseTypeInfo); + } + + isCallbackInvoked = true; + return node; + } + }; + + options.GetJsonSchemaAsNode(type, exporterOptions); + Assert.True(isCallbackInvoked); + } + [Fact] public void ReferenceHandlePreserve_Enabled_ThrowsNotSupportedException() { diff --git a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs index c96ad22b47b53..cc3b5b082fc89 100644 --- a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs +++ b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs @@ -1251,6 +1251,89 @@ async Task StartClientAsync() }).Dispose(); } + [ConditionalFact(nameof(IsThreadingAndRemoteExecutorSupported))] + public static void PrioritizationExperimentConfigVarTest() + { + // Avoid contaminating the main process' environment + RemoteExecutor.Invoke(() => + { + // The actual test process below will inherit the config var + Environment.SetEnvironmentVariable("DOTNET_ThreadPool_PrioritizationExperiment", "1"); + + RemoteExecutor.Invoke(() => + { + const int WorkItemCountPerKind = 100; + + int completedWorkItemCount = 0; + var allWorkItemsCompleted = new AutoResetEvent(false); + Action workItem = _ => + { + if (Interlocked.Increment(ref completedWorkItemCount) == WorkItemCountPerKind * 3) + { + allWorkItemsCompleted.Set(); + } + }; + + var startTest = new ManualResetEvent(false); + + var t = new Thread(() => + { + // Enqueue global work from a non-thread-pool thread + + startTest.CheckedWait(); + + for (int i = 0; i < WorkItemCountPerKind; i++) + { + ThreadPool.UnsafeQueueUserWorkItem(workItem, 0, preferLocal: false); + } + }); + t.IsBackground = true; + t.Start(); + + ThreadPool.UnsafeQueueUserWorkItem( + _ => + { + // Enqueue global work from a thread pool worker thread + + startTest.CheckedWait(); + + for (int i = 0; i < WorkItemCountPerKind; i++) + { + ThreadPool.UnsafeQueueUserWorkItem(workItem, 0, preferLocal: false); + } + }, + 0, + preferLocal: false); + + t = new Thread(() => + { + // Enqueue local work from thread pool worker threads + + Assert.True(WorkItemCountPerKind / 10 * 10 == WorkItemCountPerKind); + Action localWorkItemEnqueuer = _ => + { + for (int i = 0; i < WorkItemCountPerKind / 10; i++) + { + ThreadPool.UnsafeQueueUserWorkItem(workItem, 0, preferLocal: true); + } + }; + + startTest.CheckedWait(); + + for (int i = 0; i < 10; i++) + { + ThreadPool.UnsafeQueueUserWorkItem(localWorkItemEnqueuer, 0, preferLocal: false); + } + }); + t.IsBackground = true; + t.Start(); + + startTest.Set(); + allWorkItemsCompleted.CheckedWait(); + }).Dispose(); + }).Dispose(); + } + public static bool IsThreadingAndRemoteExecutorSupported => PlatformDetection.IsThreadingSupported && RemoteExecutor.IsSupported; diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 6b06baeb76034..6d769c4297fae 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -661,6 +661,7 @@ private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/96191", TestPlatforms.Browser)] public void NamedMutex_ThreadExitDisposeRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); diff --git a/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs b/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs index 7aabd01c39f1e..faac4d9cf9f85 100644 --- a/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs +++ b/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs @@ -90,6 +90,7 @@ public static void RunSemaphoreSlimTest1_WaitAsync() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/99519", TestPlatforms.Browser)] public static void RunSemaphoreSlimTest1_WaitAsync_NegativeCases() { // Invalid timeout diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.sln b/src/mono/System.Private.CoreLib/System.Private.CoreLib.sln index d23b2e284f5bc..0b525b7c00d62 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.sln +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28902.138 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35017.193 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "System.Private.CoreLib.csproj", "{8FBEB036-6F52-464C-8BC9-B0B5F18262A6}" EndProject @@ -8,29 +8,77 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "System.Private.CoreLib.Shar EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "..\..\libraries\System.Private.CoreLib\gen\System.Private.CoreLib.Generators.csproj", "{A4CD9C83-5937-46B7-A1F2-1990F5B938E7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{59C812D5-8154-44CC-A9F7-85C5719BC53A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{07D181B4-A6A5-4B3B-8D65-A55E40FFE7CF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{353DC895-E827-4EB4-92B6-28A7446F5765}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{8ACD32CC-D728-4668-8D24-EF6787828B3F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{69C4C1F3-CE1E-44B6-BE20-0DEDF47EC9CC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{49D59E02-3010-4140-97FF-903D31DF9224}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\..\libraries\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{663D1F21-B4B4-4BDF-A95F-69933D072036}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\..\libraries\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{69B56E13-3BAB-4F0E-9DD2-DC805244BA42}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\libraries\System.Private.CoreLib\ref\System.Private.CoreLib.csproj", "{1AAF4103-8688-4ABF-B347-EE60E35109BD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.CodeFixProvider", "..\..\tools\illink\src\ILLink.CodeFix\ILLink.CodeFixProvider.csproj", "{9C2717EE-3D47-4F89-97D5-0873FFE0B987}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.RoslynAnalyzer", "..\..\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj", "{650A6AE8-0B76-453B-A785-F3DD0458A3BC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\ref\Mono.Linker.csproj", "{5F4290E3-9282-43F4-8A2E-EEA7665CC208}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILLink.Tasks", "..\..\tools\illink\src\ILLink.Tasks\ILLink.Tasks.csproj", "{648B364B-C1F1-44BC-B22B-288DA0898DCA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker", "..\..\tools\illink\src\linker\Mono.Linker.csproj", "{98B8A25B-AF88-4920-92B4-669C798F7A38}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.DependencyAnalysisFramework", "..\..\coreclr\tools\aot\ILCompiler.DependencyAnalysisFramework\ILCompiler.DependencyAnalysisFramework.csproj", "{C575D3FA-B9D8-4683-9EFB-C400AE315D35}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ILLink.Shared", "..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.shproj", "{FF598E93-8E9E-4091-9F50-61A7572663AE}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{8fbeb036-6f52-464c-8bc9-b0b5f18262a6}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|amd64 = Checked|amd64 Checked|Any CPU = Checked|Any CPU Checked|arm = Checked|arm Checked|arm64 = Checked|arm64 + Checked|armv6 = Checked|armv6 + Checked|ppc64le = Checked|ppc64le + Checked|riscv64 = Checked|riscv64 + Checked|s390x = Checked|s390x + Checked|wasm = Checked|wasm Checked|wasm32 = Checked|wasm32 + Checked|x64 = Checked|x64 Checked|x86 = Checked|x86 Debug|amd64 = Debug|amd64 Debug|Any CPU = Debug|Any CPU Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 + Debug|armv6 = Debug|armv6 + Debug|ppc64le = Debug|ppc64le + Debug|riscv64 = Debug|riscv64 + Debug|s390x = Debug|s390x + Debug|wasm = Debug|wasm Debug|wasm32 = Debug|wasm32 + Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|amd64 = Release|amd64 Release|Any CPU = Release|Any CPU Release|arm = Release|arm Release|arm64 = Release|arm64 + Release|armv6 = Release|armv6 + Release|ppc64le = Release|ppc64le + Release|riscv64 = Release|riscv64 + Release|s390x = Release|s390x + Release|wasm = Release|wasm Release|wasm32 = Release|wasm32 + Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution @@ -41,7 +89,19 @@ Global {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|arm.Build.0 = Checked|arm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|arm64.ActiveCfg = Checked|arm64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|arm64.Build.0 = Checked|arm64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|armv6.ActiveCfg = Checked|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|armv6.Build.0 = Checked|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|ppc64le.ActiveCfg = Checked|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|ppc64le.Build.0 = Checked|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|riscv64.ActiveCfg = Checked|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|riscv64.Build.0 = Checked|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|s390x.ActiveCfg = Checked|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|s390x.Build.0 = Checked|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|wasm.ActiveCfg = Checked|wasm + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|wasm.Build.0 = Checked|wasm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|wasm32.ActiveCfg = Checked|x86 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|x64.ActiveCfg = Checked|x64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|x64.Build.0 = Checked|x64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|x86.ActiveCfg = Checked|x86 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Checked|x86.Build.0 = Checked|x86 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|amd64.ActiveCfg = Debug|x64 @@ -51,7 +111,19 @@ Global {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|arm.Build.0 = Debug|arm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|arm64.ActiveCfg = Debug|arm64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|arm64.Build.0 = Debug|arm64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|armv6.ActiveCfg = Debug|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|armv6.Build.0 = Debug|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|ppc64le.ActiveCfg = Debug|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|ppc64le.Build.0 = Debug|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|riscv64.ActiveCfg = Debug|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|riscv64.Build.0 = Debug|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|s390x.ActiveCfg = Debug|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|s390x.Build.0 = Debug|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|wasm.ActiveCfg = Debug|wasm + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|wasm.Build.0 = Debug|wasm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|wasm32.ActiveCfg = Debug|x86 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|x64.ActiveCfg = Debug|x64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|x64.Build.0 = Debug|x64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|x86.ActiveCfg = Debug|x86 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Debug|x86.Build.0 = Debug|x86 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|amd64.ActiveCfg = Release|x64 @@ -61,7 +133,19 @@ Global {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|arm.Build.0 = Release|arm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|arm64.ActiveCfg = Release|arm64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|arm64.Build.0 = Release|arm64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|armv6.ActiveCfg = Release|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|armv6.Build.0 = Release|armv6 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|ppc64le.ActiveCfg = Release|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|ppc64le.Build.0 = Release|ppc64le + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|riscv64.ActiveCfg = Release|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|riscv64.Build.0 = Release|riscv64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|s390x.ActiveCfg = Release|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|s390x.Build.0 = Release|s390x + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|wasm.ActiveCfg = Release|wasm + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|wasm.Build.0 = Release|wasm {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|wasm32.ActiveCfg = Release|x86 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|x64.ActiveCfg = Release|x64 + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|x64.Build.0 = Release|x64 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|x86.ActiveCfg = Release|x86 {8FBEB036-6F52-464C-8BC9-B0B5F18262A6}.Release|x86.Build.0 = Release|x86 {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|amd64.ActiveCfg = Debug|Any CPU @@ -72,8 +156,20 @@ Global {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|arm.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|arm64.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|arm64.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|armv6.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|armv6.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|ppc64le.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|ppc64le.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|riscv64.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|riscv64.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|s390x.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|s390x.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|wasm.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|wasm.Build.0 = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|wasm32.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|wasm32.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|x64.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|x64.Build.0 = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|x86.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Checked|x86.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|amd64.ActiveCfg = Debug|Any CPU @@ -84,8 +180,20 @@ Global {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|arm.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|arm64.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|arm64.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|armv6.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|armv6.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|ppc64le.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|riscv64.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|s390x.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|s390x.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|wasm.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|wasm.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|wasm32.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|wasm32.Build.0 = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|x64.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|x86.ActiveCfg = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Debug|x86.Build.0 = Debug|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|amd64.ActiveCfg = Release|Any CPU @@ -96,15 +204,700 @@ Global {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|arm.Build.0 = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|arm64.ActiveCfg = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|arm64.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|armv6.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|armv6.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|ppc64le.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|ppc64le.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|riscv64.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|riscv64.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|s390x.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|s390x.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|wasm.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|wasm.Build.0 = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|wasm32.ActiveCfg = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|wasm32.Build.0 = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|x64.ActiveCfg = Release|Any CPU + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|x64.Build.0 = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|x86.ActiveCfg = Release|Any CPU {A4CD9C83-5937-46B7-A1F2-1990F5B938E7}.Release|x86.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|amd64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|amd64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|Any CPU.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|arm.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|arm.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|arm64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|arm64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|armv6.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|armv6.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|ppc64le.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|riscv64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|s390x.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|s390x.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|wasm.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|wasm.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|wasm32.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|x64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|x64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|x86.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Checked|x86.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|amd64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|amd64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|Any CPU.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|arm.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|arm.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|arm64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|arm64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|armv6.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|armv6.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|ppc64le.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|riscv64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|s390x.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|s390x.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|wasm.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|wasm.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|wasm32.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|x64.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|x64.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|x86.ActiveCfg = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Debug|x86.Build.0 = Debug|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|amd64.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|amd64.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|Any CPU.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|Any CPU.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|arm.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|arm.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|arm64.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|arm64.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|armv6.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|armv6.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|ppc64le.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|ppc64le.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|riscv64.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|riscv64.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|s390x.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|s390x.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|wasm.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|wasm.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|wasm32.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|wasm32.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|x64.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|x64.Build.0 = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|x86.ActiveCfg = Release|Any CPU + {663D1F21-B4B4-4BDF-A95F-69933D072036}.Release|x86.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|amd64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|amd64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|Any CPU.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|arm.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|arm.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|arm64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|arm64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|armv6.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|armv6.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|ppc64le.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|riscv64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|s390x.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|s390x.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|wasm.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|wasm.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|wasm32.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|x64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|x64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|x86.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Checked|x86.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|amd64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|amd64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|arm.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|arm.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|arm64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|arm64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|armv6.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|armv6.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|ppc64le.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|riscv64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|s390x.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|s390x.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|wasm.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|wasm.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|wasm32.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|x64.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|x64.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|x86.ActiveCfg = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Debug|x86.Build.0 = Debug|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|amd64.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|amd64.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|Any CPU.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|arm.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|arm.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|arm64.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|arm64.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|armv6.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|armv6.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|ppc64le.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|ppc64le.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|riscv64.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|riscv64.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|s390x.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|s390x.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|wasm.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|wasm.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|wasm32.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|wasm32.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|x64.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|x64.Build.0 = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|x86.ActiveCfg = Release|Any CPU + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42}.Release|x86.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|amd64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|amd64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|Any CPU.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|arm.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|arm.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|arm64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|arm64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|armv6.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|armv6.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|ppc64le.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|riscv64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|s390x.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|s390x.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|wasm.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|wasm.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|wasm32.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|x64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|x64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|x86.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Checked|x86.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|amd64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|amd64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|arm.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|arm.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|arm64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|arm64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|armv6.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|armv6.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|ppc64le.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|riscv64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|s390x.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|s390x.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|wasm.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|wasm.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|wasm32.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|x64.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|x64.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|x86.ActiveCfg = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Debug|x86.Build.0 = Debug|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|amd64.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|amd64.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|Any CPU.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|arm.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|arm.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|arm64.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|arm64.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|armv6.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|armv6.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|ppc64le.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|ppc64le.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|riscv64.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|riscv64.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|s390x.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|s390x.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|wasm.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|wasm.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|wasm32.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|wasm32.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|x64.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|x64.Build.0 = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|x86.ActiveCfg = Release|Any CPU + {1AAF4103-8688-4ABF-B347-EE60E35109BD}.Release|x86.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|amd64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|amd64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|Any CPU.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|arm.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|arm.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|arm64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|arm64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|armv6.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|armv6.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|ppc64le.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|riscv64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|s390x.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|s390x.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|wasm.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|wasm.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|wasm32.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|x64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|x64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|x86.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Checked|x86.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|amd64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|amd64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|arm.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|arm.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|arm64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|arm64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|armv6.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|armv6.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|ppc64le.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|riscv64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|s390x.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|s390x.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|wasm.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|wasm.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|wasm32.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|x64.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|x64.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Debug|x86.Build.0 = Debug|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|amd64.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|amd64.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|Any CPU.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|arm.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|arm.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|arm64.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|arm64.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|armv6.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|armv6.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|ppc64le.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|ppc64le.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|riscv64.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|riscv64.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|s390x.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|s390x.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|wasm.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|wasm.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|wasm32.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|wasm32.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|x64.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|x64.Build.0 = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|x86.ActiveCfg = Release|Any CPU + {9C2717EE-3D47-4F89-97D5-0873FFE0B987}.Release|x86.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|amd64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|amd64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|Any CPU.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|arm.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|arm.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|arm64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|arm64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|armv6.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|armv6.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|ppc64le.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|riscv64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|s390x.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|s390x.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|wasm.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|wasm.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|wasm32.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|x64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|x64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|x86.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Checked|x86.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|amd64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|amd64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|arm.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|arm.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|arm64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|arm64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|armv6.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|armv6.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|ppc64le.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|riscv64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|s390x.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|s390x.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|wasm.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|wasm.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|wasm32.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|x64.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|x64.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|x86.ActiveCfg = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Debug|x86.Build.0 = Debug|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|amd64.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|amd64.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|Any CPU.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|arm.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|arm.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|arm64.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|arm64.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|armv6.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|armv6.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|ppc64le.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|ppc64le.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|riscv64.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|riscv64.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|s390x.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|s390x.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|wasm.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|wasm.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|wasm32.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|wasm32.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|x64.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|x64.Build.0 = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|x86.ActiveCfg = Release|Any CPU + {650A6AE8-0B76-453B-A785-F3DD0458A3BC}.Release|x86.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|amd64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|amd64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|Any CPU.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|arm.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|arm.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|arm64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|arm64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|armv6.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|armv6.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|ppc64le.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|riscv64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|s390x.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|s390x.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|wasm.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|wasm.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|wasm32.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|x64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|x64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|x86.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Checked|x86.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|amd64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|amd64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|arm.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|arm.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|arm64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|arm64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|armv6.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|armv6.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|ppc64le.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|riscv64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|s390x.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|s390x.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|wasm.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|wasm.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|wasm32.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|x64.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|x64.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|x86.ActiveCfg = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Debug|x86.Build.0 = Debug|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|amd64.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|amd64.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|Any CPU.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|arm.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|arm.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|arm64.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|arm64.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|armv6.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|armv6.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|ppc64le.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|ppc64le.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|riscv64.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|riscv64.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|s390x.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|s390x.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|wasm.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|wasm.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|wasm32.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|wasm32.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|x64.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|x64.Build.0 = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|x86.ActiveCfg = Release|Any CPU + {5F4290E3-9282-43F4-8A2E-EEA7665CC208}.Release|x86.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|amd64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|amd64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|Any CPU.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|arm.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|arm.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|arm64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|arm64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|armv6.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|armv6.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|ppc64le.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|riscv64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|s390x.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|s390x.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|wasm.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|wasm.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|wasm32.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|x64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|x64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|x86.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Checked|x86.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|amd64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|amd64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|arm.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|arm.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|arm64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|arm64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|armv6.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|armv6.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|ppc64le.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|riscv64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|s390x.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|s390x.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|wasm.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|wasm.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|wasm32.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|x64.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|x64.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|x86.ActiveCfg = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Debug|x86.Build.0 = Debug|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|amd64.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|amd64.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|Any CPU.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|arm.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|arm.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|arm64.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|arm64.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|armv6.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|armv6.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|ppc64le.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|ppc64le.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|riscv64.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|riscv64.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|s390x.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|s390x.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|wasm.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|wasm.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|wasm32.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|wasm32.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|x64.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|x64.Build.0 = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|x86.ActiveCfg = Release|Any CPU + {648B364B-C1F1-44BC-B22B-288DA0898DCA}.Release|x86.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|amd64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|amd64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|Any CPU.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|arm.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|arm.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|arm64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|arm64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|armv6.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|armv6.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|ppc64le.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|ppc64le.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|riscv64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|riscv64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|s390x.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|s390x.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|wasm.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|wasm.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|wasm32.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|wasm32.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|x64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|x64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|x86.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Checked|x86.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|amd64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|amd64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|arm.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|arm.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|arm64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|arm64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|armv6.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|armv6.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|ppc64le.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|ppc64le.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|riscv64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|riscv64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|s390x.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|s390x.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|wasm.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|wasm.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|wasm32.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|wasm32.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|x64.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|x64.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|x86.ActiveCfg = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Debug|x86.Build.0 = Debug|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|amd64.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|amd64.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|Any CPU.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|arm.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|arm.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|arm64.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|arm64.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|armv6.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|armv6.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|ppc64le.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|ppc64le.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|riscv64.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|riscv64.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|s390x.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|s390x.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|wasm.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|wasm.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|wasm32.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|wasm32.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|x64.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|x64.Build.0 = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|x86.ActiveCfg = Release|Any CPU + {98B8A25B-AF88-4920-92B4-669C798F7A38}.Release|x86.Build.0 = Release|Any CPU + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|amd64.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|amd64.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|Any CPU.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|Any CPU.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|arm.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|arm.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|arm64.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|arm64.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|armv6.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|armv6.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|ppc64le.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|ppc64le.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|riscv64.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|riscv64.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|s390x.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|s390x.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|wasm.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|wasm.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|wasm32.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|wasm32.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|x64.ActiveCfg = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|x64.Build.0 = Checked|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|x86.ActiveCfg = Checked|x86 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Checked|x86.Build.0 = Checked|x86 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|amd64.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|amd64.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|Any CPU.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|Any CPU.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|arm.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|arm.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|arm64.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|arm64.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|armv6.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|armv6.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|ppc64le.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|ppc64le.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|riscv64.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|riscv64.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|s390x.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|s390x.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|wasm.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|wasm.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|wasm32.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|wasm32.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|x64.ActiveCfg = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|x64.Build.0 = Debug|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|x86.ActiveCfg = Debug|x86 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Debug|x86.Build.0 = Debug|x86 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|amd64.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|amd64.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|Any CPU.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|Any CPU.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|arm.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|arm.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|arm64.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|arm64.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|armv6.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|armv6.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|ppc64le.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|ppc64le.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|riscv64.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|riscv64.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|s390x.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|s390x.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|wasm.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|wasm.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|wasm32.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|wasm32.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|x64.ActiveCfg = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|x64.Build.0 = Release|x64 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|x86.ActiveCfg = Release|x86 + {C575D3FA-B9D8-4683-9EFB-C400AE315D35}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {8FBEB036-6F52-464C-8BC9-B0B5F18262A6} = {353DC895-E827-4EB4-92B6-28A7446F5765} + {845C8B26-350B-4E63-BD11-2C8150444E28} = {353DC895-E827-4EB4-92B6-28A7446F5765} + {A4CD9C83-5937-46B7-A1F2-1990F5B938E7} = {59C812D5-8154-44CC-A9F7-85C5719BC53A} + {69C4C1F3-CE1E-44B6-BE20-0DEDF47EC9CC} = {8ACD32CC-D728-4668-8D24-EF6787828B3F} + {49D59E02-3010-4140-97FF-903D31DF9224} = {8ACD32CC-D728-4668-8D24-EF6787828B3F} + {4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6} = {8ACD32CC-D728-4668-8D24-EF6787828B3F} + {663D1F21-B4B4-4BDF-A95F-69933D072036} = {59C812D5-8154-44CC-A9F7-85C5719BC53A} + {69B56E13-3BAB-4F0E-9DD2-DC805244BA42} = {59C812D5-8154-44CC-A9F7-85C5719BC53A} + {1AAF4103-8688-4ABF-B347-EE60E35109BD} = {07D181B4-A6A5-4B3B-8D65-A55E40FFE7CF} + {9C2717EE-3D47-4F89-97D5-0873FFE0B987} = {69C4C1F3-CE1E-44B6-BE20-0DEDF47EC9CC} + {650A6AE8-0B76-453B-A785-F3DD0458A3BC} = {69C4C1F3-CE1E-44B6-BE20-0DEDF47EC9CC} + {5F4290E3-9282-43F4-8A2E-EEA7665CC208} = {49D59E02-3010-4140-97FF-903D31DF9224} + {648B364B-C1F1-44BC-B22B-288DA0898DCA} = {4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6} + {98B8A25B-AF88-4920-92B4-669C798F7A38} = {4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6} + {C575D3FA-B9D8-4683-9EFB-C400AE315D35} = {4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6} + {FF598E93-8E9E-4091-9F50-61A7572663AE} = {4AE3D340-9B0C-4B86-94B7-A4B44E0AAAB6} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {48FC8980-C27D-47CB-B4A6-BFF2AC21D716} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{650a6ae8-0b76-453b-a785-f3dd0458a3bc}*SharedItemsImports = 5 + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{8fbeb036-6f52-464c-8bc9-b0b5f18262a6}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{98b8a25b-af88-4920-92b4-669c798f7a38}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 + EndGlobalSection EndGlobal diff --git a/src/mono/browser/runtime/cwraps.ts b/src/mono/browser/runtime/cwraps.ts index 794682b7e6c29..7cbf1cdec962c 100644 --- a/src/mono/browser/runtime/cwraps.ts +++ b/src/mono/browser/runtime/cwraps.ts @@ -53,7 +53,7 @@ const fn_signatures: SigLine[] = [ [true, "mono_wasm_load_icu_data", "number", ["number"]], [false, "mono_wasm_add_assembly", "number", ["string", "number", "number"]], [true, "mono_wasm_add_satellite_assembly", "void", ["string", "string", "number", "number"]], - [false, "mono_wasm_load_runtime", null, ["string", "number"]], + [false, "mono_wasm_load_runtime", null, ["number"]], [true, "mono_wasm_change_debugger_log_level", "void", ["number"]], [true, "mono_wasm_assembly_load", "number", ["string"]], diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 40664b86a7d42..0e534a3a8d528 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -159,6 +159,8 @@ 52428800 $(WasiClang) + <_WasiAfterRuntimeLoadedDeclarations>@(WasiAfterRuntimeLoadedDeclarations, ' ') + <_WasiAfterRuntimeLoadedCalls>@(WasiAfterRuntimeLoadedCalls, ' ') @@ -204,10 +206,10 @@ <_WasiClangCFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> - <_WasiClangCFlags Condition="'@(WasiAfterRuntimeLoadedDeclarations)' != ''" - Include="-D WASI_AFTER_RUNTIME_LOADED_DECLARATIONS="@(WasiAfterRuntimeLoadedDeclarations, ' ')"" /> - <_WasiClangCFlags Condition="'@(WasiAfterRuntimeLoadedCalls)' != ''" - Include="-D WASI_AFTER_RUNTIME_LOADED_CALLS="@(WasiAfterRuntimeLoadedCalls, ' ')"" /> + <_WasiClangCFlags Condition="'$(_WasiAfterRuntimeLoadedDeclarations)' != ''" + Include="-D WASI_AFTER_RUNTIME_LOADED_DECLARATIONS="$(_WasiAfterRuntimeLoadedDeclarations)"" /> + <_WasiClangCFlags Condition="'$(_WasiAfterRuntimeLoadedCalls)' != ''" + Include="-D WASI_AFTER_RUNTIME_LOADED_CALLS="$(_WasiAfterRuntimeLoadedCalls)"" /> <_WasiClangLDFlags Include="$(WasiClangLinkOptimizationFlag)" /> <_WasiClangLDFlags Include="@(_WasiClangCommonFlags)" /> diff --git a/src/mono/wasm/host/BrowserHost.cs b/src/mono/wasm/host/BrowserHost.cs index cbe160eeb0214..598da1174f7db 100644 --- a/src/mono/wasm/host/BrowserHost.cs +++ b/src/mono/wasm/host/BrowserHost.cs @@ -61,12 +61,6 @@ private async Task RunAsync(ILoggerFactory loggerFactory, CancellationToken toke envVars[kvp.Key] = kvp.Value; } - foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) - { - if (de.Key is not null && de.Value is not null) - envVars[(string)de.Key] = (string)de.Value; - } - var runArgsJson = new RunArgumentsJson(applicationArguments: _args.AppArgs, runtimeArguments: _args.CommonConfig.RuntimeArguments, environmentVariables: envVars, diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt index a277d5df3e5bd..f87db8a8c75b6 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt @@ -33,7 +33,7 @@ set(NATIVECRYPTO_SOURCES add_library(System.Security.Cryptography.Native.Android SHARED - ${NATIVECRYPTO_SOURCES} + ${NATIVECRYPTO_SOURCES} pal_jni_onload.c ${VERSION_FILE_PATH} ) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c index 243dbd1d9466d..ee31a3ac58d64 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c @@ -689,11 +689,10 @@ int GetEnumAsInt(JNIEnv *env, jobject enumObj) return value; } -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved) +jint AndroidCryptoNative_InitLibraryOnLoad (JavaVM *vm, void *reserved) { (void)reserved; - LOG_INFO("JNI_OnLoad in pal_jni.c"); + LOG_DEBUG("%s in %s", __PRETTY_FUNCTION__, __FILE__); gJvm = vm; JNIEnv* env = GetJNIEnv(); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h index 79bc888224629..5f7d7c002c414 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h @@ -605,6 +605,11 @@ jfieldID GetField(JNIEnv *env, bool isStatic, jclass klass, const char* name, co jfieldID GetOptionalField(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig) ARGS_NON_NULL_ALL; JNIEnv* GetJNIEnv(void); +// This is supposed to be called by embedders who link the **static** archive of this library. +// The function must be called from the embedder's `JNI_OnLoad` function prior to using any +// APIs in this library. +jint AndroidCryptoNative_InitLibraryOnLoad (JavaVM *vm, void *reserved); + int GetEnumAsInt(JNIEnv *env, jobject enumObj) ARGS_NON_NULL_ALL; void* xmalloc (size_t size) __mallocfunc __BIONIC_ALLOC_SIZE(1) __wur; diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni_onload.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni_onload.c new file mode 100644 index 0000000000000..e2ecc9f3b8aa5 --- /dev/null +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni_onload.c @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_jni.h" + +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) +{ + return AndroidCryptoNative_InitLibraryOnLoad (vm, reserved); +} diff --git a/src/native/managed/cdacreader/src/Contracts/Exception.cs b/src/native/managed/cdacreader/src/Contracts/Exception.cs index c06a6984db898..2ad3d10faeb65 100644 --- a/src/native/managed/cdacreader/src/Contracts/Exception.cs +++ b/src/native/managed/cdacreader/src/Contracts/Exception.cs @@ -5,6 +5,16 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; +internal record struct ExceptionData( + TargetPointer Message, + TargetPointer InnerException, + TargetPointer StackTrace, + TargetPointer WatsonBuckets, + TargetPointer StackTraceString, + TargetPointer RemoteStackTraceString, + int HResult, + int XCode); + internal interface IException : IContract { static string IContract.Name { get; } = nameof(Exception); @@ -17,7 +27,8 @@ static IContract IContract.Create(Target target, int version) }; } - public virtual TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) => throw new NotImplementedException(); + public virtual TargetPointer GetNestedExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) => throw new NotImplementedException(); + public virtual ExceptionData GetExceptionData(TargetPointer managedException) => throw new NotImplementedException(); } internal readonly struct Exception : IException diff --git a/src/native/managed/cdacreader/src/Contracts/Exception_1.cs b/src/native/managed/cdacreader/src/Contracts/Exception_1.cs index 57249576719ee..faadb768cc8d8 100644 --- a/src/native/managed/cdacreader/src/Contracts/Exception_1.cs +++ b/src/native/managed/cdacreader/src/Contracts/Exception_1.cs @@ -14,10 +14,24 @@ internal Exception_1(Target target) _target = target; } - TargetPointer IException.GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) + TargetPointer IException.GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo) { - Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd(exception); - nextNestedException = exceptionInfo.PreviousNestedInfo; + Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd(exceptionInfoAddr); + nextNestedExceptionInfo = exceptionInfo.PreviousNestedInfo; return exceptionInfo.ThrownObject.Object; } + + ExceptionData IException.GetExceptionData(TargetPointer exceptionAddr) + { + Data.Exception exception = _target.ProcessedData.GetOrAdd(exceptionAddr); + return new ExceptionData( + exception.Message, + exception.InnerException, + exception.StackTrace, + exception.WatsonBuckets, + exception.StackTraceString, + exception.RemoteStackTraceString, + exception.HResult, + exception.XCode); + } } diff --git a/src/native/managed/cdacreader/src/Contracts/Loader.cs b/src/native/managed/cdacreader/src/Contracts/Loader.cs new file mode 100644 index 0000000000000..e30633fdf2a25 --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/Loader.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly struct ModuleHandle +{ + internal ModuleHandle(TargetPointer address) + { + Address = address; + } + + internal TargetPointer Address { get; } +} + +[Flags] +internal enum ModuleFlags +{ + EditAndContinue = 0x00000008, // Edit and Continue is enabled for this module + ReflectionEmit = 0x00000040, // Reflection.Emit was used to create this module +} + +internal record struct ModuleLookupTables( + TargetPointer FieldDefToDesc, + TargetPointer ManifestModuleReferences, + TargetPointer MemberRefToDesc, + TargetPointer MethodDefToDesc, + TargetPointer TypeDefToMethodTable, + TargetPointer TypeRefToMethodTable); + +internal interface ILoader : IContract +{ + static string IContract.Name => nameof(Loader); + static IContract IContract.Create(Target target, int version) + { + return version switch + { + 1 => new Loader_1(target), + _ => default(Loader), + }; + } + + public virtual ModuleHandle GetModuleHandle(TargetPointer modulePointer) => throw new NotImplementedException(); + + public virtual TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException(); + public virtual ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException(); + public virtual TargetPointer GetLoaderAllocator(ModuleHandle handle) => throw new NotImplementedException(); + public virtual TargetPointer GetThunkHeap(ModuleHandle handle) => throw new NotImplementedException(); + + public virtual TargetPointer GetILBase(ModuleHandle handle) => throw new NotImplementedException(); + public virtual TargetPointer GetMetadataAddress(ModuleHandle handle, out ulong size) => throw new NotImplementedException(); + + public virtual ModuleLookupTables GetLookupTables(ModuleHandle handle) => throw new NotImplementedException(); +} + +internal readonly struct Loader : ILoader +{ + // Everything throws NotImplementedException +} diff --git a/src/native/managed/cdacreader/src/Contracts/Loader_1.cs b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs new file mode 100644 index 0000000000000..533dbc467d34e --- /dev/null +++ b/src/native/managed/cdacreader/src/Contracts/Loader_1.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts; + +internal readonly struct Loader_1 : ILoader +{ + private readonly Target _target; + + internal Loader_1(Target target) + { + _target = target; + } + + ModuleHandle ILoader.GetModuleHandle(TargetPointer modulePointer) + { + if (modulePointer == TargetPointer.Null) + throw new ArgumentNullException(nameof(modulePointer)); + + return new ModuleHandle(modulePointer); + } + + TargetPointer ILoader.GetAssembly(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.Assembly; + } + + ModuleFlags ILoader.GetFlags(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return (ModuleFlags)module.Flags; + } + + TargetPointer ILoader.GetLoaderAllocator(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.LoaderAllocator; + } + + TargetPointer ILoader.GetThunkHeap(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.ThunkHeap; + } + + TargetPointer ILoader.GetILBase(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.Base; + } + + TargetPointer ILoader.GetMetadataAddress(ModuleHandle handle, out ulong size) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.GetLoadedMetadata(out size); + } + + ModuleLookupTables ILoader.GetLookupTables(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return new ModuleLookupTables( + module.FieldDefToDescMap, + module.ManifestModuleReferencesMap, + module.MemberRefToDescMap, + module.MethodDefToDescMap, + module.TypeDefToMethodTableMap, + module.TypeRefToMethodTableMap); + } +} diff --git a/src/native/managed/cdacreader/src/Contracts/Registry.cs b/src/native/managed/cdacreader/src/Contracts/Registry.cs index 9f7151adec432..21f46e481ecd9 100644 --- a/src/native/managed/cdacreader/src/Contracts/Registry.cs +++ b/src/native/managed/cdacreader/src/Contracts/Registry.cs @@ -19,6 +19,7 @@ public Registry(Target target) } public IException Exception => GetContract(); + public ILoader Loader => GetContract(); public IThread Thread => GetContract(); public IRuntimeTypeSystem RuntimeTypeSystem => GetContract(); diff --git a/src/native/managed/cdacreader/src/Data/Exception.cs b/src/native/managed/cdacreader/src/Data/Exception.cs new file mode 100644 index 0000000000000..8f08dc08810e6 --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/Exception.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class Exception : IData +{ + static Exception IData.Create(Target target, TargetPointer address) + => new Exception(target, address); + + public Exception(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.Exception); + + Message = target.ReadPointer(address + (ulong)type.Fields["_message"].Offset); + InnerException = target.ReadPointer(address + (ulong)type.Fields["_innerException"].Offset); + StackTrace = target.ReadPointer(address + (ulong)type.Fields["_stackTrace"].Offset); + WatsonBuckets = target.ReadPointer(address + (ulong)type.Fields["_watsonBuckets"].Offset); + StackTraceString = target.ReadPointer(address + (ulong)type.Fields["_stackTraceString"].Offset); + RemoteStackTraceString = target.ReadPointer(address + (ulong)type.Fields["_remoteStackTraceString"].Offset); + HResult = target.Read(address + (ulong)type.Fields["_HResult"].Offset); + XCode = target.Read(address + (ulong)type.Fields["_xcode"].Offset); + } + + public TargetPointer Message { get; init; } + public TargetPointer InnerException { get; init; } + public TargetPointer StackTrace { get; init; } + public TargetPointer WatsonBuckets { get; init; } + public TargetPointer StackTraceString { get; init; } + public TargetPointer RemoteStackTraceString { get; init; } + public int HResult { get; init; } + public int XCode { get; init; } +} diff --git a/src/native/managed/cdacreader/src/Data/Module.cs b/src/native/managed/cdacreader/src/Data/Module.cs new file mode 100644 index 0000000000000..e462a201241ce --- /dev/null +++ b/src/native/managed/cdacreader/src/Data/Module.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection.PortableExecutable; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class Module : IData +{ + static Module IData.Create(Target target, TargetPointer address) + => new Module(target, address); + + private readonly Target _target; + + public Module(Target target, TargetPointer address) + { + _target = target; + Target.TypeInfo type = target.GetTypeInfo(DataType.Module); + + Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); + Assembly = target.ReadPointer(address + (ulong)type.Fields[nameof(Assembly)].Offset); + Base = target.ReadPointer(address + (ulong)type.Fields[nameof(Base)].Offset); + LoaderAllocator = target.ReadPointer(address + (ulong)type.Fields[nameof(LoaderAllocator)].Offset); + ThunkHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(ThunkHeap)].Offset); + + FieldDefToDescMap = target.ReadPointer(address + (ulong)type.Fields[nameof(FieldDefToDescMap)].Offset); + ManifestModuleReferencesMap = target.ReadPointer(address + (ulong)type.Fields[nameof(ManifestModuleReferencesMap)].Offset); + MemberRefToDescMap = target.ReadPointer(address + (ulong)type.Fields[nameof(MemberRefToDescMap)].Offset); + MethodDefToDescMap = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDefToDescMap)].Offset); + TypeDefToMethodTableMap = target.ReadPointer(address + (ulong)type.Fields[nameof(TypeDefToMethodTableMap)].Offset); + TypeRefToMethodTableMap = target.ReadPointer(address + (ulong)type.Fields[nameof(TypeRefToMethodTableMap)].Offset); + } + + public TargetPointer Assembly { get; init; } + public uint Flags { get; init; } + public TargetPointer Base { get; init; } + public TargetPointer LoaderAllocator { get; init; } + public TargetPointer ThunkHeap { get; init; } + + public TargetPointer FieldDefToDescMap { get; init; } + public TargetPointer ManifestModuleReferencesMap { get; init; } + public TargetPointer MemberRefToDescMap { get; init; } + public TargetPointer MethodDefToDescMap { get; init; } + public TargetPointer TypeDefToMethodTableMap { get; init; } + public TargetPointer TypeRefToMethodTableMap { get; init; } + + private TargetPointer _metadataStart = TargetPointer.Null; + private ulong _metadataSize; + public TargetPointer GetLoadedMetadata(out ulong size) + { + if (Base != TargetPointer.Null && _metadataStart == TargetPointer.Null && _metadataSize == 0) + { + int peSignatureOffset = _target.Read(Base + PEFormat.DosStub.PESignatureOffset); + ulong headerOffset = Base + (ulong)peSignatureOffset; + ushort magic = _target.Read(headerOffset + PEFormat.PEHeader.MagicOffset); + ulong clrHeaderOffset = magic == (ushort)PEMagic.PE32 + ? PEFormat.PEHeader.CLRRuntimeHeader32Offset + : PEFormat.PEHeader.CLRRuntimeHeader32PlusOffset; + int corHeaderRva = _target.Read(headerOffset + clrHeaderOffset); + + // Read RVA and size of the metadata + ulong metadataDirectoryAddress = Base + (ulong)corHeaderRva + PEFormat.CorHeader.MetadataOffset; + _metadataStart = Base + (ulong)_target.Read(metadataDirectoryAddress); + _metadataSize = (ulong)_target.Read(metadataDirectoryAddress + sizeof(int)); + } + + size = _metadataSize; + return _metadataStart; + } + + // https://learn.microsoft.com/windows/win32/debug/pe-format + private static class PEFormat + { + private const int PESignatureSize = sizeof(int); + private const int CoffHeaderSize = 20; + + public static class DosStub + { + public const int PESignatureOffset = 0x3c; + } + + public static class PEHeader + { + private const ulong OptionalHeaderOffset = PESignatureSize + CoffHeaderSize; + public const ulong MagicOffset = OptionalHeaderOffset; + public const ulong CLRRuntimeHeader32Offset = OptionalHeaderOffset + 208; + public const ulong CLRRuntimeHeader32PlusOffset = OptionalHeaderOffset + 224; + } + + // See ECMA-335 II.25.3.3 CLI Header + public static class CorHeader + { + public const ulong MetadataOffset = 8; + } + } +} diff --git a/src/native/managed/cdacreader/src/DataType.cs b/src/native/managed/cdacreader/src/DataType.cs index 338a544ab488c..3f20bdf7b095b 100644 --- a/src/native/managed/cdacreader/src/DataType.cs +++ b/src/native/managed/cdacreader/src/DataType.cs @@ -23,9 +23,10 @@ public enum DataType Thread, ThreadStore, GCAllocContext, + Exception, ExceptionInfo, RuntimeThreadLocals, - + Module, MethodTable, EEClass, MethodTableAuxiliaryData, diff --git a/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs index 6a806e631731c..ef4952f64f61c 100644 --- a/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdacreader/src/Legacy/ISOSDacInterface.cs @@ -43,6 +43,36 @@ internal struct DacpThreadData public ulong nextThread; } +internal struct DacpModuleData +{ + public ulong Address; + public ulong PEAssembly; // Actually the module address in .NET 9+ + public ulong ilBase; + public ulong metadataStart; + public ulong metadataSize; + public ulong Assembly; // Assembly pointer + public uint isReflection; + public uint isPEFile; + + public ulong dwBaseClassIndex; // Always 0 - .NET no longer has this + public ulong dwModuleID; // Always 0 - .NET no longer has this + + public uint dwTransientFlags; + + public ulong TypeDefToMethodTableMap; + public ulong TypeRefToMethodTableMap; + public ulong MethodDefToDescMap; + public ulong FieldDefToDescMap; + public ulong MemberRefToDescMap; + public ulong FileReferencesMap; + public ulong ManifestModuleReferencesMap; + + public ulong LoaderAllocator; + public ulong ThunkHeap; + + public ulong dwModuleIndex; // Always 0 - .NET no longer has this +} + internal struct DacpMethodTableData { public int bIsFree; // everything else is NULL if this is true. @@ -98,7 +128,7 @@ internal unsafe partial interface ISOSDacInterface [PreserveSig] int GetModule(ulong addr, /*IXCLRDataModule*/ void** mod); [PreserveSig] - int GetModuleData(ulong moduleAddr, /*struct DacpModuleData*/ void* data); + int GetModuleData(ulong moduleAddr, DacpModuleData* data); [PreserveSig] int TraverseModuleMap(/*ModuleMapType*/ int mmt, ulong moduleAddr, /*MODULEMAPTRAVERSE*/ void* pCallback, void* token); [PreserveSig] @@ -304,6 +334,30 @@ internal unsafe partial interface ISOSDacInterface int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded); }; +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value +internal struct DacpExceptionObjectData +{ + public ulong Message; + public ulong InnerException; + public ulong StackTrace; + public ulong WatsonBuckets; + public ulong StackTraceString; + public ulong RemoteStackTraceString; + public int HResult; + public int XCode; +} +#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value + +[GeneratedComInterface] +[Guid("A16026EC-96F4-40BA-87FB-5575986FB7AF")] +internal unsafe partial interface ISOSDacInterface2 +{ + [PreserveSig] + int GetObjectExceptionData(ulong objectAddress, DacpExceptionObjectData* data); + [PreserveSig] + int IsRCWDCOMProxy(ulong rcwAddress, int* inDCOMProxy); +} + [GeneratedComInterface] [Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")] internal partial interface ISOSDacInterface9 diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index 240d98bf7d295..5ebbbd7a7471e 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -18,7 +17,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// corresponding error code. /// [GeneratedComClass] -internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9 +internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface2, ISOSDacInterface9 { private readonly Target _target; @@ -151,14 +150,61 @@ public unsafe int GetMethodTableForEEClass(ulong eeClassReallyCanonMT, ulong* va public unsafe int GetMethodTableSlot(ulong mt, uint slot, ulong* value) => HResults.E_NOTIMPL; public unsafe int GetMethodTableTransparencyData(ulong mt, void* data) => HResults.E_NOTIMPL; public unsafe int GetModule(ulong addr, void** mod) => HResults.E_NOTIMPL; - public unsafe int GetModuleData(ulong moduleAddr, void* data) => HResults.E_NOTIMPL; + + public unsafe int GetModuleData(ulong moduleAddr, DacpModuleData* data) + { + if (moduleAddr == 0 || data == null) + return HResults.E_INVALIDARG; + + try + { + Contracts.ILoader contract = _target.Contracts.Loader; + Contracts.ModuleHandle handle = contract.GetModuleHandle(moduleAddr); + + data->Address = moduleAddr; + data->PEAssembly = moduleAddr; // Module address in .NET 9+ - correspondingly, SOS-DAC APIs for PE assemblies expect a module address + data->Assembly = contract.GetAssembly(handle); + + Contracts.ModuleFlags flags = contract.GetFlags(handle); + bool isReflectionEmit = flags.HasFlag(Contracts.ModuleFlags.ReflectionEmit); + data->isReflection = (uint)(isReflectionEmit ? 1 : 0); + data->isPEFile = (uint)(isReflectionEmit ? 0 : 1); // ReflectionEmit module means it is not a PE file + data->dwTransientFlags = (uint)flags; + + data->ilBase = contract.GetILBase(handle); + data->metadataStart = contract.GetMetadataAddress(handle, out ulong metadataSize); + data->metadataSize = metadataSize; + + data->LoaderAllocator = contract.GetLoaderAllocator(handle); + data->ThunkHeap = contract.GetThunkHeap(handle); + + Contracts.ModuleLookupTables tables = contract.GetLookupTables(handle); + data->FieldDefToDescMap = tables.FieldDefToDesc; + data->ManifestModuleReferencesMap = tables.ManifestModuleReferences; + data->MemberRefToDescMap = tables.MemberRefToDesc; + data->MethodDefToDescMap = tables.MethodDefToDesc; + data->TypeDefToMethodTableMap = tables.TypeDefToMethodTable; + data->TypeRefToMethodTableMap = tables.TypeRefToMethodTable; + + // Always 0 - .NET no longer has these concepts + data->dwModuleID = 0; + data->dwBaseClassIndex = 0; + data->dwModuleIndex = 0; + } + catch (Exception e) + { + return e.HResult; + } + + return HResults.S_OK; + } public unsafe int GetNestedExceptionData(ulong exception, ulong* exceptionObject, ulong* nextNestedException) { try { Contracts.IException contract = _target.Contracts.Exception; - TargetPointer exceptionObjectLocal = contract.GetExceptionInfo(exception, out TargetPointer nextNestedExceptionLocal); + TargetPointer exceptionObjectLocal = contract.GetNestedExceptionInfo(exception, out TargetPointer nextNestedExceptionLocal); *exceptionObject = exceptionObjectLocal; *nextNestedException = nextNestedExceptionLocal; } @@ -172,6 +218,30 @@ public unsafe int GetNestedExceptionData(ulong exception, ulong* exceptionObject public unsafe int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded) => HResults.E_NOTIMPL; public unsafe int GetObjectData(ulong objAddr, void* data) => HResults.E_NOTIMPL; + + public unsafe int GetObjectExceptionData(ulong objectAddress, DacpExceptionObjectData* data) + { + try + { + Contracts.IException contract = _target.Contracts.Exception; + Contracts.ExceptionData exceptionData = contract.GetExceptionData(objectAddress); + data->Message = exceptionData.Message; + data->InnerException = exceptionData.InnerException; + data->StackTrace = exceptionData.StackTrace; + data->WatsonBuckets = exceptionData.WatsonBuckets; + data->StackTraceString = exceptionData.StackTraceString; + data->RemoteStackTraceString = exceptionData.RemoteStackTraceString; + data->HResult = exceptionData.HResult; + data->XCode = exceptionData.XCode; + } + catch (Exception ex) + { + return ex.HResult; + } + + return HResults.S_OK; + } + public unsafe int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded) => HResults.E_NOTIMPL; public unsafe int GetOOMData(ulong oomAddr, void* data) => HResults.E_NOTIMPL; public unsafe int GetOOMStaticData(void* data) => HResults.E_NOTIMPL; @@ -255,6 +325,7 @@ public unsafe int GetThreadStoreData(DacpThreadStoreData* data) public unsafe int GetTLSIndex(uint* pIndex) => HResults.E_NOTIMPL; public unsafe int GetUsefulGlobals(void* data) => HResults.E_NOTIMPL; public unsafe int GetWorkRequestData(ulong addrWorkRequest, void* data) => HResults.E_NOTIMPL; + public unsafe int IsRCWDCOMProxy(ulong rcwAddress, int* inDCOMProxy) => HResults.E_NOTIMPL; public unsafe int TraverseEHInfo(ulong ip, void* pCallback, void* token) => HResults.E_NOTIMPL; public unsafe int TraverseLoaderHeap(ulong loaderHeapAddr, void* pCallback) => HResults.E_NOTIMPL; public unsafe int TraverseModuleMap(int mmt, ulong moduleAddr, void* pCallback, void* token) => HResults.E_NOTIMPL; From 2d8bee3cf8f699d8d6991f2045458510a5503df3 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 03:01:58 +0200 Subject: [PATCH 16/37] emit the link on the request span instead of wait_for_connection --- .../src/System/Net/Http/DiagnosticsHandler.cs | 2 +- .../ConnectionPool/ConnectionSetupDiagnostics.cs | 15 ++++++++++----- .../ConnectionPool/HttpConnectionWaiter.cs | 10 ++-------- .../Http/SocketsHttpHandler/Http2Connection.cs | 1 + .../Net/Http/SocketsHttpHandler/HttpConnection.cs | 1 + .../tests/FunctionalTests/DiagnosticsTests.cs | 10 ++++++++-- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs index f191fa5f89d06..0429b8a6b5ace 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs @@ -16,7 +16,7 @@ namespace System.Net.Http internal sealed class DiagnosticsHandler : HttpMessageHandlerStage { private static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(DiagnosticsHandlerLoggingStrings.DiagnosticListenerName); - private static readonly ActivitySource s_activitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.RequestNamespace); + internal static readonly ActivitySource s_activitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.RequestNamespace); private readonly HttpMessageHandler _innerHandler; private readonly DistributedContextPropagator _propagator; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index 06fa3d1e5696e..16cd371ca219a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -80,14 +80,19 @@ public static void ReportError(Activity? activity, Exception exception) return activity; } - public static void StopWaitForConnectionActivity(Activity waitForConnectionActivity, HttpConnectionBase? connection) + public static void AddConnectionLinkToRequestActivity(Activity connectionSetupActivity) { - Debug.Assert(waitForConnectionActivity is not null); - if (waitForConnectionActivity.IsAllDataRequested && connection?.ConnectionSetupActivity is Activity connectionSetupActivity) + Debug.Assert(connectionSetupActivity is not null); + + // We only support links for request activities created by the "System.Net.Http" ActivitySource. + if (DiagnosticsHandler.s_activitySource.HasListeners()) { - waitForConnectionActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); + Activity? requestActivity = Activity.Current; + if (requestActivity?.Source == DiagnosticsHandler.s_activitySource) + { + requestActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); + } } - waitForConnectionActivity.Stop(); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index 9edb9cdda4843..a29c6bbab8442 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -30,15 +30,10 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag long startingTimestamp = Stopwatch.GetTimestamp(); - Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(pool.OriginAuthority); + using Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(pool.OriginAuthority); try { - T connection = await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); - if (waitForConnectionActivity is not null) - { - ConnectionSetupDiagnostics.StopWaitForConnectionActivity(waitForConnectionActivity, connection); - } - return connection; + return await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); } catch (Exception ex) when (waitForConnectionActivity is not null) { @@ -47,7 +42,6 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag } finally { - waitForConnectionActivity?.Stop(); TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp); int versionMajor = typeof(T) == typeof(HttpConnection) ? 1 : 2; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 5ed1c52624f4f..20f8a91c812e4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -1980,6 +1980,7 @@ public async Task SendAsync(HttpRequestMessage request, boo Debug.Assert(async); Debug.Assert(!_pool.HasSyncObjLock); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); + if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index b5b1ccee5a95a..af08767a5431a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -548,6 +548,7 @@ public async Task SendAsync(HttpRequestMessage request, boo // Send the request. if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); + if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken); try { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index c9534586f5dfe..928e6c4b77a0e 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -647,7 +647,9 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( { Assert.Same(conn, tls.Parent); } - wait1.Links.Single(l => l.Context == conn.Context); + + // req1->conn link: + req1.Links.Single(l => l.Context == conn.Context); // Verify timing relationships for connection setup: ActivityAssert.FinishedInOrder(dns, sock); @@ -675,9 +677,13 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( // The second request should reuse the first connection, connection_setup and wait_for_connection should not be recorded again. await client.SendAsync(CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); requestRecorder.VerifyActivityRecorded(2); - Assert.NotSame(req1, requestRecorder.LastFinishedActivity); + Activity req2 = requestRecorder.LastFinishedActivity; + Assert.NotSame(req1, req2); waitForConnectionRecorder.VerifyActivityRecorded(1); connectionSetupRecorder.VerifyActivityRecorded(1); + + // The second request should also have a link to the shared connection. + req2.Links.Single(l => l.Context == conn.Context); }, async server => { From 9995e27c5d71858c3d1e932d37736e424b9f4ca5 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 17:54:32 +0200 Subject: [PATCH 17/37] adjust System.Net.NameResolution --- .../src/System/Net/NameResolutionTelemetry.cs | 6 +- .../tests/FunctionalTests/ActivityTest.cs | 74 ++++++++++++++++--- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 3656fcbd9512e..2a2c30a55c202 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -156,7 +156,7 @@ internal static string GetHostnameFromStateObject(object hostNameOrAddress) /// internal readonly struct NameResolutionActivity { - private const string ActivitySourceName = "System.Net.NameResolution"; + private const string ActivitySourceName = "Experimental.System.Net.NameResolution"; private const string ActivityName = ActivitySourceName + ".DnsLookup"; private static readonly ActivitySource s_activitySource = new(ActivitySourceName); @@ -171,7 +171,7 @@ public NameResolutionActivity(object hostNameOrAddress, long startingTimestamp) if (_activity is not null) { string host = NameResolutionTelemetry.GetHostnameFromStateObject(hostNameOrAddress); - _activity.DisplayName = $"DNS {host}"; + _activity.DisplayName = hostNameOrAddress is IPAddress ? $"DNS reverse lookup {host}" : $"DNS lookup {host}"; if (_activity.IsAllDataRequested) { _activity.SetTag("dns.question.name", host); @@ -199,7 +199,7 @@ public bool Stop(object? answer, Exception? exception, out TimeSpan duration) }; Debug.Assert(answerValues is not null); - _activity.SetTag("dns.answer", answerValues); + _activity.SetTag("dns.answers", answerValues); } else { diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs index f15a3bc0c9221..6e8e1e1f5cb2d 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs @@ -14,13 +14,13 @@ namespace System.Net.NameResolution.Tests { public class ActivityTest { - private const string ActivitySourceName = "System.Net.NameResolution"; + private const string ActivitySourceName = "Experimental.System.Net.NameResolution"; private const string ActivityName = ActivitySourceName + ".DnsLookup"; [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(false)] [InlineData(true)] - public async Task ResolveValidHostName_ActivityRecorded(bool createParentActivity) + public async Task ForwardLookup_ValidHostName_ActivityRecorded(bool createParentActivity) { await RemoteExecutor.Invoke(static async (createParentActivity) => { @@ -55,8 +55,8 @@ void Verify(int timesLookupRecorded) { recorder.VerifyActivityRecorded(timesLookupRecorded); Activity activity = recorder.LastFinishedActivity; - VerifyCommonActivityInfo(activity, ValidHostName); - ActivityAssert.HasTag(activity, "dns.answer", (string[] answers) => answers.Contains(expected4) || answers.Contains(expected6)); + VerifyForwardActivityInfo(activity, ValidHostName); + ActivityAssert.HasTag(activity, "dns.answers", (string[] answers) => answers.Contains(expected4) || answers.Contains(expected6)); ActivityAssert.HasNoTag(activity, "error.type"); } @@ -66,9 +66,53 @@ void Verify(int timesLookupRecorded) [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(false)] [InlineData(true)] - public static async Task ResolveInvalidHostName_ActivityRecorded(bool createParentActivity) + public async Task ReverseLookup_ValidIP_ActivityRecorded(bool createParentActivity) { - const string InvalidHostName = $"invalid...example.com...{nameof(ResolveInvalidHostName_ActivityRecorded)}"; + await RemoteExecutor.Invoke(static async (createParentActivity) => + { + string loopbackIPString = IPAddress.Loopback.ToString(); + using var recorder = new ActivityRecorder(ActivitySourceName, ActivityName) + { + ExpectedParent = bool.Parse(createParentActivity) ? new Activity("parent").Start() : null + }; + + IPHostEntry entry = await Dns.GetHostEntryAsync(IPAddress.Loopback); // Also does a forward lookup + Verify(2); + + await Dns.GetHostEntryAsync(loopbackIPString); + Verify(4); + + Dns.GetHostEntry(IPAddress.Loopback); + Verify(6); + + Dns.GetHostEntry(loopbackIPString); + Verify(8); + + Dns.EndGetHostEntry(Dns.BeginGetHostEntry(IPAddress.Loopback, null, null)); + Verify(10); + + Dns.EndGetHostEntry(Dns.BeginGetHostEntry(loopbackIPString, null, null)); + Verify(12); + + void Verify(int timesLookupRecorded) + { + recorder.VerifyActivityRecorded(timesLookupRecorded); + Activity reverseActivity = recorder.FinishedActivities.ToArray()[^2]; + VerifyReverseActivityInfo(reverseActivity, IPAddress.Loopback); + ActivityAssert.HasTag(reverseActivity, "dns.answers", (string[] answers) => answers.Contains(entry.HostName)); + ActivityAssert.HasNoTag(reverseActivity, "error.type"); + VerifyForwardActivityInfo(recorder.LastStartedActivity, entry.HostName); + } + + }, createParentActivity.ToString()).DisposeAsync(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public static async Task ForwardLookup_InvalidHostName_ActivityRecorded(bool createParentActivity) + { + const string InvalidHostName = $"invalid...example.com...{nameof(ForwardLookup_InvalidHostName_ActivityRecorded)}"; await RemoteExecutor.Invoke(async (createParentActivity) => { @@ -101,18 +145,26 @@ void Verify(int timesLookupRecorded) Activity activity = recorder.LastFinishedActivity; Assert.Equal(ActivityStatusCode.Error, activity.Status); - VerifyCommonActivityInfo(activity, InvalidHostName); + VerifyForwardActivityInfo(activity, InvalidHostName); ActivityAssert.HasTag(activity, "error.type", "host_not_found"); } }, createParentActivity.ToString()).DisposeAsync(); } - static void VerifyCommonActivityInfo(Activity activity, string host) + static void VerifyForwardActivityInfo(Activity activity, string question) + { + Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal(ActivityName, activity.OperationName); + Assert.Equal($"DNS lookup {question}", activity.DisplayName); + ActivityAssert.HasTag(activity, "dns.question.name", question); + } + + static void VerifyReverseActivityInfo(Activity activity, IPAddress question) { Assert.Equal(ActivityKind.Client, activity.Kind); - Assert.Equal("System.Net.NameResolution.DnsLookup", activity.OperationName); - Assert.Equal($"DNS {host}", activity.DisplayName); - ActivityAssert.HasTag(activity, "dns.question.name", host); + Assert.Equal(ActivityName, activity.OperationName); + Assert.Equal($"DNS reverse lookup {question}", activity.DisplayName); + ActivityAssert.HasTag(activity, "dns.question.name", question.ToString()); } } } From c2c7c87977df0b6ec92c31476371e74b24670892 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 18:29:25 +0200 Subject: [PATCH 18/37] adjust System.Net.Sockets naming, add UDS test --- .../System/Net/Sockets/SocketsTelemetry.cs | 4 +- .../tests/FunctionalTests/TelemetryTest.cs | 49 ++++++++++++++++--- .../FunctionalTests/UnixDomainSocketTest.cs | 2 +- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 3dd07e1150f31..c36ca0768debb 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -10,7 +10,7 @@ namespace System.Net.Sockets [EventSource(Name = "System.Net.Sockets")] internal sealed class SocketsTelemetry : EventSource { - private const string ActivitySourceName = "System.Net.Sockets"; + private const string ActivitySourceName = "Experimental.System.Net.Sockets"; private const string ConnectActivityName = ActivitySourceName + ".Connect"; private static readonly ActivitySource s_connectActivitySource = new(ActivitySourceName); @@ -81,7 +81,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) } [NonEvent] - public Activity? ConnectStart(SocketAddress address, EndPoint endPoint, bool keepActivityCurrent) + public Activity? ConnectStart(SocketAddress address, EndPoint endPoint, bool keepActivityCurrent) { Interlocked.Increment(ref _currentOutgoingConnectAttempts); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index 27297bb670b3b..25f6e22d2bf3f 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -18,7 +18,7 @@ namespace System.Net.Sockets.Tests { public class TelemetryTest { - private const string ActivitySourceName = "System.Net.Sockets"; + private const string ActivitySourceName = "Experimental.System.Net.Sockets"; private const string ActivityName = ActivitySourceName + ".Connect"; private static readonly Lazy> s_remoteServerIsReachable = new Lazy>(() => Task.Run(async () => @@ -137,26 +137,26 @@ await RemoteExecutor.Invoke(static async (connectMethod, ipv6Str) => recorder.VerifyActivityRecorded(1); Activity activity = recorder.LastFinishedActivity; - VerifyConnectActivity(activity, (IPEndPoint)server.LocalEndPoint, ipv6); + VerifyTcpConnectActivity(activity, (IPEndPoint)server.LocalEndPoint, ipv6); Assert.Same(parent, Activity.Current); parent.Stop(); }, connectMethod, ipv6.ToString()).DisposeAsync(); } - static void VerifyConnectActivity(Activity activity, IPEndPoint remoteEndPoint, bool ipv6) + static void VerifyTcpConnectActivity(Activity activity, IPEndPoint remoteEndPoint, bool ipv6) { string address = remoteEndPoint.Address.ToString(); int port = remoteEndPoint.Port; Assert.Equal(ActivityKind.Client, activity.Kind); - Assert.Equal("System.Net.Sockets.Connect", activity.OperationName); + Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"socket connect {address}:{port}", activity.DisplayName); ActivityAssert.HasTag(activity, "network.peer.address", address); ActivityAssert.HasTag(activity, "network.peer.port", port); ActivityAssert.HasTag(activity, "network.type", ipv6 ? "ipv6" : "ipv4"); } - //[OuterLoop("Connection failure takes long on Windows.")] + [OuterLoop("Connection failure takes long on Windows.")] [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [MemberData(nameof(SocketMethods_WithBools_MemberData))] public async Task Connect_Failure_ActivityRecorded(string connectMethod, bool ipv6) @@ -181,7 +181,7 @@ await RemoteExecutor.Invoke(static async (connectMethod, ipv6Str) => recorder.VerifyActivityRecorded(1); Activity activity = recorder.LastFinishedActivity; - VerifyConnectActivity(activity, (IPEndPoint)notListening.LocalEndPoint, ipv6); + VerifyTcpConnectActivity(activity, (IPEndPoint)notListening.LocalEndPoint, ipv6); string expectedErrorType = ActivityAssert.CamelToSnake(ex.SocketErrorCode.ToString()); ActivityAssert.HasTag(activity, "error.type", expectedErrorType); Assert.Equal(ActivityStatusCode.Error, activity.Status); @@ -191,6 +191,43 @@ await RemoteExecutor.Invoke(static async (connectMethod, ipv6Str) => }, connectMethod, ipv6.ToString()).DisposeAsync(); } + [ConditionalTheory(typeof(Socket), nameof(Socket.OSSupportsUnixDomainSockets))] + [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] + [MemberData(nameof(SocketMethods_MemberData))] + public async Task Socket_UDS_Success_ActivityRecorded(string connectMethod) + { + await RemoteExecutor.Invoke(static async connectMethod => + { + Socket server = null; + UnixDomainSocketEndPoint endPoint = null; + + //Path selection is contingent on a successful Bind(). + //If it fails, the next iteration will try another path. + RetryHelper.Execute(() => + { + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + endPoint = new UnixDomainSocketEndPoint(UnixDomainSocketTest.GetRandomNonExistingFilePath()); + server.Bind(endPoint); + server.Listen(); + }, retryWhen: e => e is SocketException); + + using Socket client = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + + using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName); + + Task connectTask = GetHelperBase(connectMethod).ConnectAsync(client, endPoint); + await server.AcceptAsync(); + await connectTask; + + recorder.VerifyActivityRecorded(1); + Activity activity = recorder.LastFinishedActivity; + Assert.Equal(ActivityName, activity.OperationName); + Assert.Equal($"socket connect {endPoint}", activity.DisplayName); + ActivityAssert.HasTag(activity, "network.peer.address", endPoint.ToString()); + + }, connectMethod).DisposeAsync(); + } + [OuterLoop] [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [MemberData(nameof(SocketMethods_Matrix_MemberData))] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs index 58edc1ecffaa5..a49b8aa235a4e 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs @@ -636,7 +636,7 @@ public async Task UnixDomainSocket_Receive_GetsCanceledByDispose() } } - private static string GetRandomNonExistingFilePath() + internal static string GetRandomNonExistingFilePath() { string result; do From 8acab5520361f307883c56370a31c1aa17b017a4 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 19:19:24 +0200 Subject: [PATCH 19/37] replace the _connectActivity field with a CWT --- .../src/System/Net/Sockets/Socket.cs | 10 +++---- .../Net/Sockets/SocketAsyncEventArgs.cs | 27 ++++++++++++++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index e4f7f41e87600..82b1171a3146e 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2782,7 +2782,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan WildcardBindForConnectIfNecessary(endPointSnapshot.AddressFamily); - e._connectActivity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); + e.ConnectActivity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); // Prepare for the native call. try @@ -2792,8 +2792,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._connectActivity, ex.Message); - e._connectActivity = null; + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e.ConnectActivity, ex.Message); + e.ConnectActivity = null; throw; } @@ -2809,8 +2809,8 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan } catch (Exception ex) { - SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e._connectActivity, ex.Message); - e._connectActivity = null; + SocketsTelemetry.Log.AfterConnect(SocketError.NotSocket, e.ConnectActivity, ex.Message); + e.ConnectActivity = null; _localEndPoint = null; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index c9398fb7dda8c..63cd9a8febf17 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -71,10 +72,10 @@ public partial class SocketAsyncEventArgs : EventArgs, IDisposable private readonly bool _flowExecutionContext; private ExecutionContext? _context; private static readonly ContextCallback s_executionCallback = ExecutionCallback; + private static ConditionalWeakTable? s_connectActivityTable; private Socket? _currentSocket; private bool _userSocket; // if false when performing Connect, _currentSocket should be disposed private bool _disposeCalled; - internal Activity? _connectActivity; // Controls thread safety via Interlocked. private const int Configuring = -1; @@ -225,8 +226,8 @@ private void AfterConnectAcceptTelemetry() break; case SocketAsyncOperation.Connect: - SocketsTelemetry.Log.AfterConnect(SocketError, _connectActivity); - _connectActivity = null; + SocketsTelemetry.Log.AfterConnect(SocketError, ConnectActivity); + ConnectActivity = null; break; default: @@ -304,6 +305,26 @@ public object? UserToken set { _userToken = value; } } + internal Activity? ConnectActivity + { + // ConditionalWeakTable is used to avoid penalizing every SAEA with a new field in the the vast majority of the cases, + // when ConnectActivity is null. Accessors of this property should never race over the same SAEA instance. + // Telemetry logic ensures that getter calls are always preceded by a setter call. + get => s_connectActivityTable?.TryGetValue(this, out Activity? result) == true ? result : null; + set + { + if (value is not null) + { + LazyInitializer.EnsureInitialized(ref s_connectActivityTable, () => new ConditionalWeakTable()); + s_connectActivityTable.AddOrUpdate(this, value); + } + else + { + s_connectActivityTable?.Remove(this); + } + } + } + public void SetBuffer(int offset, int count) { StartConfiguring(); From afe164840299ef889f059897e2fbac447909e170 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 20:09:55 +0200 Subject: [PATCH 20/37] Adjust SslStream tracing --- .../src/System/Net/Security/SslStream.IO.cs | 6 ++--- .../tests/FunctionalTests/TelemetryTest.cs | 27 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index e5a7315b70f2c..435142e0ca3cc 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -15,7 +15,7 @@ namespace System.Net.Security { public partial class SslStream { - private const string ActivitySourceName = "System.Net.Security"; + private const string ActivitySourceName = "Experimental.System.Net.Security"; private const string ActivityName = ActivitySourceName + ".TlsHandshake"; private static readonly ActivitySource s_activitySource = new(ActivitySourceName); @@ -136,13 +136,13 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell startingTimestamp = 0; } - using Activity? activity = s_activitySource.StartActivity(ActivityName, IsServer ? ActivityKind.Server : ActivityKind.Client); + using Activity? activity = s_activitySource.StartActivity(ActivityName); if (activity is not null) { activity.DisplayName = IsServer ? "TLS server" : $"TLS client {TargetHostName}"; if (activity.IsAllDataRequested && !IsServer) { - activity.SetTag("tls.client.server_name", TargetHostName); + activity.SetTag("server.address", TargetHostName); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs index 7437b32cbcee3..281e0dff3a657 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs @@ -17,7 +17,7 @@ namespace System.Net.Security.Tests { public class TelemetryTest { - private const string ActivitySourceName = "System.Net.Security"; + private const string ActivitySourceName = "Experimental.System.Net.Security"; private const string ActivityName = ActivitySourceName + ".TlsHandshake"; [Fact] @@ -48,8 +48,9 @@ await RemoteExecutor.Invoke(async synchronousApiStr => await test.SslStream_StreamToStream_Authentication_Success(); recorder.VerifyActivityRecorded(2); // client + server - Activity clientActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Client); - Activity serverActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Server); + Activity clientActivity = recorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS client")); + Activity serverActivity = recorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS server")); + Assert.True(Enum.GetValues(typeof(SslProtocols)).Length == 8, "We need to extend the mapping in case new values are added to SslProtocols."); #pragma warning disable 0618, SYSLIB0039 (string protocolName, string protocolVersion) = test.SslProtocol switch { @@ -63,16 +64,18 @@ await RemoteExecutor.Invoke(async synchronousApiStr => }; #pragma warning restore 0618, SYSLIB0039 + Assert.Equal(ActivityKind.Internal, clientActivity.Kind); Assert.True(clientActivity.Duration > TimeSpan.Zero); - Assert.Equal("System.Net.Security.TlsHandshake", clientActivity.OperationName); + Assert.Equal(ActivityName, clientActivity.OperationName); Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); - ActivityAssert.HasTag(clientActivity, "tls.client.server_name", test.Name); + ActivityAssert.HasTag(clientActivity, "server.address", test.Name); ActivityAssert.HasTag(clientActivity, "tls.protocol.name", protocolName); ActivityAssert.HasTag(clientActivity, "tls.protocol.version", protocolVersion); ActivityAssert.HasNoTag(clientActivity, "error.type"); + Assert.Equal(ActivityKind.Internal, serverActivity.Kind); Assert.True(serverActivity.Duration > TimeSpan.Zero); - Assert.Equal("System.Net.Security.TlsHandshake", serverActivity.OperationName); + Assert.Equal(ActivityName, serverActivity.OperationName); Assert.StartsWith($"TLS server", serverActivity.DisplayName); ActivityAssert.HasTag(serverActivity, "tls.protocol.name", protocolName); ActivityAssert.HasTag(serverActivity, "tls.protocol.version", protocolVersion); @@ -93,18 +96,20 @@ await RemoteExecutor.Invoke(async () => recorder.VerifyActivityRecorded(2); // client + server - Activity clientActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Client); - Activity serverActivity = recorder.FinishedActivities.Single(a => a.Kind == ActivityKind.Server); + Activity clientActivity = recorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS client")); + Activity serverActivity = recorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS server")); + Assert.Equal(ActivityKind.Internal, clientActivity.Kind); Assert.Equal(ActivityStatusCode.Error, clientActivity.Status); Assert.True(clientActivity.Duration > TimeSpan.Zero); - Assert.Equal("System.Net.Security.TlsHandshake", clientActivity.OperationName); + Assert.Equal(ActivityName, clientActivity.OperationName); Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); - ActivityAssert.HasTag(clientActivity, "tls.client.server_name", test.Name); + ActivityAssert.HasTag(clientActivity, "server.address", test.Name); ActivityAssert.HasTag(clientActivity, "error.type", typeof(AuthenticationException).FullName); + Assert.Equal(ActivityKind.Internal, serverActivity.Kind); Assert.True(serverActivity.Duration > TimeSpan.Zero); - Assert.Equal("System.Net.Security.TlsHandshake", serverActivity.OperationName); + Assert.Equal(ActivityName, serverActivity.OperationName); Assert.StartsWith($"TLS server", serverActivity.DisplayName); }).DisposeAsync(); } From 96f1f18762eaf43280f33557d50dca327b892b5b Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 20:13:59 +0200 Subject: [PATCH 21/37] ActivityKind --- .../src/System/Net/NameResolutionTelemetry.cs | 2 +- .../tests/FunctionalTests/ActivityTest.cs | 4 ++-- .../src/System/Net/Sockets/SocketsTelemetry.cs | 2 +- .../System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 2a2c30a55c202..ba6f625e31bd4 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -167,7 +167,7 @@ internal readonly struct NameResolutionActivity public NameResolutionActivity(object hostNameOrAddress, long startingTimestamp) { _startingTimestamp = startingTimestamp; - _activity = s_activitySource.StartActivity(ActivityName, ActivityKind.Client); + _activity = s_activitySource.StartActivity(ActivityName); if (_activity is not null) { string host = NameResolutionTelemetry.GetHostnameFromStateObject(hostNameOrAddress); diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs index 6e8e1e1f5cb2d..13dfeb908942c 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/ActivityTest.cs @@ -153,7 +153,7 @@ void Verify(int timesLookupRecorded) static void VerifyForwardActivityInfo(Activity activity, string question) { - Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal(ActivityKind.Internal, activity.Kind); Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"DNS lookup {question}", activity.DisplayName); ActivityAssert.HasTag(activity, "dns.question.name", question); @@ -161,7 +161,7 @@ static void VerifyForwardActivityInfo(Activity activity, string question) static void VerifyReverseActivityInfo(Activity activity, IPAddress question) { - Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal(ActivityKind.Internal, activity.Kind); Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"DNS reverse lookup {question}", activity.DisplayName); ActivityAssert.HasTag(activity, "dns.question.name", question.ToString()); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index c36ca0768debb..00daf69152d99 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -94,7 +94,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) if (s_connectActivitySource.HasListeners()) { Activity? activityToReset = keepActivityCurrent ? Activity.Current : null; - activity = s_connectActivitySource.StartActivity(ConnectActivityName, ActivityKind.Client); + activity = s_connectActivitySource.StartActivity(ConnectActivityName); if (keepActivityCurrent) { // Do not overwrite Activity.Current in the caller's ExecutionContext. diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index 25f6e22d2bf3f..825ef3234700c 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -148,7 +148,7 @@ static void VerifyTcpConnectActivity(Activity activity, IPEndPoint remoteEndPoin { string address = remoteEndPoint.Address.ToString(); int port = remoteEndPoint.Port; - Assert.Equal(ActivityKind.Client, activity.Kind); + Assert.Equal(ActivityKind.Internal, activity.Kind); Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"socket connect {address}:{port}", activity.DisplayName); ActivityAssert.HasTag(activity, "network.peer.address", address); @@ -221,6 +221,7 @@ await RemoteExecutor.Invoke(static async connectMethod => recorder.VerifyActivityRecorded(1); Activity activity = recorder.LastFinishedActivity; + Assert.Equal(ActivityKind.Internal, activity.Kind); Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"socket connect {endPoint}", activity.DisplayName); ActivityAssert.HasTag(activity, "network.peer.address", endPoint.ToString()); From a9cd814ac54f52ef4d722211aba82563c27582f5 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 20:53:07 +0200 Subject: [PATCH 22/37] adjust HTTP Activities --- .../Http/DiagnosticsHandlerLoggingStrings.cs | 4 +-- .../ConnectionSetupDiagnostics.cs | 7 +++--- .../tests/FunctionalTests/DiagnosticsTests.cs | 25 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs index 45015585d408e..c22ff068c44c0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs @@ -17,9 +17,9 @@ internal static class DiagnosticsHandlerLoggingStrings public const string RequestActivityStartName = RequestActivityName + ".Start"; public const string RequestActivityStopName = RequestActivityName + ".Stop"; - public const string ConnectionNamespace = "System.Net.Http.Connections"; + public const string ConnectionNamespace = "Experimental.System.Net.Http.Connections"; public const string ConnectionSetupActivityName = ConnectionNamespace + ".ConnectionSetup"; - public const string WaitForConnectionNamespace = "System.Net.Http.ConnectionLink"; + public const string WaitForConnectionNamespace = ConnectionNamespace; public const string WaitForConnectionActivityName = WaitForConnectionNamespace + ".WaitForConnection"; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index 16cd371ca219a..aaa2ae66b2751 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -7,20 +7,21 @@ namespace System.Net.Http { + // Implements distributed tracing logic for managing the "HTTP connection_setup" and "HTTP wait_for_connection" Activities. internal static class ConnectionSetupDiagnostics { - private static readonly ActivitySource s_connectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); + private static readonly ActivitySource s_connectionSetupActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); private static readonly ActivitySource s_waitForConnectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.WaitForConnectionNamespace); public static Activity? StartConnectionSetupActivity(bool isSecure, HttpAuthority authority) { Activity? activity = null; - if (s_connectionActivitySource.HasListeners()) + if (s_connectionSetupActivitySource.HasListeners()) { // Connection activities should be new roots and not parented under whatever // request happens to be in progress when the connection is started. Activity.Current = null; - activity = s_connectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName, ActivityKind.Client); + activity = s_connectionSetupActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName); } if (activity is not null) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 928e6c4b77a0e..12b93e8dc625f 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -593,18 +593,17 @@ static async Task RunTest(string useVersion, string testAsync, string useTlsStri { ExpectedParent = parentActivity }; - using ActivityRecorder waitForConnectionRecorder = new("System.Net.Http.ConnectionLink", "System.Net.Http.ConnectionLink.WaitForConnection") + using ActivityRecorder waitForConnectionRecorder = new("Experimental.System.Net.Http.Connections", "Experimental.System.Net.Http.Connections.WaitForConnection") { VerifyParent = false }; - using ActivityRecorder connectionSetupRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.ConnectionSetup"); - using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DnsLookup") { VerifyParent = false }; - using ActivityRecorder socketRecorder = new("System.Net.Sockets", "System.Net.Sockets.Connect") { VerifyParent = false }; - using ActivityRecorder tlsRecorder = new("System.Net.Security", "System.Net.Security.TlsHandshake") + using ActivityRecorder connectionSetupRecorder = new("Experimental.System.Net.Http.Connections", "Experimental.System.Net.Http.Connections.ConnectionSetup"); + using ActivityRecorder dnsRecorder = new("Experimental.System.Net.NameResolution", "Experimental.System.Net.NameResolution.DnsLookup") { VerifyParent = false }; + using ActivityRecorder socketRecorder = new("Experimental.System.Net.Sockets", "Experimental.System.Net.Sockets.Connect") { VerifyParent = false }; + using ActivityRecorder tlsRecorder = new("Experimental.System.Net.Security", "Experimental.System.Net.Security.TlsHandshake") { - VerifyParent = false, - Filter = a => a.Kind == ActivityKind.Client // do not capture the server handshake + VerifyParent = false }; await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( @@ -624,7 +623,7 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( Activity? tls = null; if (useTls) { - tls = tlsRecorder.VerifyActivityRecordedOnce(); + tls = tlsRecorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS client")); } else { @@ -664,6 +663,8 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( } // Verify display names and attributes: + Assert.Equal(ActivityKind.Internal, wait1.Kind); + Assert.Equal(ActivityKind.Internal, conn.Kind); Assert.Equal($"HTTP wait_for_connection localhost:{uri.Port}", wait1.DisplayName); Assert.Equal($"HTTP connection_setup localhost:{uri.Port}", conn.DisplayName); ActivityAssert.HasTag(conn, "network.peer.address", @@ -720,13 +721,13 @@ static async Task RunTest(string useVersion, string testAsync, string failureTyp { ExpectedParent = parentActivity }; - using ActivityRecorder waitForConnectionRecorder = new("System.Net.Http.ConnectionLink", "System.Net.Http.ConnectionLink.WaitForConnection") + using ActivityRecorder waitForConnectionRecorder = new("Experimental.System.Net.Http.Connections", "Experimental.System.Net.Http.Connections.WaitForConnection") { VerifyParent = false }; - using ActivityRecorder connectionSetupRecorder = new("System.Net.Http.Connections", "System.Net.Http.Connections.ConnectionSetup"); - using ActivityRecorder dnsRecorder = new("System.Net.NameResolution", "System.Net.NameResolution.DnsLookup") { VerifyParent = false }; - using ActivityRecorder socketRecorder = new("System.Net.Sockets", "System.Net.Sockets.Connect") { VerifyParent = false }; + using ActivityRecorder connectionSetupRecorder = new("Experimental.System.Net.Http.Connections", "Experimental.System.Net.Http.Connections.ConnectionSetup"); + using ActivityRecorder dnsRecorder = new("Experimental.System.Net.NameResolution", "Experimental.System.Net.NameResolution.DnsLookup") { VerifyParent = false }; + using ActivityRecorder socketRecorder = new("Experimental.System.Net.Sockets", "Experimental.System.Net.Sockets.Connect") { VerifyParent = false }; Uri uri; using Socket? notListening = failureType is "socket" ? new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) : null; From 576842c47a0ec880cdf371935f420a02d9435991 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Jul 2024 23:50:41 +0200 Subject: [PATCH 23/37] SocketsHttpHandler_DiagnosticsTest_Http3 --- .../tests/FunctionalTests/DiagnosticsTests.cs | 7 +++++++ .../tests/FunctionalTests/SocketsHttpHandlerTest.cs | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 12b93e8dc625f..0191fc7925e5e 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -14,6 +14,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; +using Microsoft.DotNet.XUnitExtensions; using Xunit; using Xunit.Abstractions; @@ -237,6 +238,12 @@ await RemoteExecutor.Invoke(async (useVersion, testAsync) => [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public async Task SendAsync_ExpectedDiagnosticCancelledLogging() { + if (UseVersion == HttpVersion30) + { + // [ActiveIssue("https://github.com/dotnet/runtime/issues/104699")] + throw new SkipTestException("SendAsync_ExpectedDiagnosticCancelledLogging is broken on HTTP/3."); + } + await RemoteExecutor.Invoke(async (useVersion, testAsync) => { TaskCompletionSource responseLoggedTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index ea34d7bf2479d..18d3ee156e785 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -292,6 +292,14 @@ public SocketsHttpHandler_DiagnosticsTest_Http2(ITestOutputHelper output) : base protected override Version UseVersion => HttpVersion.Version20; } + [ConditionalClass(typeof(HttpClientHandlerTestBase), nameof(IsQuicSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103703", typeof(PlatformDetection), nameof(PlatformDetection.IsArmProcess))] + public sealed class SocketsHttpHandler_DiagnosticsTest_Http3 : DiagnosticsTest + { + public SocketsHttpHandler_DiagnosticsTest_Http3(ITestOutputHelper output) : base(output) { } + protected override Version UseVersion => HttpVersion.Version30; + } + public sealed class SocketsHttpHandler_HttpClient_SelectedSites_Test : HttpClient_SelectedSites_Test { public SocketsHttpHandler_HttpClient_SelectedSites_Test(ITestOutputHelper output) : base(output) { } From f04ab6ef5f6eb1cd4c4afb5a8f88d4817e515cac Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 11 Jul 2024 00:31:22 +0200 Subject: [PATCH 24/37] WIP h3 --- .../ConnectionPool/HttpConnectionWaiter.cs | 2 +- .../tests/FunctionalTests/DiagnosticsTests.cs | 80 ++++++++++++------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index a29c6bbab8442..72f51bd7c0557 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -19,7 +19,7 @@ internal sealed class HttpConnectionWaiter : TaskCompletionSourceWithCancella public ValueTask WaitForConnectionAsync(HttpRequestMessage request, HttpConnectionPool pool, bool async, CancellationToken requestCancellationToken) { - return HttpTelemetry.Log.IsEnabled() || pool.Settings._metrics!.RequestsQueueDuration.Enabled || Activity.Current?.OperationName is DiagnosticsHandlerLoggingStrings.RequestActivityName + return HttpTelemetry.Log.IsEnabled() || pool.Settings._metrics!.RequestsQueueDuration.Enabled || Activity.Current?.Source == DiagnosticsHandler.s_activitySource ? WaitForConnectionWithTelemetryAsync(request, pool, async, requestCancellationToken) : WaitWithCancellationAsync(async, requestCancellationToken); } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 0191fc7925e5e..fa4cc340c46f5 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -589,7 +589,10 @@ protected static void VerifyTag(KeyValuePair[] tags, string [InlineData(true)] public async Task SendAsync_Success_ConnectionSetupActivityGraphRecorded(bool useTls) { - await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); + if (UseVersion == HttpVersion30 && !useTls) return; + + await RunTest(UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()); + //await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); static async Task RunTest(string useVersion, string testAsync, string useTlsString) { bool useTls = bool.Parse(useTlsString); @@ -616,25 +619,38 @@ static async Task RunTest(string useVersion, string testAsync, string useTlsStri await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( async uri => { - uri = new Uri($"{uri.Scheme}://localhost:{uri.Port}"); + Version version = Version.Parse(useVersion); + if (version != HttpVersion30) + { + uri = new Uri($"{uri.Scheme}://localhost:{uri.Port}"); + } + using HttpClient client = new HttpClient(CreateHttpClientHandler(allowAllCertificates: true)); - await client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true)); + await client.SendAsync(bool.Parse(testAsync), CreateRequest(HttpMethod.Get, uri, version, exactVersion: true)); Activity req1 = requestRecorder.VerifyActivityRecordedOnce(); Activity wait1 = waitForConnectionRecorder.VerifyActivityRecordedOnce(); Activity conn = connectionSetupRecorder.VerifyActivityRecordedOnce(); - Activity dns = dnsRecorder.VerifyActivityRecordedOnce(); - Assert.True(socketRecorder.Stopped is 1 or 2); - Activity sock = socketRecorder.LastFinishedActivity; + + Activity? dns = null; + Activity? sock = null; Activity? tls = null; - if (useTls) - { - tls = tlsRecorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS client")); - } - else + + if (version != HttpVersion30) { - tlsRecorder.VerifyActivityRecorded(0); + dns = dnsRecorder.VerifyActivityRecordedOnce(); + Assert.True(socketRecorder.Stopped is 1 or 2); + sock = socketRecorder.LastFinishedActivity; + + if (useTls) + { + tls = tlsRecorder.FinishedActivities.Single(a => a.DisplayName.StartsWith("TLS client")); + } + else + { + tlsRecorder.VerifyActivityRecorded(0); + } } // Verify relationships between request and connection_setup, wait_for_connection: @@ -645,28 +661,32 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( ActivityAssert.FinishedInOrder(conn, wait1); ActivityAssert.FinishedInOrder(wait1, req1); - // Verify the connection_setup graph: - Assert.Null(conn.Parent); - Assert.Same(conn, dns.Parent); - Assert.Same(conn, sock.Parent); - if (useTls) - { - Assert.Same(conn, tls.Parent); - } - // req1->conn link: req1.Links.Single(l => l.Context == conn.Context); - // Verify timing relationships for connection setup: - ActivityAssert.FinishedInOrder(dns, sock); - if (useTls) - { - ActivityAssert.FinishedInOrder(sock, tls); - ActivityAssert.FinishedInOrder(tls, conn); - } - else + // Verify the connection_setup graph: + Assert.Null(conn.Parent); + + if (version != HttpVersion30) { - ActivityAssert.FinishedInOrder(sock, conn); + Assert.Same(conn, dns.Parent); + Assert.Same(conn, sock.Parent); + if (useTls) + { + Assert.Same(conn, tls.Parent); + } + + // Verify timing relationships for connection setup: + ActivityAssert.FinishedInOrder(dns, sock); + if (useTls) + { + ActivityAssert.FinishedInOrder(sock, tls); + ActivityAssert.FinishedInOrder(tls, conn); + } + else + { + ActivityAssert.FinishedInOrder(sock, conn); + } } // Verify display names and attributes: From 7b9403991ade3db9e9aecf3d4dee55b6308aa4f3 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 11 Jul 2024 01:04:19 +0200 Subject: [PATCH 25/37] adjust to main --- src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs index 2ff1108bb9686..b592f0ce44857 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs @@ -704,7 +704,7 @@ private static Task RunAsync(Func>)s_tasks).Remove(new KeyValuePair(key!, task)); // Since it was canceled, func(..) had not executed and call AfterResolution it needs to be called here. - NameResolutionTelemetry.Log.AfterResolution(key!, startingTimestamp, new OperationCanceledException()); + NameResolutionTelemetry.Log.AfterResolution(key!, activity, new OperationCanceledException()); } }, key, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } From 1c5e7723c6e2b58217526b24e50bbe7cd96f454c Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 11 Jul 2024 02:28:39 +0200 Subject: [PATCH 26/37] implement H/3 connection diagnostics --- .../HttpConnectionPool.Http3.cs | 25 +++++++-- .../SocketsHttpHandler/Http3Connection.cs | 4 +- .../tests/FunctionalTests/DiagnosticsTests.cs | 54 ++++++++++++------- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs index b2d17af903c61..5800f8747c084 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs @@ -75,7 +75,7 @@ internal sealed partial class HttpConnectionPool // Loop in case we get a 421 and need to send the request to a different authority. while (true) { - if (!TryGetHttp3Authority(request, out _, out Exception? reasonException)) + if (!TryGetHttp3Authority(request, out HttpAuthority? authority, out Exception? reasonException)) { if (reasonException is null) { @@ -88,7 +88,16 @@ internal sealed partial class HttpConnectionPool if (!TryGetPooledHttp3Connection(request, out Http3Connection? connection, out HttpConnectionWaiter? http3ConnectionWaiter)) { - connection = await http3ConnectionWaiter.WaitWithCancellationAsync(cancellationToken).ConfigureAwait(false); + using Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(authority); + try + { + connection = await http3ConnectionWaiter.WaitWithCancellationAsync(cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, ex); + throw; + } } // Request cannot be sent over H/3 connection, try downgrade or report failure. @@ -98,6 +107,9 @@ internal sealed partial class HttpConnectionPool return null; } + Activity? connectionSetupActivity = connection.ConnectionSetupActivity; + if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(connectionSetupActivity); + HttpResponseMessage response = await connection.SendAsync(request, queueStartingTimestamp, cancellationToken).ConfigureAwait(false); // If an Alt-Svc authority returns 421, it means it can't actually handle the request. @@ -245,20 +257,22 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. CancellationTokenSource cts = GetConnectTimeoutCancellationTokenSource(); waiter.ConnectionCancellationTokenSource = cts; + Activity? connectionSetupActivity = null; try { if (TryGetHttp3Authority(queueItem.Request, out authority, out Exception? reasonException)) { + connectionSetupActivity = ConnectionSetupDiagnostics.StartConnectionSetupActivity(isSecure: true, authority); // If the authority was sent as an option through alt-svc then include alt-used header. connection = new Http3Connection(this, authority, includeAltUsedHeader: _http3Authority == authority); - QuicConnection quicConnection = await ConnectHelper.ConnectQuicAsync(queueItem.Request, new DnsEndPoint(authority.IdnHost, authority.Port), _poolManager.Settings._pooledConnectionIdleTimeout, _sslOptionsHttp3!, connection.StreamCapacityCallback, cts.Token).ConfigureAwait(false); if (quicConnection.NegotiatedApplicationProtocol != SslApplicationProtocol.Http3) { await quicConnection.DisposeAsync().ConfigureAwait(false); throw new HttpRequestException(HttpRequestError.ConnectionError, "QUIC connected but no HTTP/3 indicated via ALPN.", null, RequestRetryType.RetryOnConnectionFailure); } - connection.InitQuicConnection(quicConnection); + if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, null, quicConnection.RemoteEndPoint); + connection.InitQuicConnection(quicConnection, connectionSetupActivity); } else if (reasonException is not null) { @@ -271,6 +285,9 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. CreateConnectTimeoutException(oce) : e; + Debug.Assert(connectionSetupActivity?.IsStopped is not true); + if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, e, null); + // If the connection hasn't been initialized with QuicConnection, get rid of it. connection?.Dispose(); connection = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 1224bdee5b961..be96cc9279b31 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -89,9 +89,9 @@ public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, bool in } } - public void InitQuicConnection(QuicConnection connection) + public void InitQuicConnection(QuicConnection connection, Activity? connectionSetupActivity) { - MarkConnectionAsEstablished(connectionSetupActivity: null, remoteEndPoint: connection.RemoteEndPoint); + MarkConnectionAsEstablished(connectionSetupActivity: connectionSetupActivity, remoteEndPoint: connection.RemoteEndPoint); _connection = connection; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index fa4cc340c46f5..a0d5ec13bc16b 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -591,8 +591,7 @@ public async Task SendAsync_Success_ConnectionSetupActivityGraphRecorded(bool us { if (UseVersion == HttpVersion30 && !useTls) return; - await RunTest(UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()); - //await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); + await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), useTls.ToString()).DisposeAsync(); static async Task RunTest(string useVersion, string testAsync, string useTlsString) { bool useTls = bool.Parse(useTlsString); @@ -692,13 +691,13 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( // Verify display names and attributes: Assert.Equal(ActivityKind.Internal, wait1.Kind); Assert.Equal(ActivityKind.Internal, conn.Kind); - Assert.Equal($"HTTP wait_for_connection localhost:{uri.Port}", wait1.DisplayName); - Assert.Equal($"HTTP connection_setup localhost:{uri.Port}", conn.DisplayName); + Assert.Equal($"HTTP wait_for_connection {uri.Host}:{uri.Port}", wait1.DisplayName); + Assert.Equal($"HTTP connection_setup {uri.Host}:{uri.Port}", conn.DisplayName); ActivityAssert.HasTag(conn, "network.peer.address", (string a) => a == IPAddress.Loopback.ToString() || a == IPAddress.Loopback.MapToIPv6().ToString() || a == IPAddress.IPv6Loopback.ToString()); - ActivityAssert.HasTag(conn, "server.address", "localhost"); + ActivityAssert.HasTag(conn, "server.address", uri.Host); ActivityAssert.HasTag(conn, "server.port", uri.Port); ActivityAssert.HasTag(conn, "url.scheme", useTls ? "https" : "http"); @@ -739,8 +738,9 @@ public async Task SendAsync_ConnectionFailure_RecordsActivitiesWithCorrectErrorI await RemoteExecutor.Invoke(RunTest, UseVersion.ToString(), TestAsync.ToString(), failureType).DisposeAsync(); static async Task RunTest(string useVersion, string testAsync, string failureType) { - using HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); - + Version version = Version.Parse(useVersion); + + using HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); using HttpClient client = new HttpClient(handler); Activity parentActivity = new Activity("parent").Start(); @@ -757,20 +757,23 @@ static async Task RunTest(string useVersion, string testAsync, string failureTyp using ActivityRecorder socketRecorder = new("Experimental.System.Net.Sockets", "Experimental.System.Net.Sockets.Connect") { VerifyParent = false }; Uri uri; - using Socket? notListening = failureType is "socket" ? new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) : null; + using Socket? notListening = failureType is "socket" + ? (version == HttpVersion30) ? new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) : new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) + : null; + if (failureType is "dns") { - uri = new Uri("http://does.not.exist.sorry"); + uri = new Uri("https://does.not.exist.sorry"); } else { Debug.Assert(notListening is not null); notListening.Bind(new IPEndPoint(IPAddress.Loopback, 0)); IPEndPoint ep = (IPEndPoint)notListening.LocalEndPoint; - uri = new Uri($"http://{ep.Address}:{ep.Port}"); + uri = new Uri($"https://{ep.Address}:{ep.Port}"); } - using HttpRequestMessage request = CreateRequest(HttpMethod.Get, uri, Version.Parse(useVersion), exactVersion: true); + using HttpRequestMessage request = CreateRequest(HttpMethod.Get, uri, version, exactVersion: true); await Assert.ThrowsAsync(() => client.SendAsync(bool.Parse(testAsync), request)); Activity req = requestRecorder.VerifyActivityRecordedOnce(); @@ -782,27 +785,38 @@ static async Task RunTest(string useVersion, string testAsync, string failureTyp if (failureType == "dns") { - Activity dns = dnsRecorder.VerifyActivityRecordedOnce(); - Assert.Same(conn, dns.Parent); - Assert.Equal(ActivityStatusCode.Error, dns.Status); Assert.Equal(ActivityStatusCode.Error, conn.Status); Assert.Equal(ActivityStatusCode.Error, wait.Status); - ActivityAssert.HasTag(dns, "error.type", (string t) => t is "host_not_found" or "timed_out"); + ActivityAssert.HasTag(conn, "error.type", "name_resolution_error"); ActivityAssert.HasTag(wait, "error.type", "name_resolution_error"); + + // Whether System.Net.Quic uses System.Net.Dns is an implementation detail. + if (version != HttpVersion30) + { + Activity dns = dnsRecorder.VerifyActivityRecordedOnce(); + Assert.Same(conn, dns.Parent); + Assert.Equal(ActivityStatusCode.Error, dns.Status); + ActivityAssert.HasTag(dns, "error.type", (string t) => t is "host_not_found" or "timed_out"); + } } else { Debug.Assert(failureType is "socket"); - Activity sock = socketRecorder.VerifyActivityRecordedOnce(); - Assert.Same(conn, sock.Parent); - - Assert.Equal(ActivityStatusCode.Error, sock.Status); + Assert.Equal(ActivityStatusCode.Error, conn.Status); Assert.Equal(ActivityStatusCode.Error, wait.Status); - ActivityAssert.HasTag(sock, "error.type", (string t) => t is "connection_refused" or "timed_out"); + ActivityAssert.HasTag(conn, "error.type", "connection_error"); ActivityAssert.HasTag(wait, "error.type", "connection_error"); + + if (version != HttpVersion30) + { + Activity sock = socketRecorder.VerifyActivityRecordedOnce(); + Assert.Same(conn, sock.Parent); + Assert.Equal(ActivityStatusCode.Error, sock.Status); + ActivityAssert.HasTag(sock, "error.type", (string t) => t is "connection_refused" or "timed_out"); + } } } } From 8c008e119c92e6417380ca466ed513d0d250d27f Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 11 Jul 2024 02:56:37 +0200 Subject: [PATCH 27/37] actually use the same ActivitySource for ConnectionSetup & WaitForConnection --- .../System/Net/Http/DiagnosticsHandlerLoggingStrings.cs | 7 +++---- .../ConnectionPool/ConnectionSetupDiagnostics.cs | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs index c22ff068c44c0..975ab45405631 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandlerLoggingStrings.cs @@ -17,9 +17,8 @@ internal static class DiagnosticsHandlerLoggingStrings public const string RequestActivityStartName = RequestActivityName + ".Start"; public const string RequestActivityStopName = RequestActivityName + ".Stop"; - public const string ConnectionNamespace = "Experimental.System.Net.Http.Connections"; - public const string ConnectionSetupActivityName = ConnectionNamespace + ".ConnectionSetup"; - public const string WaitForConnectionNamespace = ConnectionNamespace; - public const string WaitForConnectionActivityName = WaitForConnectionNamespace + ".WaitForConnection"; + public const string ConnectionsNamespace = "Experimental.System.Net.Http.Connections"; + public const string ConnectionSetupActivityName = ConnectionsNamespace + ".ConnectionSetup"; + public const string WaitForConnectionActivityName = ConnectionsNamespace + ".WaitForConnection"; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs index aaa2ae66b2751..d971854d437bd 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs @@ -10,18 +10,17 @@ namespace System.Net.Http // Implements distributed tracing logic for managing the "HTTP connection_setup" and "HTTP wait_for_connection" Activities. internal static class ConnectionSetupDiagnostics { - private static readonly ActivitySource s_connectionSetupActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionNamespace); - private static readonly ActivitySource s_waitForConnectionActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.WaitForConnectionNamespace); + private static readonly ActivitySource s_connectionsActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionsNamespace); public static Activity? StartConnectionSetupActivity(bool isSecure, HttpAuthority authority) { Activity? activity = null; - if (s_connectionSetupActivitySource.HasListeners()) + if (s_connectionsActivitySource.HasListeners()) { // Connection activities should be new roots and not parented under whatever // request happens to be in progress when the connection is started. Activity.Current = null; - activity = s_connectionSetupActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName); + activity = s_connectionsActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName); } if (activity is not null) @@ -72,7 +71,7 @@ public static void ReportError(Activity? activity, Exception exception) public static Activity? StartWaitForConnectionActivity(HttpAuthority authority) { - Activity? activity = s_waitForConnectionActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); + Activity? activity = s_connectionsActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); if (activity is not null) { activity.DisplayName = $"HTTP wait_for_connection {authority.HostValue}:{authority.Port}"; From e829df2965c590646dcf9fb1babb59e839d36e44 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 11 Jul 2024 23:46:39 +0200 Subject: [PATCH 28/37] *handshake --- .../src/System/Net/Security/SslStream.IO.cs | 2 +- .../tests/FunctionalTests/TelemetryTest.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 435142e0ca3cc..a740ceb9d2fe6 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -139,7 +139,7 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell using Activity? activity = s_activitySource.StartActivity(ActivityName); if (activity is not null) { - activity.DisplayName = IsServer ? "TLS server" : $"TLS client {TargetHostName}"; + activity.DisplayName = IsServer ? "TLS server handshake" : $"TLS client handshake {TargetHostName}"; if (activity.IsAllDataRequested && !IsServer) { activity.SetTag("server.address", TargetHostName); diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs index 281e0dff3a657..393c62140d55a 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TelemetryTest.cs @@ -67,7 +67,7 @@ await RemoteExecutor.Invoke(async synchronousApiStr => Assert.Equal(ActivityKind.Internal, clientActivity.Kind); Assert.True(clientActivity.Duration > TimeSpan.Zero); Assert.Equal(ActivityName, clientActivity.OperationName); - Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); + Assert.Equal($"TLS client handshake {test.Name}", clientActivity.DisplayName); ActivityAssert.HasTag(clientActivity, "server.address", test.Name); ActivityAssert.HasTag(clientActivity, "tls.protocol.name", protocolName); ActivityAssert.HasTag(clientActivity, "tls.protocol.version", protocolVersion); @@ -76,7 +76,7 @@ await RemoteExecutor.Invoke(async synchronousApiStr => Assert.Equal(ActivityKind.Internal, serverActivity.Kind); Assert.True(serverActivity.Duration > TimeSpan.Zero); Assert.Equal(ActivityName, serverActivity.OperationName); - Assert.StartsWith($"TLS server", serverActivity.DisplayName); + Assert.StartsWith($"TLS server handshake", serverActivity.DisplayName); ActivityAssert.HasTag(serverActivity, "tls.protocol.name", protocolName); ActivityAssert.HasTag(serverActivity, "tls.protocol.version", protocolVersion); ActivityAssert.HasNoTag(serverActivity, "error.type"); @@ -103,14 +103,14 @@ await RemoteExecutor.Invoke(async () => Assert.Equal(ActivityStatusCode.Error, clientActivity.Status); Assert.True(clientActivity.Duration > TimeSpan.Zero); Assert.Equal(ActivityName, clientActivity.OperationName); - Assert.Equal($"TLS client {test.Name}", clientActivity.DisplayName); + Assert.Equal($"TLS client handshake {test.Name}", clientActivity.DisplayName); ActivityAssert.HasTag(clientActivity, "server.address", test.Name); ActivityAssert.HasTag(clientActivity, "error.type", typeof(AuthenticationException).FullName); Assert.Equal(ActivityKind.Internal, serverActivity.Kind); Assert.True(serverActivity.Duration > TimeSpan.Zero); Assert.Equal(ActivityName, serverActivity.OperationName); - Assert.StartsWith($"TLS server", serverActivity.DisplayName); + Assert.StartsWith($"TLS server handshake", serverActivity.DisplayName); }).DisposeAsync(); } From 7c94ae81a84d5b74bb913e0568ede5b244739edc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 11 Jul 2024 23:53:04 +0200 Subject: [PATCH 29/37] Update src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../src/System/Net/NameResolutionTelemetry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index ba6f625e31bd4..07a252fbd250c 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -158,7 +158,7 @@ internal readonly struct NameResolutionActivity { private const string ActivitySourceName = "Experimental.System.Net.NameResolution"; private const string ActivityName = ActivitySourceName + ".DnsLookup"; - private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + private static readonly ActivitySource s_activitySource = new ActivitySource(ActivitySourceName); // _startingTimestamp == 0 means NameResolutionTelemetry and NameResolutionMetrics are both disabled. private readonly long _startingTimestamp; From 06896bf22fa325b65e500b059d8ade541a4cc296 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 12 Jul 2024 01:41:48 +0200 Subject: [PATCH 30/37] fix H3 logic based on feedback --- .../ConnectionPool/HttpConnectionPool.Http3.cs | 11 ++++------- .../Http/SocketsHttpHandler/Http3Connection.cs | 15 ++++++++++++--- .../tests/FunctionalTests/DiagnosticsTests.cs | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs index 5800f8747c084..579af33e8735f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs @@ -85,10 +85,10 @@ internal sealed partial class HttpConnectionPool } long queueStartingTimestamp = HttpTelemetry.Log.IsEnabled() || Settings._metrics!.RequestsQueueDuration.Enabled ? Stopwatch.GetTimestamp() : 0; + Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(authority); if (!TryGetPooledHttp3Connection(request, out Http3Connection? connection, out HttpConnectionWaiter? http3ConnectionWaiter)) { - using Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(authority); try { connection = await http3ConnectionWaiter.WaitWithCancellationAsync(cancellationToken).ConfigureAwait(false); @@ -96,6 +96,7 @@ internal sealed partial class HttpConnectionPool catch (Exception ex) { ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, ex); + waitForConnectionActivity?.Stop(); throw; } } @@ -107,10 +108,7 @@ internal sealed partial class HttpConnectionPool return null; } - Activity? connectionSetupActivity = connection.ConnectionSetupActivity; - if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(connectionSetupActivity); - - HttpResponseMessage response = await connection.SendAsync(request, queueStartingTimestamp, cancellationToken).ConfigureAwait(false); + HttpResponseMessage response = await connection.SendAsync(request, queueStartingTimestamp, waitForConnectionActivity, cancellationToken).ConfigureAwait(false); // If an Alt-Svc authority returns 421, it means it can't actually handle the request. // An authority is supposed to be able to handle ALL requests to the origin, so this is a server bug. @@ -285,8 +283,7 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. CreateConnectTimeoutException(oce) : e; - Debug.Assert(connectionSetupActivity?.IsStopped is not true); - if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, e, null); + if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, connectionException, null); // If the connection hasn't been initialized with QuicConnection, get rid of it. connection?.Dispose(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index be96cc9279b31..c695df0b0f910 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -241,7 +241,7 @@ public Task WaitForAvailableStreamsAsync() } } - public async Task SendAsync(HttpRequestMessage request, long queueStartingTimestamp, CancellationToken cancellationToken) + public async Task SendAsync(HttpRequestMessage request, long queueStartingTimestamp, Activity? waitForConnectionActivity, CancellationToken cancellationToken) { // Allocate an active request QuicStream? quicStream = null; @@ -269,10 +269,17 @@ public async Task SendAsync(HttpRequestMessage request, lon } // Swallow any exceptions caused by the connection being closed locally or even disposed due to a race. // Since quicStream will stay `null`, the code below will throw appropriate exception to retry the request. - catch (ObjectDisposedException) { } - catch (QuicException e) when (e.QuicError != QuicError.OperationAborted) { } + catch (ObjectDisposedException e) + { + ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, e); + } + catch (QuicException e) when (e.QuicError != QuicError.OperationAborted) + { + ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, e); + } finally { + waitForConnectionActivity?.Stop(); if (queueStartingTimestamp != 0) { TimeSpan duration = Stopwatch.GetElapsedTime(queueStartingTimestamp); @@ -304,6 +311,8 @@ public async Task SendAsync(HttpRequestMessage request, lon throw new HttpRequestException(HttpRequestError.Unknown, SR.net_http_request_aborted, null, RequestRetryType.RetryOnConnectionFailure); } + Debug.Assert(waitForConnectionActivity?.IsStopped != false); + if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); Task responseTask = requestStream.SendAsync(cancellationToken); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index a0d5ec13bc16b..43507ebe97947 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -706,7 +706,7 @@ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync( requestRecorder.VerifyActivityRecorded(2); Activity req2 = requestRecorder.LastFinishedActivity; Assert.NotSame(req1, req2); - waitForConnectionRecorder.VerifyActivityRecorded(1); + waitForConnectionRecorder.VerifyActivityRecorded(version == HttpVersion30 ? 2 : 1); connectionSetupRecorder.VerifyActivityRecorded(1); // The second request should also have a link to the shared connection. From b455d17282a35f83c9f9070a0a2e0c54f6d88fd2 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 12 Jul 2024 01:47:38 +0200 Subject: [PATCH 31/37] ConnectionSetupDiagnostics -> ConnectionSetupDistributedTracing --- .../System.Net.Http/src/System.Net.Http.csproj | 2 +- ...nostics.cs => ConnectionSetupDistributedTracing.cs} | 2 +- .../ConnectionPool/HttpConnectionPool.Http3.cs | 10 +++++----- .../ConnectionPool/HttpConnectionPool.cs | 4 ++-- .../ConnectionPool/HttpConnectionWaiter.cs | 4 ++-- .../Net/Http/SocketsHttpHandler/Http2Connection.cs | 2 +- .../Net/Http/SocketsHttpHandler/Http3Connection.cs | 6 +++--- .../Net/Http/SocketsHttpHandler/HttpConnection.cs | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) rename src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/{ConnectionSetupDiagnostics.cs => ConnectionSetupDistributedTracing.cs} (98%) diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index f1a64dd5bd299..5a824c7c5aa7c 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -175,7 +175,7 @@ - + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDistributedTracing.cs similarity index 98% rename from src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs rename to src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDistributedTracing.cs index d971854d437bd..aaa60449f410c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDiagnostics.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDistributedTracing.cs @@ -8,7 +8,7 @@ namespace System.Net.Http { // Implements distributed tracing logic for managing the "HTTP connection_setup" and "HTTP wait_for_connection" Activities. - internal static class ConnectionSetupDiagnostics + internal static class ConnectionSetupDistributedTracing { private static readonly ActivitySource s_connectionsActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionsNamespace); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs index 579af33e8735f..3a1d7e11324f3 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs @@ -85,7 +85,7 @@ internal sealed partial class HttpConnectionPool } long queueStartingTimestamp = HttpTelemetry.Log.IsEnabled() || Settings._metrics!.RequestsQueueDuration.Enabled ? Stopwatch.GetTimestamp() : 0; - Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(authority); + Activity? waitForConnectionActivity = ConnectionSetupDistributedTracing.StartWaitForConnectionActivity(authority); if (!TryGetPooledHttp3Connection(request, out Http3Connection? connection, out HttpConnectionWaiter? http3ConnectionWaiter)) { @@ -95,7 +95,7 @@ internal sealed partial class HttpConnectionPool } catch (Exception ex) { - ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, ex); + ConnectionSetupDistributedTracing.ReportError(waitForConnectionActivity, ex); waitForConnectionActivity?.Stop(); throw; } @@ -260,7 +260,7 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. { if (TryGetHttp3Authority(queueItem.Request, out authority, out Exception? reasonException)) { - connectionSetupActivity = ConnectionSetupDiagnostics.StartConnectionSetupActivity(isSecure: true, authority); + connectionSetupActivity = ConnectionSetupDistributedTracing.StartConnectionSetupActivity(isSecure: true, authority); // If the authority was sent as an option through alt-svc then include alt-used header. connection = new Http3Connection(this, authority, includeAltUsedHeader: _http3Authority == authority); QuicConnection quicConnection = await ConnectHelper.ConnectQuicAsync(queueItem.Request, new DnsEndPoint(authority.IdnHost, authority.Port), _poolManager.Settings._pooledConnectionIdleTimeout, _sslOptionsHttp3!, connection.StreamCapacityCallback, cts.Token).ConfigureAwait(false); @@ -269,7 +269,7 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. await quicConnection.DisposeAsync().ConfigureAwait(false); throw new HttpRequestException(HttpRequestError.ConnectionError, "QUIC connected but no HTTP/3 indicated via ALPN.", null, RequestRetryType.RetryOnConnectionFailure); } - if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, null, quicConnection.RemoteEndPoint); + if (connectionSetupActivity is not null) ConnectionSetupDistributedTracing.StopConnectionSetupActivity(connectionSetupActivity, null, quicConnection.RemoteEndPoint); connection.InitQuicConnection(quicConnection, connectionSetupActivity); } else if (reasonException is not null) @@ -283,7 +283,7 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. CreateConnectTimeoutException(oce) : e; - if (connectionSetupActivity is not null) ConnectionSetupDiagnostics.StopConnectionSetupActivity(connectionSetupActivity, connectionException, null); + if (connectionSetupActivity is not null) ConnectionSetupDistributedTracing.StopConnectionSetupActivity(connectionSetupActivity, connectionException, null); // If the connection hasn't been initialized with QuicConnection, get rid of it. connection?.Dispose(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index 5573df990656f..4770b49203624 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -572,7 +572,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn Exception? exception = null; TransportContext? transportContext = null; - Activity? activity = ConnectionSetupDiagnostics.StartConnectionSetupActivity(IsSecure, OriginAuthority); + Activity? activity = ConnectionSetupDistributedTracing.StartConnectionSetupActivity(IsSecure, OriginAuthority); try { @@ -648,7 +648,7 @@ public async ValueTask SendWithVersionDetectionAndRetryAsyn { if (activity is not null) { - ConnectionSetupDiagnostics.StopConnectionSetupActivity(activity, exception, remoteEndPoint); + ConnectionSetupDistributedTracing.StopConnectionSetupActivity(activity, exception, remoteEndPoint); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs index 72f51bd7c0557..9e1e0f7127d68 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionWaiter.cs @@ -30,14 +30,14 @@ private async ValueTask WaitForConnectionWithTelemetryAsync(HttpRequestMessag long startingTimestamp = Stopwatch.GetTimestamp(); - using Activity? waitForConnectionActivity = ConnectionSetupDiagnostics.StartWaitForConnectionActivity(pool.OriginAuthority); + using Activity? waitForConnectionActivity = ConnectionSetupDistributedTracing.StartWaitForConnectionActivity(pool.OriginAuthority); try { return await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false); } catch (Exception ex) when (waitForConnectionActivity is not null) { - ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, ex); + ConnectionSetupDistributedTracing.ReportError(waitForConnectionActivity, ex); throw; } finally diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 20f8a91c812e4..71dec0acc09db 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -1980,7 +1980,7 @@ public async Task SendAsync(HttpRequestMessage request, boo Debug.Assert(async); Debug.Assert(!_pool.HasSyncObjLock); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); - if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); + if (ConnectionSetupActivity is not null) ConnectionSetupDistributedTracing.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index c695df0b0f910..d2f1389ae1207 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -271,11 +271,11 @@ public async Task SendAsync(HttpRequestMessage request, lon // Since quicStream will stay `null`, the code below will throw appropriate exception to retry the request. catch (ObjectDisposedException e) { - ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, e); + ConnectionSetupDistributedTracing.ReportError(waitForConnectionActivity, e); } catch (QuicException e) when (e.QuicError != QuicError.OperationAborted) { - ConnectionSetupDiagnostics.ReportError(waitForConnectionActivity, e); + ConnectionSetupDistributedTracing.ReportError(waitForConnectionActivity, e); } finally { @@ -312,7 +312,7 @@ public async Task SendAsync(HttpRequestMessage request, lon } Debug.Assert(waitForConnectionActivity?.IsStopped != false); - if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); + if (ConnectionSetupActivity is not null) ConnectionSetupDistributedTracing.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); Task responseTask = requestStream.SendAsync(cancellationToken); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index af08767a5431a..e71c4c743d631 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -548,7 +548,7 @@ public async Task SendAsync(HttpRequestMessage request, boo // Send the request. if (NetEventSource.Log.IsEnabled()) Trace($"Sending request: {request}"); - if (ConnectionSetupActivity is not null) ConnectionSetupDiagnostics.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); + if (ConnectionSetupActivity is not null) ConnectionSetupDistributedTracing.AddConnectionLinkToRequestActivity(ConnectionSetupActivity); CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken); try { From 56e8cb3655dee4729092e9fef93fab89f2236dc0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 12 Jul 2024 16:26:29 +0200 Subject: [PATCH 32/37] suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../System.Net.Security/src/System/Net/Security/SslStream.IO.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 238c925ca3c97..0c62f850f0c8c 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -18,7 +18,7 @@ public partial class SslStream private const string ActivitySourceName = "Experimental.System.Net.Security"; private const string ActivityName = ActivitySourceName + ".TlsHandshake"; - private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + private static readonly ActivitySource s_activitySource = new ActivitySource(ActivitySourceName); private readonly SslAuthenticationOptions _sslAuthenticationOptions = new SslAuthenticationOptions(); private int _nestedAuth; From 870eae516d30c4a83350815b5a7a5a94985d2b31 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 12 Jul 2024 16:27:30 +0200 Subject: [PATCH 33/37] suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../src/System/Net/Sockets/SocketsTelemetry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 00daf69152d99..612e972e57acc 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -12,7 +12,7 @@ internal sealed class SocketsTelemetry : EventSource { private const string ActivitySourceName = "Experimental.System.Net.Sockets"; private const string ConnectActivityName = ActivitySourceName + ".Connect"; - private static readonly ActivitySource s_connectActivitySource = new(ActivitySourceName); + private static readonly ActivitySource s_connectActivitySource = new ActivitySource(ActivitySourceName); public static readonly SocketsTelemetry Log = new SocketsTelemetry(); From de774dd3242c0922bdd351213a9d87f518724bad Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 12 Jul 2024 16:27:48 +0200 Subject: [PATCH 34/37] suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../tests/FunctionalTests/System.Net.Sockets.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index 02ba46be4f07a..2b5c1cea632f0 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -79,7 +79,7 @@ Link="SocketCommon\SocketImplementationType.cs" /> + Link="Common\System\Net\ActivityRecorder.cs" /> Date: Fri, 12 Jul 2024 18:15:38 +0200 Subject: [PATCH 35/37] implement 'network.transport' --- .../src/System/Net/Sockets/Socket.cs | 4 ++-- .../src/System/Net/Sockets/SocketsTelemetry.cs | 13 ++++++++++++- .../tests/FunctionalTests/TelemetryTest.cs | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 82b1171a3146e..02edb8853f909 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2782,7 +2782,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan WildcardBindForConnectIfNecessary(endPointSnapshot.AddressFamily); - e.ConnectActivity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, endPointSnapshot, keepActivityCurrent: true); + e.ConnectActivity = SocketsTelemetry.Log.ConnectStart(e._socketAddress!, _protocolType, endPointSnapshot, keepActivityCurrent: true); // Prepare for the native call. try @@ -3191,7 +3191,7 @@ private SocketAddress Serialize(ref EndPoint remoteEP) private void DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) { - Activity? activity = SocketsTelemetry.Log.ConnectStart(socketAddress, endPointSnapshot, keepActivityCurrent: false); + Activity? activity = SocketsTelemetry.Log.ConnectStart(socketAddress, _protocolType, endPointSnapshot, keepActivityCurrent: false); SocketError errorCode; try { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs index 612e972e57acc..2a7abb81f60b8 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketsTelemetry.cs @@ -81,7 +81,7 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) } [NonEvent] - public Activity? ConnectStart(SocketAddress address, EndPoint endPoint, bool keepActivityCurrent) + public Activity? ConnectStart(SocketAddress address, ProtocolType protocolType, EndPoint endPoint, bool keepActivityCurrent) { Interlocked.Increment(ref _currentOutgoingConnectAttempts); @@ -113,6 +113,14 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) activity.SetTag("network.peer.address", ipEndPoint.Address.ToString()); activity.SetTag("network.peer.port", port); activity.SetTag("network.type", ipEndPoint.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); + if (protocolType is ProtocolType.Tcp) + { + SetNetworkTransport(activity, "tcp"); + } + else if (protocolType is ProtocolType.Udp) + { + SetNetworkTransport(activity, "udp"); + } } } else if (endPoint is UnixDomainSocketEndPoint udsEndPoint) @@ -123,10 +131,13 @@ private void AcceptFailed(SocketError error, string? exceptionMessage) if (activity.IsAllDataRequested) { activity.SetTag("network.peer.address", peerAddress); + SetNetworkTransport(activity, "unix"); } } } + static void SetNetworkTransport(Activity activity, string transportType) => activity.SetTag("network.transport", transportType); + return activity; } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index 825ef3234700c..5bc5beb9201ce 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -154,6 +154,7 @@ static void VerifyTcpConnectActivity(Activity activity, IPEndPoint remoteEndPoin ActivityAssert.HasTag(activity, "network.peer.address", address); ActivityAssert.HasTag(activity, "network.peer.port", port); ActivityAssert.HasTag(activity, "network.type", ipv6 ? "ipv6" : "ipv4"); + ActivityAssert.HasTag(activity, "network.transport", "tcp"); } [OuterLoop("Connection failure takes long on Windows.")] @@ -225,6 +226,7 @@ await RemoteExecutor.Invoke(static async connectMethod => Assert.Equal(ActivityName, activity.OperationName); Assert.Equal($"socket connect {endPoint}", activity.DisplayName); ActivityAssert.HasTag(activity, "network.peer.address", endPoint.ToString()); + ActivityAssert.HasTag(activity, "network.transport", "unix"); }, connectMethod).DisposeAsync(); } From d99734f0895465ce78b099b8f8db4c46122aa6d0 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 12 Jul 2024 19:31:27 +0200 Subject: [PATCH 36/37] SslStream: move Activity management code to NetSecurityTelemetry --- .../Net/Security/NetSecurityTelemetry.cs | 58 +++++++++++++++++++ .../src/System/Net/Security/SslStream.IO.cs | 56 ++---------------- .../src/System/Net/Security/SslStream.cs | 2 +- 3 files changed, 64 insertions(+), 52 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs index c751742175af9..6b425c2891935 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs @@ -12,6 +12,11 @@ namespace System.Net.Security [EventSource(Name = "System.Net.Security")] internal sealed class NetSecurityTelemetry : EventSource { + private const string ActivitySourceName = "Experimental.System.Net.Security"; + private const string ActivityName = ActivitySourceName + ".TlsHandshake"; + + private static readonly ActivitySource s_activitySource = new ActivitySource(ActivitySourceName); + private const string EventSourceSuppressMessage = "Parameters to this method are primitive and are trimmer safe"; public static readonly NetSecurityTelemetry Log = new NetSecurityTelemetry(); @@ -39,6 +44,8 @@ internal sealed class NetSecurityTelemetry : EventSource private long _sessionsOpenTls12; private long _sessionsOpenTls13; + public static bool AnyTelemetryEnabled() => Log.IsEnabled() || s_activitySource.HasListeners(); + protected override void OnEventCommand(EventCommandEventArgs command) { if (command.Command == EventCommand.Enable) @@ -304,5 +311,56 @@ private unsafe void WriteEvent(int eventId, bool arg1, double arg2, string? arg3 WriteEventCore(eventId, NumEventDatas, descrs); } } + + [NonEvent] + public static Activity? StartActivity(SslStream stream) + { + using Activity? activity = s_activitySource.StartActivity(ActivityName); + if (activity is not null) + { + activity.DisplayName = stream.IsServer ? "TLS server handshake" : $"TLS client handshake {stream.TargetHostName}"; + if (activity.IsAllDataRequested && !stream.IsServer) + { + activity.SetTag("server.address", stream.TargetHostName); + } + } + return activity; + } + + [NonEvent] + public static void StopActivity(Activity? activity, Exception? exception, SslStream stream) + { + if (activity?.IsAllDataRequested != true) return; + + SslProtocols protocol = stream.GetSslProtocolInternal(); + (string? protocolName, string? protocolVersion) = GetNameAndVersionString(protocol); + + if (protocolName is not null) + { + Debug.Assert(protocolVersion is not null); + activity.SetTag("tls.protocol.name", protocolName); + activity.SetTag("tls.protocol.version", protocolVersion); + } + + if (exception is not null) + { + activity.SetStatus(ActivityStatusCode.Error); + activity.SetTag("error.type", exception.GetType().FullName); + } + + static (string?, string?) GetNameAndVersionString(SslProtocols protocol) => protocol switch + { +#pragma warning disable 0618 // Ssl2, Ssl3 are deprecated. + SslProtocols.Ssl2 => ("ssl", "2"), + SslProtocols.Ssl3 => ("ssl", "3"), +#pragma warning restore 0618 +#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete. + SslProtocols.Tls => ("tls", "1"), + SslProtocols.Tls12 => ("tls", "1.2"), +#pragma warning restore SYSLIB0039 + SslProtocols.Tls13 => ("tls", "1.3"), + _ => (null, null) + }; + } } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 0c62f850f0c8c..0275b8fa5cfea 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -15,11 +15,6 @@ namespace System.Net.Security { public partial class SslStream { - private const string ActivitySourceName = "Experimental.System.Net.Security"; - private const string ActivityName = ActivitySourceName + ".TlsHandshake"; - - private static readonly ActivitySource s_activitySource = new ActivitySource(ActivitySourceName); - private readonly SslAuthenticationOptions _sslAuthenticationOptions = new SslAuthenticationOptions(); private int _nestedAuth; private bool _isRenego; @@ -111,7 +106,7 @@ private Task ProcessAuthenticationAsync(bool isAsync = false, CancellationToken { ThrowIfExceptional(); - if (NetSecurityTelemetry.Log.IsEnabled() || s_activitySource.HasListeners()) + if (NetSecurityTelemetry.AnyTelemetryEnabled()) { return ProcessAuthenticationWithTelemetryAsync(isAsync, cancellationToken); } @@ -136,18 +131,8 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell startingTimestamp = 0; } - using Activity? activity = s_activitySource.StartActivity(ActivityName); - if (activity is not null) - { - activity.DisplayName = IsServer ? "TLS server handshake" : $"TLS client handshake {TargetHostName}"; - if (activity.IsAllDataRequested && !IsServer) - { - activity.SetTag("server.address", TargetHostName); - } - } - + Activity? activity = NetSecurityTelemetry.StartActivity(this); Exception? exception = null; - SslProtocols? protocol = null; try { Task task = isAsync ? @@ -161,8 +146,8 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell // SslStream could already have been disposed at this point, in which case _connectionOpenedStatus == 2 // Make sure that we increment the open connection counter only if it is guaranteed to be decremented in dispose/finalize bool connectionOpen = Interlocked.CompareExchange(ref _connectionOpenedStatus, 1, 0) == 0; - protocol = GetSslProtocolInternal(); - NetSecurityTelemetry.Log.HandshakeCompleted(protocol.Value, startingTimestamp, connectionOpen); + SslProtocols protocol = GetSslProtocolInternal(); + NetSecurityTelemetry.Log.HandshakeCompleted(protocol, startingTimestamp, connectionOpen); } } catch (Exception ex) @@ -177,39 +162,8 @@ private async Task ProcessAuthenticationWithTelemetryAsync(bool isAsync, Cancell } finally { - if (activity is not null && activity.IsAllDataRequested) - { - protocol ??= GetSslProtocolInternal(); - (string? protocolName, string? protocolVersion) = GetNameAndVersionString(protocol.Value); - - if (protocolName is not null) - { - Debug.Assert(protocolVersion is not null); - activity.SetTag("tls.protocol.name", protocolName); - activity.SetTag("tls.protocol.version", protocolVersion); - } - - if (exception is not null) - { - activity.SetStatus(ActivityStatusCode.Error); - activity.SetTag("error.type", exception.GetType().FullName); - } - } + NetSecurityTelemetry.StopActivity(activity, exception, this); } - - static (string?, string?) GetNameAndVersionString(SslProtocols protocol) => protocol switch - { -#pragma warning disable 0618 // Ssl2, Ssl3 are deprecated. - SslProtocols.Ssl2 => ("ssl", "2"), - SslProtocols.Ssl3 => ("ssl", "3"), -#pragma warning restore 0618 -#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete. - SslProtocols.Tls => ("tls", "1"), - SslProtocols.Tls12 => ("tls", "1.2"), -#pragma warning restore SYSLIB0039 - SslProtocols.Tls13 => ("tls", "1.3"), - _ => (null, null) - }; } // diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs index 82ca35d1b0d5f..5b991106dbc3b 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs @@ -486,7 +486,7 @@ public virtual SslProtocols SslProtocol } // Skips the ThrowIfExceptionalOrNotHandshake() check - private SslProtocols GetSslProtocolInternal() + internal SslProtocols GetSslProtocolInternal() { if (_connectionInfo.Protocol == 0) { From ae587f7dc2609a581e9bc014cf286f6a9668c802 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Fri, 12 Jul 2024 19:51:50 +0200 Subject: [PATCH 37/37] readd assertion and add comment --- .../ConnectionPool/HttpConnectionPool.Http3.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs index 3a1d7e11324f3..bae0ef3895255 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.Http3.cs @@ -283,6 +283,9 @@ private async Task InjectNewHttp3ConnectionAsync(RequestQueue. CreateConnectTimeoutException(oce) : e; + // On success path connectionSetupActivity is stopped before calling InitQuicConnection(). + // This assertion makes sure that InitQuicConnection() does not throw unexpectedly. + Debug.Assert(connectionSetupActivity?.IsStopped is not true); if (connectionSetupActivity is not null) ConnectionSetupDistributedTracing.StopConnectionSetupActivity(connectionSetupActivity, connectionException, null); // If the connection hasn't been initialized with QuicConnection, get rid of it.