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 781b6676f5665..9f1e840303635 100644 --- a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs +++ b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs @@ -290,6 +290,8 @@ public partial class Socket : System.IDisposable public short Ttl { get { throw null; } set { } } public bool UseOnlyOverlappedIO { get { throw null; } set { } } public System.Net.Sockets.Socket Accept() { throw null; } + public System.Threading.Tasks.Task AcceptAsync() { throw null; } + public System.Threading.Tasks.Task AcceptAsync(System.Net.Sockets.Socket? acceptSocket) { throw null; } public bool AcceptAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public System.IAsyncResult BeginAccept(System.AsyncCallback? callback, object? state) { throw null; } public System.IAsyncResult BeginAccept(int receiveSize, System.AsyncCallback? callback, object? state) { throw null; } @@ -320,6 +322,14 @@ public partial class Socket : System.IDisposable public void Connect(System.Net.IPAddress address, int port) { } public void Connect(System.Net.IPAddress[] addresses, int port) { } public void Connect(string host, int port) { } + public System.Threading.Tasks.Task ConnectAsync(System.Net.EndPoint remoteEP) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(System.Net.EndPoint remoteEP, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task ConnectAsync(System.Net.IPAddress address, 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.Task ConnectAsync(System.Net.IPAddress[] addresses, int port) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(System.Net.IPAddress[] addresses, int port, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task ConnectAsync(string host, int port) { throw null; } + public System.Threading.Tasks.ValueTask ConnectAsync(string host, int port, System.Threading.CancellationToken cancellationToken) { throw null; } public bool ConnectAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public static bool ConnectAsync(System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType, System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public void Disconnect(bool reuseSocket) { } @@ -362,13 +372,18 @@ public partial class Socket : System.IDisposable public int Receive(System.Span buffer) { throw null; } public int Receive(System.Span buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } public int Receive(System.Span buffer, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; } + public System.Threading.Tasks.Task ReceiveAsync(System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + public System.Threading.Tasks.Task ReceiveAsync(System.Collections.Generic.IList> buffers, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + public System.Threading.Tasks.ValueTask ReceiveAsync(System.Memory buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public bool ReceiveAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public int ReceiveFrom(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; } public int ReceiveFrom(byte[] buffer, int size, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; } public int ReceiveFrom(byte[] buffer, ref System.Net.EndPoint remoteEP) { throw null; } public int ReceiveFrom(byte[] buffer, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; } + public System.Threading.Tasks.Task ReceiveFromAsync(System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; } public bool ReceiveFromAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP, out System.Net.Sockets.IPPacketInformation ipPacketInformation) { throw null; } + public System.Threading.Tasks.Task ReceiveMessageFromAsync(System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; } public bool ReceiveMessageFromAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public static void Select(System.Collections.IList? checkRead, System.Collections.IList? checkWrite, System.Collections.IList? checkError, int microSeconds) { } public int Send(byte[] buffer) { throw null; } @@ -382,6 +397,9 @@ public partial class Socket : System.IDisposable public int Send(System.ReadOnlySpan buffer) { throw null; } public int Send(System.ReadOnlySpan buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } public int Send(System.ReadOnlySpan buffer, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; } + public System.Threading.Tasks.Task SendAsync(System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + public System.Threading.Tasks.Task SendAsync(System.Collections.Generic.IList> buffers, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + public System.Threading.Tasks.ValueTask SendAsync(System.ReadOnlyMemory buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public bool SendAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } public void SendFile(string? fileName) { } public void SendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, System.Net.Sockets.TransmitFileOptions flags) { } @@ -390,6 +408,7 @@ public partial class Socket : System.IDisposable public int SendTo(byte[] buffer, int size, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; } public int SendTo(byte[] buffer, System.Net.EndPoint remoteEP) { throw null; } public int SendTo(byte[] buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; } + public System.Threading.Tasks.Task SendToAsync(System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; } public bool SendToAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] public void SetIPProtectionLevel(System.Net.Sockets.IPProtectionLevel level) { } @@ -552,24 +571,43 @@ public enum SocketShutdown } public static partial class SocketTaskExtensions { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task AcceptAsync(this System.Net.Sockets.Socket socket) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task AcceptAsync(this System.Net.Sockets.Socket socket, System.Net.Sockets.Socket? acceptSocket) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.EndPoint remoteEP) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.EndPoint remoteEP, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress address, int port) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] 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; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, System.Net.IPAddress[] addresses, int port) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] 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; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ConnectAsync(this System.Net.Sockets.Socket socket, string host, int port) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.ValueTask ConnectAsync(this System.Net.Sockets.Socket socket, string host, int port, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ReceiveAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] 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; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] 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; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ReceiveFromAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task ReceiveMessageFromAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task SendAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task SendAsync(this System.Net.Sockets.Socket socket, System.Collections.Generic.IList> buffers, System.Net.Sockets.SocketFlags socketFlags) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.ValueTask SendAsync(this System.Net.Sockets.Socket socket, System.ReadOnlyMemory buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Threading.Tasks.Task SendToAsync(this System.Net.Sockets.Socket socket, System.ArraySegment buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; } } public enum SocketType 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 3f8e8a75fa55b..07cc7af8128c4 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 @@ -28,7 +28,18 @@ public partial class Socket /// Cached instance for send operations that return . private TaskSocketAsyncEventArgs? _multiBufferSendEventArgs; - internal Task AcceptAsync(Socket? acceptSocket) + /// + /// Accepts an incoming connection. + /// + /// An asynchronous task that completes with the accepted Socket. + public Task AcceptAsync() => AcceptAsync((Socket?)null); + + /// + /// Accepts an incoming connection. + /// + /// The socket to use for accepting the connection. + /// An asynchronous task that completes with the accepted Socket. + public Task AcceptAsync(Socket? acceptSocket) { // Get any cached SocketAsyncEventArg we may have. TaskSocketAsyncEventArgs? saea = Interlocked.Exchange(ref _acceptEventArgs, null); @@ -71,9 +82,20 @@ internal Task AcceptAsync(Socket? acceptSocket) return t; } - internal Task ConnectAsync(EndPoint remoteEP) => ConnectAsync(remoteEP, default).AsTask(); - - internal ValueTask ConnectAsync(EndPoint remoteEP, CancellationToken cancellationToken) + /// + /// Establishes a connection to a remote host. + /// + /// The endpoint to connect to. + /// An asynchronous task that completes when the connection is established. + public Task ConnectAsync(EndPoint remoteEP) => ConnectAsync(remoteEP, default).AsTask(); + + /// + /// Establishes a connection to a remote host. + /// + /// The endpoint to connect to. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes when the connection is established. + public ValueTask ConnectAsync(EndPoint remoteEP, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { @@ -114,16 +136,41 @@ static async ValueTask WaitForConnectWithCancellation(AwaitableSocketAsyncEventA throw; } } - } - internal Task ConnectAsync(IPAddress address, int port) => ConnectAsync(new IPEndPoint(address, 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) + /// + /// Establishes a connection to a remote host. + /// + /// The IPAddress of the remote host to connect to. + /// The port on the remote host to connect to. + /// An asynchronous task that completes when the connection is established. + public Task ConnectAsync(IPAddress address, int port) => ConnectAsync(new IPEndPoint(address, port)); + + /// + /// Establishes a connection to a remote host. + /// + /// The IPAddress of the remote host to connect to. + /// The port on the remote host to connect to. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes when the connection is established. + public ValueTask ConnectAsync(IPAddress address, int port, CancellationToken cancellationToken) => ConnectAsync(new IPEndPoint(address, port), cancellationToken); + + /// + /// Establishes a connection to a remote host. + /// + /// A list of IPAddresses for the remote host that will be used to attempt to connect to the remote host. + /// The port on the remote host to connect to. + /// An asynchronous task that completes when the connection is established. + public Task ConnectAsync(IPAddress[] addresses, int port) => ConnectAsync(addresses, port, CancellationToken.None).AsTask(); + + /// + /// Establishes a connection to a remote host. + /// + /// A list of IPAddresses for the remote host that will be used to attempt to connect to the remote host. + /// The port on the remote host to connect to. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes when the connection is established. + public ValueTask ConnectAsync(IPAddress[] addresses, int port, CancellationToken cancellationToken) { ThrowIfDisposed(); @@ -188,9 +235,22 @@ async ValueTask Core(IPAddress[] addresses, int port, CancellationToken cancella } } - internal Task ConnectAsync(string host, int port) => ConnectAsync(host, port, default).AsTask(); - - internal ValueTask ConnectAsync(string host, int port, CancellationToken cancellationToken) + /// + /// Establishes a connection to a remote host. + /// + /// The hostname of the remote host to connect to. + /// The port on the remote host to connect to. + /// An asynchronous task that completes when the connection is established. + public Task ConnectAsync(string host, int port) => ConnectAsync(host, port, default).AsTask(); + + /// + /// Establishes a connection to a remote host. + /// + /// The hostname of the remote host to connect to. + /// The port on the remote host to connect to. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes when the connection is established. + public ValueTask ConnectAsync(string host, int port, CancellationToken cancellationToken) { if (host == null) { @@ -203,12 +263,30 @@ internal ValueTask ConnectAsync(string host, int port, CancellationToken cancell return ConnectAsync(ep, cancellationToken); } + /// + /// Receives data from a connected socket. + /// + /// The buffer for the received data. + /// A bitwise combination of SocketFlags values that will be used when receiving the data. + /// An asynchronous task that completes with the number of bytes received. + public Task ReceiveAsync(ArraySegment buffer, SocketFlags socketFlags) => ReceiveAsync(buffer, socketFlags, fromNetworkStream: false); + internal Task ReceiveAsync(ArraySegment buffer, SocketFlags socketFlags, bool fromNetworkStream) { ValidateBuffer(buffer); return ReceiveAsync(buffer, socketFlags, fromNetworkStream, default).AsTask(); } + /// + /// Receives data from a connected socket. + /// + /// The buffer for the received data. + /// A bitwise combination of SocketFlags values that will be used when receiving the data. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes with the number of bytes received. + public ValueTask ReceiveAsync(Memory buffer, SocketFlags socketFlags, CancellationToken cancellationToken) => + ReceiveAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken); + internal ValueTask ReceiveAsync(Memory buffer, SocketFlags socketFlags, bool fromNetworkStream, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) @@ -227,7 +305,13 @@ internal ValueTask ReceiveAsync(Memory buffer, SocketFlags socketFlag return saea.ReceiveAsync(this, cancellationToken); } - internal Task ReceiveAsync(IList> buffers, SocketFlags socketFlags) + /// + /// Receives data from a connected socket. + /// + /// A list of buffers for the received data. + /// A bitwise combination of SocketFlags values that will be used when receiving the data. + /// An asynchronous task that completes with the number of bytes received. + public Task ReceiveAsync(IList> buffers, SocketFlags socketFlags) { ValidateBuffersList(buffers); @@ -243,7 +327,14 @@ internal Task ReceiveAsync(IList> buffers, SocketFlags s return GetTaskForSendReceive(ReceiveAsync(saea), saea, fromNetworkStream: false, isReceive: true); } - internal Task ReceiveFromAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) + /// + /// Receives data and returns the endpoint of the sending host. + /// + /// The buffer for the received data. + /// A bitwise combination of SocketFlags values that will be used when receiving the data. + /// An endpoint of the same type as the endpoint of the remote host. + /// An asynchronous task that completes with a SocketReceiveFromResult containing the number of bytes received and the endpoint of the sending host. + public Task ReceiveFromAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) { var tcs = new StateTaskCompletionSource(this) { _field1 = remoteEndPoint }; BeginReceiveFrom(buffer.Array!, buffer.Offset, buffer.Count, socketFlags, ref tcs._field1, iar => @@ -263,7 +354,14 @@ internal Task ReceiveFromAsync(ArraySegment buffe return tcs.Task; } - internal Task ReceiveMessageFromAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) + /// + /// Receives data and returns additional information about the sender of the message. + /// + /// The buffer for the received data. + /// A bitwise combination of SocketFlags values that will be used when receiving the data. + /// An endpoint of the same type as the endpoint of the remote host. + /// An asynchronous task that completes with a SocketReceiveMessageFromResult containing the number of bytes received and additional information about the sending host. + public Task ReceiveMessageFromAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) { var tcs = new StateTaskCompletionSource(this) { _field1 = socketFlags, _field2 = remoteEndPoint }; BeginReceiveMessageFrom(buffer.Array!, buffer.Offset, buffer.Count, socketFlags, ref tcs._field2, iar => @@ -286,13 +384,26 @@ internal Task ReceiveMessageFromAsync(ArraySegme return tcs.Task; } - internal Task SendAsync(ArraySegment buffer, SocketFlags socketFlags) + /// + /// Sends data on a connected socket. + /// + /// The buffer for the data to send. + /// A bitwise combination of SocketFlags values that will be used when sending the data. + /// An asynchronous task that completes with the number of bytes sent. + public Task SendAsync(ArraySegment buffer, SocketFlags socketFlags) { ValidateBuffer(buffer); return SendAsync(buffer, socketFlags, default).AsTask(); } - internal ValueTask SendAsync(ReadOnlyMemory buffer, SocketFlags socketFlags, CancellationToken cancellationToken) + /// + /// Sends data on a connected socket. + /// + /// The buffer for the data to send. + /// A bitwise combination of SocketFlags values that will be used when sending the data. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes with the number of bytes sent. + public ValueTask SendAsync(ReadOnlyMemory buffer, SocketFlags socketFlags, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { @@ -328,7 +439,13 @@ internal ValueTask SendAsyncForNetworkStream(ReadOnlyMemory buffer, Socket return saea.SendAsyncForNetworkStream(this, cancellationToken); } - internal Task SendAsync(IList> buffers, SocketFlags socketFlags) + /// + /// Sends data on a connected socket. + /// + /// A list of buffers for the data to send. + /// A bitwise combination of SocketFlags values that will be used when sending the data. + /// An asynchronous task that completes with the number of bytes sent. + public Task SendAsync(IList> buffers, SocketFlags socketFlags) { ValidateBuffersList(buffers); @@ -344,7 +461,14 @@ internal Task SendAsync(IList> buffers, SocketFlags sock return GetTaskForSendReceive(SendAsync(saea), saea, fromNetworkStream: false, isReceive: false); } - internal Task SendToAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEP) + /// + /// Sends data to the specified remote host. + /// + /// The buffer for the data to send. + /// A bitwise combination of SocketFlags values that will be used when sending the data. + /// The remote host to which to send the data. + /// An asynchronous task that completes with the number of bytes sent. + public Task SendToAsync(ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEP) { var tcs = new TaskCompletionSource(this); BeginSendTo(buffer.Array!, buffer.Offset, buffer.Count, socketFlags, remoteEP, iar => 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 f6a2243e626df..1d9a3d6826a62 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 @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.ComponentModel; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -9,45 +10,64 @@ namespace System.Net.Sockets { public static class SocketTaskExtensions { + [EditorBrowsable(EditorBrowsableState.Never)] public static Task AcceptAsync(this Socket socket) => - socket.AcceptAsync((Socket?)null); + socket.AcceptAsync(); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task AcceptAsync(this Socket socket, Socket? acceptSocket) => socket.AcceptAsync(acceptSocket); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ConnectAsync(this Socket socket, EndPoint remoteEP) => socket.ConnectAsync(remoteEP); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask ConnectAsync(this Socket socket, EndPoint remoteEP, CancellationToken cancellationToken) => socket.ConnectAsync(remoteEP, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ConnectAsync(this Socket socket, IPAddress address, int port) => socket.ConnectAsync(address, port); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask ConnectAsync(this Socket socket, IPAddress address, int port, CancellationToken cancellationToken) => socket.ConnectAsync(address, port, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ConnectAsync(this Socket socket, IPAddress[] addresses, int port) => socket.ConnectAsync(addresses, port); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask ConnectAsync(this Socket socket, IPAddress[] addresses, int port, CancellationToken cancellationToken) => socket.ConnectAsync(addresses, port, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ConnectAsync(this Socket socket, string host, int port) => socket.ConnectAsync(host, port); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask ConnectAsync(this Socket socket, string host, int port, CancellationToken cancellationToken) => socket.ConnectAsync(host, port, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ReceiveAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags) => - socket.ReceiveAsync(buffer, socketFlags, fromNetworkStream: false); + socket.ReceiveAsync(buffer, socketFlags); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask ReceiveAsync(this Socket socket, Memory buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) => - socket.ReceiveAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken: cancellationToken); + socket.ReceiveAsync(buffer, socketFlags, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ReceiveAsync(this Socket socket, IList> buffers, SocketFlags socketFlags) => socket.ReceiveAsync(buffers, socketFlags); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ReceiveFromAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) => socket.ReceiveFromAsync(buffer, socketFlags, remoteEndPoint); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task ReceiveMessageFromAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) => socket.ReceiveMessageFromAsync(buffer, socketFlags, remoteEndPoint); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task SendAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags) => socket.SendAsync(buffer, socketFlags); + [EditorBrowsable(EditorBrowsableState.Never)] public static ValueTask SendAsync(this Socket socket, ReadOnlyMemory buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) => socket.SendAsync(buffer, socketFlags, cancellationToken); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task SendAsync(this Socket socket, IList> buffers, SocketFlags socketFlags) => socket.SendAsync(buffers, socketFlags); + [EditorBrowsable(EditorBrowsableState.Never)] public static Task SendToAsync(this Socket socket, ArraySegment buffer, SocketFlags socketFlags, EndPoint remoteEP) => socket.SendToAsync(buffer, socketFlags, remoteEP); } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs index accf15c3ec7f5..003c7fdbbc611 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs @@ -505,7 +505,7 @@ public void Select_LargeList_Throws_ArgumentOutOfRange() [Fact] public void AcceptAsync_NullAsyncEventArgs_Throws_ArgumentNull() { - Assert.Throws(() => GetSocket().AcceptAsync(null)); + Assert.Throws(() => GetSocket().AcceptAsync((SocketAsyncEventArgs)null)); } [Fact] @@ -537,7 +537,7 @@ public void AcceptAsync_NotListening_Throws_InvalidOperation() [Fact] public void ConnectAsync_NullAsyncEventArgs_Throws_ArgumentNull() { - Assert.Throws(() => GetSocket().ConnectAsync(null)); + Assert.Throws(() => GetSocket().ConnectAsync((SocketAsyncEventArgs)null)); } [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTaskExtensionsTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTaskExtensionsTest.cs new file mode 100644 index 0000000000000..bdc7ec7e3ef0f --- /dev/null +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTaskExtensionsTest.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Threading.Tasks; + +using Xunit; + +namespace System.Net.Sockets.Tests +{ + public class SocketTaskExtensionsTest + { + [Fact] + public async Task EnsureMethodsAreCallable() + { + // The purpose of this test is just to ensure that the now-hidden extension methods in SocketTaskExtensions are + // properly invoking the underlying instance methods, and not accidentally binding to themselves, causing infinite recursion. + Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + IPEndPoint badEndPoint = new IPEndPoint(IPAddress.None, 0); + string badHostName = "nosuchhost.invalid"; + byte[] buffer = new byte[1]; + + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.AcceptAsync(s)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.AcceptAsync(s, null)); + + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badEndPoint)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badEndPoint, CancellationToken.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badEndPoint.Address, badEndPoint.Port)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badEndPoint.Address, badEndPoint.Port, CancellationToken.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, new IPAddress[] { badEndPoint.Address, badEndPoint.Address }, badEndPoint.Port)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, new IPAddress[] { badEndPoint.Address, badEndPoint.Address }, badEndPoint.Port, CancellationToken.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badHostName, badEndPoint.Port)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ConnectAsync(s, badHostName, badEndPoint.Port, CancellationToken.None)); + + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ReceiveAsync(s, new ArraySegment(buffer), SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ReceiveAsync(s, buffer.AsMemory(), SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ReceiveAsync(s, new ArraySegment[] { new ArraySegment(buffer) }, SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ReceiveFromAsync(s, new ArraySegment(buffer), SocketFlags.None, badEndPoint)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.ReceiveMessageFromAsync(s, new ArraySegment(buffer), SocketFlags.None, badEndPoint)); + + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.SendAsync(s, new ArraySegment(buffer), SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.SendAsync(s, buffer.AsMemory(), SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.SendAsync(s, new ArraySegment[] { new ArraySegment(buffer) }, SocketFlags.None)); + await Assert.ThrowsAsync(async () => await SocketTaskExtensions.SendToAsync(s, new ArraySegment(buffer), SocketFlags.None, badEndPoint)); + } + } +} diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index e2522c8009bcb..bda9103731e62 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -52,6 +52,7 @@ +