diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs index cba2f936ef8dd2..b97f4876bfa7f2 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs @@ -74,7 +74,7 @@ internal override async ValueTask ConnectAsync(CancellationToken cancellationTok } Socket socket = new Socket(_remoteEndPoint!.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - await socket.ConnectAsync(_remoteEndPoint).ConfigureAwait(false); + await socket.ConnectAsync(_remoteEndPoint, cancellationToken).ConfigureAwait(false); socket.NoDelay = true; _localEndPoint = (IPEndPoint?)socket.LocalEndPoint; diff --git a/src/libraries/System.Net.Connections/src/System.Net.Connections.csproj b/src/libraries/System.Net.Connections/src/System.Net.Connections.csproj index 7ccd9e6f600ab5..cf6682f2cd821e 100644 --- a/src/libraries/System.Net.Connections/src/System.Net.Connections.csproj +++ b/src/libraries/System.Net.Connections/src/System.Net.Connections.csproj @@ -18,7 +18,6 @@ - diff --git a/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/SocketsConnectionFactory.cs b/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/SocketsConnectionFactory.cs index 2936a04e0484cc..732ad9447828a5 100644 --- a/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/SocketsConnectionFactory.cs +++ b/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/SocketsConnectionFactory.cs @@ -64,27 +64,7 @@ public override async ValueTask ConnectAsync( try { - using var args = new TaskSocketAsyncEventArgs(); - args.RemoteEndPoint = endPoint; - - if (socket.ConnectAsync(args)) - { - using (cancellationToken.UnsafeRegister(static o => Socket.CancelConnectAsync((SocketAsyncEventArgs)o!), args)) - { - await args.Task.ConfigureAwait(false); - } - } - - if (args.SocketError != SocketError.Success) - { - if (args.SocketError == SocketError.OperationAborted) - { - cancellationToken.ThrowIfCancellationRequested(); - } - - throw NetworkErrorHelper.MapSocketException(new SocketException((int)args.SocketError)); - } - + await socket.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false); return new SocketConnection(socket); } catch (SocketException socketException) diff --git a/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/TaskSocketAsyncEventArgs.cs b/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/TaskSocketAsyncEventArgs.cs deleted file mode 100644 index a1bb69d3f0501e..00000000000000 --- a/src/libraries/System.Net.Connections/src/System/Net/Connections/Sockets/TaskSocketAsyncEventArgs.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Net.Sockets; -using System.Threading.Tasks; -using System.Threading.Tasks.Sources; - -namespace System.Net.Connections -{ - internal sealed class TaskSocketAsyncEventArgs : SocketAsyncEventArgs, IValueTaskSource - { - private ManualResetValueTaskSourceCore _valueTaskSource; - - public void ResetTask() => _valueTaskSource.Reset(); - public ValueTask Task => new ValueTask(this, _valueTaskSource.Version); - - public void GetResult(short token) => _valueTaskSource.GetResult(token); - public ValueTaskSourceStatus GetStatus(short token) => _valueTaskSource.GetStatus(token); - public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _valueTaskSource.OnCompleted(continuation, state, token, flags); - - public TaskSocketAsyncEventArgs() - : base(unsafeSuppressExecutionContextFlow: true) - { - } - - protected override void OnCompleted(SocketAsyncEventArgs e) - { - _valueTaskSource.SetResult(0); - } - } -} diff --git a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs index 11d3309cf116df..e965b80cef0ea6 100644 --- a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs +++ b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs @@ -555,9 +555,13 @@ public static partial class SocketTaskExtensions public static System.Threading.Tasks.Task AcceptAsync(this System.Net.Sockets.Socket socket) { throw null; } public static System.Threading.Tasks.Task AcceptAsync(this System.Net.Sockets.Socket socket, System.Net.Sockets.Socket? acceptSocket) { throw null; } public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.EndPoint remoteEP) { throw null; } + public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.EndPoint remoteEP, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress address, int port) { throw null; } + public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress address, int port, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress[] addresses, int port) { throw null; } + public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress[] addresses, int port, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, string host, int port) { throw null; } + public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, string host, int port, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task ReceiveAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } public static System.Threading.Tasks.Task ReceiveAsync(this System.Net.Sockets.Socket socket, System.Collections.Generic.IList> buffers, System.Net.Sockets.SocketFlags socketFlags) { throw null; } public static System.Threading.Tasks.ValueTask ReceiveAsync(this System.Net.Sockets.Socket socket, System.Memory buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -606,6 +610,9 @@ public void Connect(string hostname, int port) { } public System.Threading.Tasks.Task ConnectAsync(System.Net.IPAddress address, int port) { throw null; } public System.Threading.Tasks.Task ConnectAsync(System.Net.IPAddress[] addresses, int port) { throw null; } public System.Threading.Tasks.Task ConnectAsync(string host, int port) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(System.Net.IPAddress address, int port, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(System.Net.IPAddress[] addresses, int port, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(string host, int port, System.Threading.CancellationToken cancellationToken) { throw null; } public void Dispose() { } protected virtual void Dispose(bool disposing) { } public void EndConnect(System.IAsyncResult asyncResult) { } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs index 75a226949d933e..83b8e3e4bb737e 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs @@ -74,20 +74,59 @@ internal Task AcceptAsync(Socket? acceptSocket) return t; } - internal Task ConnectAsync(EndPoint remoteEP) + internal Task ConnectAsync(EndPoint remoteEP) => ConnectAsync(remoteEP, default).AsTask(); + + internal ValueTask ConnectAsync(EndPoint remoteEP, CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) + { + return ValueTask.FromCanceled(cancellationToken); + } + // Use _singleBufferReceiveEventArgs so the AwaitableSocketAsyncEventArgs can be re-used later for receives. AwaitableSocketAsyncEventArgs saea = Interlocked.Exchange(ref _singleBufferReceiveEventArgs, null) ?? new AwaitableSocketAsyncEventArgs(this, isReceiveForCaching: true); saea.RemoteEndPoint = remoteEP; - return saea.ConnectAsync(this).AsTask(); + + ValueTask connectTask = saea.ConnectAsync(this); + if (connectTask.IsCompleted || !cancellationToken.CanBeCanceled) + { + // Avoid async invocation overhead + return connectTask; + } + else + { + return WaitForConnectWithCancellation(saea, connectTask, cancellationToken); + } + + async ValueTask WaitForConnectWithCancellation(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken) + { + Debug.Assert(cancellationToken.CanBeCanceled); + try + { + using (cancellationToken.UnsafeRegister(o => CancelConnectAsync((SocketAsyncEventArgs)o!), saea)) + { + await connectTask.ConfigureAwait(false); + } + } + catch (SocketException se) when (se.SocketErrorCode == SocketError.OperationAborted) + { + cancellationToken.ThrowIfCancellationRequested(); + throw; + } + } + } internal Task ConnectAsync(IPAddress address, int port) => ConnectAsync(new IPEndPoint(address, port)); - internal Task ConnectAsync(IPAddress[] addresses, int port) + internal ValueTask ConnectAsync(IPAddress address, int port, CancellationToken cancellationToken) => ConnectAsync(new IPEndPoint(address, port), cancellationToken); + + internal Task ConnectAsync(IPAddress[] addresses, int port) => ConnectAsync(addresses, port, CancellationToken.None).AsTask(); + + internal ValueTask ConnectAsync(IPAddress[] addresses, int port, CancellationToken cancellationToken) { if (addresses == null) { @@ -98,20 +137,20 @@ internal Task ConnectAsync(IPAddress[] addresses, int port) throw new ArgumentException(SR.net_invalidAddressList, nameof(addresses)); } - return DoConnectAsync(addresses, port); + return DoConnectAsync(addresses, port, cancellationToken); } - private async Task DoConnectAsync(IPAddress[] addresses, int port) + private async ValueTask DoConnectAsync(IPAddress[] addresses, int port, CancellationToken cancellationToken) { Exception? lastException = null; foreach (IPAddress address in addresses) { try { - await ConnectAsync(address, port).ConfigureAwait(false); + await ConnectAsync(address, port, cancellationToken).ConfigureAwait(false); return; } - catch (Exception ex) + catch (Exception ex) when (ex is not OperationCanceledException) { lastException = ex; } @@ -121,7 +160,9 @@ private async Task DoConnectAsync(IPAddress[] addresses, int port) ExceptionDispatchInfo.Throw(lastException); } - internal Task ConnectAsync(string host, int port) + internal Task ConnectAsync(string host, int port) => ConnectAsync(host, port, default).AsTask(); + + internal ValueTask ConnectAsync(string host, int port, CancellationToken cancellationToken) { if (host == null) { @@ -131,7 +172,7 @@ internal Task ConnectAsync(string host, int port) EndPoint ep = IPAddress.TryParse(host, out IPAddress? parsedAddress) ? (EndPoint) new IPEndPoint(parsedAddress, port) : new DnsEndPoint(host, port); - return ConnectAsync(ep); + return ConnectAsync(ep, cancellationToken); } internal Task ReceiveAsync(ArraySegment buffer, SocketFlags socketFlags, bool fromNetworkStream) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs index abaf3fcc52b8cf..f6a2243e626df3 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs @@ -16,12 +16,20 @@ public static Task AcceptAsync(this Socket socket, Socket? acceptSocket) public static Task ConnectAsync(this Socket socket, EndPoint remoteEP) => socket.ConnectAsync(remoteEP); + public static ValueTask ConnectAsync(this Socket socket, EndPoint remoteEP, CancellationToken cancellationToken) => + socket.ConnectAsync(remoteEP, cancellationToken); public static Task ConnectAsync(this Socket socket, IPAddress address, int port) => socket.ConnectAsync(address, port); + public static ValueTask ConnectAsync(this Socket socket, IPAddress address, int port, CancellationToken cancellationToken) => + socket.ConnectAsync(address, port, cancellationToken); public static Task ConnectAsync(this Socket socket, IPAddress[] addresses, int port) => socket.ConnectAsync(addresses, port); + public static ValueTask ConnectAsync(this Socket socket, IPAddress[] addresses, int port, CancellationToken cancellationToken) => + socket.ConnectAsync(addresses, port, cancellationToken); public static Task ConnectAsync(this Socket socket, string host, int port) => socket.ConnectAsync(host, port); + public static ValueTask ConnectAsync(this Socket socket, string host, int port, CancellationToken cancellationToken) => + socket.ConnectAsync(host, port, cancellationToken); public static Task ReceiveAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags) => socket.ReceiveAsync(buffer, socketFlags, fromNetworkStream: false); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs index e70b1625a6c5a9..937d0d008b41e0 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs @@ -259,13 +259,8 @@ public void Connect(IPAddress[] ipAddresses, int port) _active = true; } - public Task ConnectAsync(IPAddress address, int port) - { - - Task result = CompleteConnectAsync(Client.ConnectAsync(address, port)); - - return result; - } + public Task ConnectAsync(IPAddress address, int port) => + CompleteConnectAsync(Client.ConnectAsync(address, port)); public Task ConnectAsync(string host, int port) => CompleteConnectAsync(Client.ConnectAsync(host, port)); @@ -279,6 +274,21 @@ private async Task CompleteConnectAsync(Task task) _active = true; } + public ValueTask ConnectAsync(IPAddress address, int port, CancellationToken cancellationToken) => + CompleteConnectAsync(Client.ConnectAsync(address, port, cancellationToken)); + + public ValueTask ConnectAsync(string host, int port, CancellationToken cancellationToken) => + CompleteConnectAsync(Client.ConnectAsync(host, port, cancellationToken)); + + public ValueTask ConnectAsync(IPAddress[] addresses, int port, CancellationToken cancellationToken) => + CompleteConnectAsync(Client.ConnectAsync(addresses, port, cancellationToken)); + + private async ValueTask CompleteConnectAsync(ValueTask task) + { + await task.ConfigureAwait(false); + _active = true; + } + public IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback? requestCallback, object? state) => Client.BeginConnect(address, port, requestCallback, state); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs index 48fe236978c34e..08ecf15f3b925b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs @@ -204,4 +204,133 @@ public sealed class ConnectEap : Connect { public ConnectEap(ITestOutputHelper output) : base(output) {} } + + public sealed class ConnectCancellableTask : Connect + { + public ConnectCancellableTask(ITestOutputHelper output) : base(output) { } + + [Fact] + public async Task ConnectEndPoint_Precanceled_Throws() + { + EndPoint ep = new IPEndPoint(IPAddress.Parse("1.2.3.4"), 1); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + + await Assert.ThrowsAnyAsync(async () => await client.ConnectAsync(ep, cts.Token)); + } + } + + [Fact] + public async Task ConnectAddressAndPort_Precanceled_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + + await Assert.ThrowsAnyAsync(async () => await client.ConnectAsync(IPAddress.Parse("1.2.3.4"), 1, cts.Token)); + } + } + + [Fact] + public async Task ConnectMultiAddressAndPort_Precanceled_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + + await Assert.ThrowsAnyAsync(async () => await client.ConnectAsync(new IPAddress[] { IPAddress.Parse("1.2.3.4"), IPAddress.Parse("1.2.3.5") }, 1, cts.Token)); + } + } + + [Fact] + public async Task ConnectHostNameAndPort_Precanceled_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + cts.Cancel(); + + await Assert.ThrowsAnyAsync(async () => await client.ConnectAsync("1.2.3.4", 1, cts.Token)); + } + } + + [Fact] + [OuterLoop("Uses Task.Delay")] + [PlatformSpecific(TestPlatforms.Windows)] // Linux will not even attempt to connect to the invalid IP address + public async Task ConnectEndPoint_CancelDuringConnect_Throws() + { + EndPoint ep = new IPEndPoint(IPAddress.Parse("1.2.3.4"), 1); + + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + + ValueTask t = client.ConnectAsync(ep, cts.Token); + + // Delay cancellation a bit to try to ensure the OS actually attempts to connect + cts.CancelAfter(100); + + await Assert.ThrowsAnyAsync(async () => await t); + } + } + + [Fact] + [OuterLoop("Uses Task.Delay")] + [PlatformSpecific(TestPlatforms.Windows)] // Linux will not even attempt to connect to the invalid IP address + public async Task ConnectAddressAndPort_CancelDuringConnect_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + + ValueTask t = client.ConnectAsync(IPAddress.Parse("1.2.3.4"), 1, cts.Token); + + // Delay cancellation a bit to try to ensure the OS actually attempts to connect + cts.CancelAfter(100); + + await Assert.ThrowsAnyAsync(async () => await t); + } + } + + [Fact] + [OuterLoop("Uses Task.Delay")] + [PlatformSpecific(TestPlatforms.Windows)] // Linux will not even attempt to connect to the invalid IP address + public async Task ConnectMultiAddressAndPort_CancelDuringConnect_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + + ValueTask t = client.ConnectAsync(new IPAddress[] { IPAddress.Parse("1.2.3.4"), IPAddress.Parse("1.2.3.5") }, 1, cts.Token); + + // Delay cancellation a bit to try to ensure the OS actually attempts to connect + cts.CancelAfter(100); + + await Assert.ThrowsAnyAsync(async () => await t); + } + } + + [Fact] + [OuterLoop("Uses Task.Delay")] + [PlatformSpecific(TestPlatforms.Windows)] // Linux will not even attempt to connect to the invalid IP address + public async Task ConnectHostNameAndPort_CancelDuringConnect_Throws() + { + using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + var cts = new CancellationTokenSource(); + + ValueTask t = client.ConnectAsync("1.2.3.4", 1, cts.Token); + + // Delay cancellation a bit to try to ensure the OS actually attempts to connect + cts.CancelAfter(100); + + await Assert.ThrowsAnyAsync(async () => await t); + } + } + } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index 307c7c505f60b0..41fa116b0c40c9 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -179,6 +180,36 @@ public override Task SendToAsync(Socket s, ArraySegment buffer, EndPo s.SendToAsync(buffer, SocketFlags.None, endPoint); } + // Same as above, but call the CancellationToken overloads where possible + public class SocketHelperCancellableTask : SocketHelperBase + { + // Use a cancellable CancellationToken that we never cancel so that implementations can't just elide handling the CancellationToken. + private readonly CancellationTokenSource _cts = new CancellationTokenSource(); + + public override Task AcceptAsync(Socket s) => + s.AcceptAsync(); + public override Task<(Socket socket, byte[] buffer)> AcceptAsync(Socket s, int receiveSize) + => throw new NotSupportedException(); + public override Task AcceptAsync(Socket s, Socket acceptSocket) => + s.AcceptAsync(acceptSocket); + public override Task ConnectAsync(Socket s, EndPoint endPoint) => + s.ConnectAsync(endPoint, _cts.Token).AsTask(); + public override Task MultiConnectAsync(Socket s, IPAddress[] addresses, int port) => + s.ConnectAsync(addresses, port, _cts.Token).AsTask(); + public override Task ReceiveAsync(Socket s, ArraySegment buffer) => + s.ReceiveAsync(buffer, SocketFlags.None, _cts.Token).AsTask(); + public override Task ReceiveAsync(Socket s, IList> bufferList) => + s.ReceiveAsync(bufferList, SocketFlags.None); + public override Task ReceiveFromAsync(Socket s, ArraySegment buffer, EndPoint endPoint) => + s.ReceiveFromAsync(buffer, SocketFlags.None, endPoint); + public override Task SendAsync(Socket s, ArraySegment buffer) => + s.SendAsync(buffer, SocketFlags.None, _cts.Token).AsTask(); + public override Task SendAsync(Socket s, IList> bufferList) => + s.SendAsync(bufferList, SocketFlags.None); + public override Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endPoint) => + s.SendToAsync(buffer, SocketFlags.None, endPoint); + } + public sealed class SocketHelperEap : SocketHelperBase { public override bool ValidatesArrayArguments => false; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs index c30fa492476726..a2ce1a28a66138 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs @@ -4,6 +4,7 @@ using Xunit; using Xunit.Abstractions; +using System.Threading; using System.Threading.Tasks; using System.Text; using System.Diagnostics; @@ -119,6 +120,9 @@ public void Ctor_StringInt_ConnectsSuccessfully() [InlineData(3)] [InlineData(4)] [InlineData(5)] + [InlineData(6)] + [InlineData(7)] + [InlineData(8)] public async Task ConnectAsync_DnsEndPoint_Success(int mode) { using (var client = new DerivedTcpClient()) @@ -155,6 +159,18 @@ public async Task ConnectAsync_DnsEndPoint_Success(int mode) addresses = await Dns.GetHostAddressesAsync(host); await Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, addresses, port, null); break; + + case 6: + await client.ConnectAsync(host, port, CancellationToken.None); + break; + case 7: + addresses = await Dns.GetHostAddressesAsync(host); + await client.ConnectAsync(addresses[0], port, CancellationToken.None); + break; + case 8: + addresses = await Dns.GetHostAddressesAsync(host); + await client.ConnectAsync(addresses, port, CancellationToken.None); + break; } Assert.True(client.Active);