diff --git a/NuGet.config b/NuGet.config index 5404515dbd5bd8..7838cc3ddbacc0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,6 +9,10 @@ + + + + diff --git a/eng/Versions.props b/eng/Versions.props index 2a753afd4ea83c..bd9feab57cd1a7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -154,14 +154,10 @@ 1.1.0 17.4.0-preview-20220707-01 - 7.0.0-prerelease.23309.1 - 7.0.0-prerelease.23309.1 - 7.0.0-prerelease.23309.1 - 7.0.0-alpha.0.23367.2 7.0.0-prerelease.23321.1 7.0.0-prerelease.23321.1 7.0.0-prerelease.23321.1 - 7.0.0-alpha.0.23226.5 + 7.0.0-alpha.0.23367.2 2.4.2 1.0.0 2.4.5 @@ -183,7 +179,7 @@ 7.0.0-rtm.23362.1 - 2.1.1 + 2.2.2 7.0.0-alpha.1.22459.1 11.1.0-alpha.1.23115.1 diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 63b4a827d6790b..b6552b56e9efba 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -18,7 +18,7 @@ internal sealed unsafe partial class MsQuicApi { private static readonly Version MinWindowsVersion = new Version(10, 0, 20145, 1000); - private static readonly Version MinMsQuicVersion = new Version(2, 1); + private static readonly Version MinMsQuicVersion = new Version(2, 2, 2); private static readonly delegate* unmanaged[Cdecl] MsQuicOpenVersion; private static readonly delegate* unmanaged[Cdecl] MsQuicClose; diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs index 738c2365f604f7..e81786c5fbcb7d 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Interop/msquic_generated.cs @@ -129,6 +129,7 @@ internal enum QUIC_STREAM_OPEN_FLAGS NONE = 0x0000, UNIDIRECTIONAL = 0x0001, ZERO_RTT = 0x0002, + DELAY_FC_UPDATES = 0x0004, } [System.Flags] diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs index 83073bcfab5022..91386d957c5438 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs @@ -500,6 +500,8 @@ private unsafe int HandleEventPeerStreamStarted(ref PEER_STREAM_STARTED_DATA dat stream.Dispose(); return QUIC_STATUS_SUCCESS; } + + data.Flags |= QUIC_STREAM_OPEN_FLAGS.DELAY_FC_UPDATES; return QUIC_STATUS_SUCCESS; } private unsafe int HandleEventPeerCertificateReceived(ref PEER_CERTIFICATE_RECEIVED_DATA data) diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs index c032f4f8a14ea3..322f47a9e8425e 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs @@ -584,6 +584,32 @@ ValueTask OpenStreamAsync(QuicConnection connection) => unidirection await serverConnection.DisposeAsync(); } + [Fact] + public async Task OpenStreamAsync_BlocksUntilAvailable_PeerClosesWritingUnidirectional() + { + QuicListenerOptions listenerOptions = new QuicListenerOptions() + { + ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0), + ApplicationProtocols = new List() { ApplicationProtocol }, + ConnectionOptionsCallback = (_, _, _) => + { + var serverOptions = CreateQuicServerOptions(); + serverOptions.MaxInboundBidirectionalStreams = 1; + serverOptions.MaxInboundUnidirectionalStreams = 1; + return ValueTask.FromResult(serverOptions); + } + }; + (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(null, listenerOptions); + + // 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))); + + await clientConnection.DisposeAsync(); + await serverConnection.DisposeAsync(); + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -622,11 +648,24 @@ ValueTask OpenStreamAsync(QuicConnection connection, CancellationTok // Close the streams, the waitTask should finish as a result. await stream.DisposeAsync(); - QuicStream newStream = await serverConnection.AcceptInboundStreamAsync(); - await newStream.DisposeAsync(); + // Drain all server streams. + while (true) + { + using var acceptCts = new CancellationTokenSource(TimeSpan.FromSeconds(0.5)); + try + { + QuicStream serverStream = await serverConnection.AcceptInboundStreamAsync(acceptCts.Token); + await serverStream.DisposeAsync(); + } + catch (OperationCanceledException) + { + // Token expired, no more streams in the server queue, exit the loop. + break; + } + } // next call should work as intended - newStream = await OpenStreamAsync(clientConnection).AsTask().WaitAsync(TimeSpan.FromSeconds(10)); + var newStream = await OpenStreamAsync(clientConnection).AsTask().WaitAsync(TimeSpan.FromSeconds(10)); await newStream.DisposeAsync(); await clientConnection.DisposeAsync(); diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj b/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj index 62b1be2da62e95..18a4a8a0f8a521 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj @@ -4,6 +4,7 @@ true $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix true + CA2252