Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<Nullable>enable</Nullable>
<EnablePreviewFeatures>True</EnablePreviewFeatures>
<NoWarn>CA2252</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<!-- Shared production code -->
<ItemGroup>
<Compile Include="..\..\..\..\Common\src\System\Net\Logging\NetEventSource.Common.cs" Link="Common\System\Net\Logging\NetEventSource.Common.cs" />
<Compile Include="..\..\..\..\System.Net.Quic\src\System\Net\Quic\Internal\MsQuicApi.cs" Link="ProductionCode\System\Net\Quic\Internal\MsQuicApi.cs" />
<Compile Include="..\..\..\..\System.Net.Quic\src\System\Net\Quic\Internal\MsQuicSafeHandle.cs" Link="ProductionCode\System\Net\Quic\Internal\MsQuicSafeHandle.cs" />
<Compile Include="..\..\..\..\System.Net.Quic\src\System\Net\Quic\Interop\*.cs" Link="ProductionCode\System\Net\Quic\Interop\*.cs" />
<Compile Include="..\..\..\..\System.Net.Quic\src\System\Net\Quic\NetEventSource.Quic.cs" Link="ProductionCode\System\Net\Quic\NetEventSource.Quic.cs" />
Copy link
Contributor

@antonfirsov antonfirsov Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A refactor of these internals may break stress builds without us noticing, but I guess there is no good way to deal with this. We should remember that HttpStress took a dependency.

Copy link
Contributor

@antonfirsov antonfirsov Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: these files are missing from the docker context on Windows, which is why the Windows build failed. Copying them would make this solution even more fragile. Can we implement the worker delay tuning hack with reflection instead and share that implementation between System.Net.Quic.Functional.Tests and the stress tests to make sure we notice if it's broken? That would also remove the need of including anything but QuicDefaults.cs in System.Net.Quic.Functional.Tests.csproj (apart from the utility containing the hack).

Copy link
Contributor

@antonfirsov antonfirsov Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no, we would need #75347 to invoke function pointers with reflection safely. I guess, the best would be to copy & include msquic_generated.cs, then do a combination of reflection + code that only depends on the generated types.

I can take over if you want.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reflection was one of the options we discussed with @CarnaViire when implementing this in functional tests. I was able to workaround it in functional tests with source code inclusion, which is normal for corresponding tests. However, here it proves problematic.
I could re-work this to create an internal function on MsQuicApi which we would invoke via reflection from both functional tests as well as stress.

</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="5.0.9" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
using System.Threading.Tasks;
using System.Net;
using HttpStress;
using System.Net.Quic;
using Microsoft.Quic;

[assembly:SupportedOSPlatform("windows")]
[assembly:SupportedOSPlatform("linux")]
Expand All @@ -26,6 +28,8 @@ public static class Program
{
public enum ExitCode { Success = 0, StressError = 1, CliError = 2 };

public static readonly bool IsQuicSupported = QuicListener.IsSupported && QuicConnection.IsSupported;

public static async Task<int> Main(string[] args)
{
if (!TryParseCli(args, out Configuration? config))
Expand Down Expand Up @@ -169,14 +173,28 @@ private static async Task<ExitCode> Run(Configuration config)
Console.WriteLine(" Concurrency: " + config.ConcurrentRequests);
Console.WriteLine(" Content Length: " + config.MaxContentLength);
Console.WriteLine(" HTTP Version: " + config.HttpVersion);
Console.WriteLine(" QUIC supported: " + (IsQuicSupported ? "yes" : "no"));
Console.WriteLine(" MsQuic Version: " + MsQuicApi.MsQuicLibraryVersion);
Console.WriteLine(" Lifetime: " + (config.ConnectionLifetime.HasValue ? $"{config.ConnectionLifetime.Value.TotalMilliseconds}ms" : "(infinite)"));
Console.WriteLine(" Operations: " + string.Join(", ", usedClientOperations.Select(o => o.name)));
Console.WriteLine(" Random Seed: " + config.RandomSeed);
Console.WriteLine(" Cancellation: " + 100 * config.CancellationProbability + "%");
Console.WriteLine("Max Content Size: " + config.MaxContentLength);
Console.WriteLine("Query Parameters: " + config.MaxParameters);
Console.WriteLine();

if (config.HttpVersion == HttpVersion.Version30 && IsQuicSupported)
{
unsafe
{
QUIC_SETTINGS settings = default(QUIC_SETTINGS);
settings.IsSet.MaxWorkerQueueDelayUs = 1;
settings.MaxWorkerQueueDelayUs = 2_500_000u; // 2.5s, 10x the default
if (MsQuic.StatusFailed(MsQuicApi.Api.ApiTable->SetParam(null, MsQuic.QUIC_PARAM_GLOBAL_SETTINGS, (uint)sizeof(QUIC_SETTINGS), (byte*)&settings)))
{
Console.WriteLine($"Unable to set MsQuic MaxWorkerQueueDelayUs.");
}
}
}

StressServer? server = null;
if (config.RunMode.HasFlag(RunMode.server))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using static Microsoft.Quic.MsQuic;

namespace System.Net.Quic;

internal static class ThrowHelper
{
internal static Exception GetExceptionForMsQuicStatus(int status, string? message = null)
=> new QuicException(QuicError.InternalError, null, $"{message} (0x{status:x})");

internal static void ThrowIfMsQuicError(int status, string? message = null)
{
if (StatusFailed(status))
{
throw GetExceptionForMsQuicStatus(status, message);
}
}
}

internal static partial class Interop
{
internal static partial class Libraries
{
#if WINDOWS
internal const string MsQuic = "msquic.dll";
#elif OSX
internal const string MsQuic = "libmsquic.dylib";
#else
internal const string MsQuic = "libmsquic.so";
#endif
}
}