From 944d33e50f78cd6e59f14e9dac9b2dbc120535a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2020 21:09:32 +0200 Subject: [PATCH] [release/5.0-rc2] Restore exception compatibility in TcpListener.EndAccept*** (#41938) Backport of #41745 to release/5.0-rc2 --- .../src/System/Net/Sockets/TCPListener.cs | 18 +++++++++-- .../tests/FunctionalTests/TcpListenerTest.cs | 30 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs index 6c623fec1cfb9..34b0cbd858f13 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs @@ -211,13 +211,13 @@ public IAsyncResult BeginAcceptSocket(AsyncCallback? callback, object? state) => TaskToApm.Begin(AcceptSocketAsync(), callback, state); public Socket EndAcceptSocket(IAsyncResult asyncResult) => - TaskToApm.End(asyncResult); + EndAcceptCore(asyncResult); public IAsyncResult BeginAcceptTcpClient(AsyncCallback? callback, object? state) => TaskToApm.Begin(AcceptTcpClientAsync(), callback, state); public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult) => - TaskToApm.End(asyncResult); + EndAcceptCore(asyncResult); public Task AcceptSocketAsync() { @@ -280,5 +280,19 @@ private void CreateNewSocketIfNeeded() _allowNatTraversal = null; // Reset value to avoid affecting more sockets } } + + private TResult EndAcceptCore(IAsyncResult asyncResult) + { + try + { + return TaskToApm.End(asyncResult); + } + catch (SocketException) when (!_active) + { + // Socket.EndAccept(iar) throws ObjectDisposedException when the underlying socket gets closed. + // TcpClient's documented behavior was to propagate that exception, we need to emulate it for compatibility: + throw new ObjectDisposedException(typeof(Socket).FullName); + } + } } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs index eeab701bb96c5..e442a33ade7e2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs @@ -252,6 +252,36 @@ public void ExclusiveAddressUse_SetStartAndStopListenerThenRead_ReadSuccessfully Assert.True(listener.ExclusiveAddressUse); } + [Fact] + public void EndAcceptSocket_WhenStopped_ThrowsObjectDisposedException() + { + var listener = new TcpListener(IPAddress.Loopback, 0); + listener.Start(); + + IAsyncResult iar = listener.BeginAcceptSocket(callback: null, state: null); + + // Give some time for the underlying OS operation to start: + Thread.Sleep(50); + listener.Stop(); + + Assert.Throws(() => listener.EndAcceptSocket(iar)); + } + + [Fact] + public void EndAcceptTcpClient_WhenStopped_ThrowsObjectDisposedException() + { + var listener = new TcpListener(IPAddress.Loopback, 0); + listener.Start(); + + IAsyncResult iar = listener.BeginAcceptTcpClient(callback: null, state: null); + + // Give some time for the underlying OS operation to start: + Thread.Sleep(50); + listener.Stop(); + + Assert.Throws(() => listener.EndAcceptTcpClient(iar)); + } + private sealed class DerivedTcpListener : TcpListener { #pragma warning disable 0618