<ApiExclusionListPath Condition="'$(TargetPlatformIdentifier)' == ''">ExcludeApiList.PNSE.txt</ApiExclusionListPath>
<!-- This controls if we consume official binaries from MsQuic or if we use binaries published from dotnet/msquic repo.
Release branches should generally consume MsQuic release code, transport allows us to consume and test pre-released versions -->
- <UseQuicTransportPackage Condition="'$(UseQuicTransportPackage)' == ''">true</UseQuicTransportPackage>
+ <UseQuicTransportPackage Condition="'$(UseQuicTransportPackage)' == ''">false</UseQuicTransportPackage>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.Versioning.RequiresPreviewFeaturesAttribute" />
{
private static readonly Version s_minWindowsVersion = new Version(10, 0, 20145, 1000);
- private static readonly Version s_minMsQuicVersion = new Version(2, 1);
+ private static readonly Version s_minMsQuicVersion = new Version(2, 2, 2);
private static readonly delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> MsQuicOpenVersion;
private static readonly delegate* unmanaged[Cdecl]<QUIC_API_TABLE*, void> MsQuicClose;
await serverConnection.DisposeAsync();
}
+ [Fact]
+ public async Task OpenStreamAsync_BlocksUntilAvailable_PeerClosesWritingUnidirectional()
+ {
+ QuicListenerOptions listenerOptions = new QuicListenerOptions()
+ {
+ ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0),
+ ApplicationProtocols = new List<SslApplicationProtocol>() { 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<TimeoutException>(() => clientConnection.OpenOutboundStreamAsync(QuicStreamType.Unidirectional).AsTask().WaitAsync(TimeSpan.FromSeconds(1)));
+
+ await clientConnection.DisposeAsync();
+ await serverConnection.DisposeAsync();
+ }
+
[Theory]
[InlineData(false)]
[InlineData(true)]
// 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();