From a3941d0f719b561db511d350a7503d5190115d48 Mon Sep 17 00:00:00 2001 From: Aleksei Abakumkin <77539239+cranberry-knight@users.noreply.github.com> Date: Tue, 12 Apr 2022 16:39:26 +0300 Subject: [PATCH] Fix hanging of NamedPipeClientStream when connecting with infinite timeout (#66877) * Add new test for named pipe client stream. The test includes the situation when the NamedPipeClientStream doesn't response to the cancellation token. * Handle case with infinite timeout properly. --- .../System/IO/Pipes/NamedPipeClientStream.cs | 2 +- .../NamedPipeTests/NamedPipeTest.Specific.cs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs index 1667631bda0f6..8fd4c3f1da15a 100644 --- a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs +++ b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs @@ -137,7 +137,7 @@ private void ConnectInternal(int timeout, CancellationToken cancellationToken, i cancellationToken.ThrowIfCancellationRequested(); // Determine how long we should wait in this connection attempt - int waitTime = timeout - elapsed; + int waitTime = timeout == Timeout.Infinite ? CancellationCheckInterval : timeout - elapsed; if (cancellationToken.CanBeCanceled && waitTime > CancellationCheckInterval) { waitTime = CancellationCheckInterval; diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs index 64744e5a4e4fb..99c2c5d37910b 100644 --- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs +++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs @@ -675,6 +675,31 @@ public async Task ClientConnectAsync_With_Cancellation_Throws_Timeout_When_Pipe_ } } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] // Unix implementation doesn't rely on a timeout and cancellation token when connecting + public async Task ClientConnectAsync_Cancel_With_InfiniteTimeout() + { + string pipeName = PipeStreamConformanceTests.GetUniquePipeName(); + + using (var cts = new CancellationTokenSource()) + using (var server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1)) + using (var firstClient = new NamedPipeClientStream(pipeName)) + using (var secondClient = new NamedPipeClientStream(pipeName)) + { + var firstConnectionTasks = new Task[] + { + firstClient.ConnectAsync(), + server.WaitForConnectionAsync() + }; + + Assert.True(Task.WaitAll(firstConnectionTasks, 1000)); + + cts.CancelAfter(100); + + await Assert.ThrowsAsync(() => secondClient.ConnectAsync(cts.Token)).WaitAsync(1000); + } + } + public static IEnumerable GetCancellationTokens => new [] {