diff --git a/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs b/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs index f4aecc5a3f548b..cdc0cee60754a0 100644 --- a/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs +++ b/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs @@ -32,6 +32,22 @@ internal static class TaskToApm public static IAsyncResult Begin(Task task, AsyncCallback? callback, object? state) => new TaskAsyncResult(task, state, callback); + public static Task GetSynchronousExceptionTask(Exception ex) => new FailedSynchronouslyCompletionSource(ex).Task; + + public static Task GetSynchronousExceptionTask(Exception ex) => new FailedSynchronouslyCompletionSource(ex).Task; + + public static ValueTask GetSynchronousExceptionValueTask(Exception ex) => new ValueTask(new FailedSynchronouslyCompletionSource(ex).Task); + + public static bool FailedSynchronously(this Task task) => task.IsFaulted && task.AsyncState is Exception; + + public static void ThrowIfFailedSynchronously(this Task task) + { + if (task.IsFaulted && task.AsyncState is Exception ex) + { + throw ex; + } + } + /// Processes an IAsyncResult returned by Begin. /// The IAsyncResult to unwrap. public static void End(IAsyncResult asyncResult) @@ -68,6 +84,22 @@ private static void ThrowArgumentException(IAsyncResult asyncResult) => new ArgumentNullException(nameof(asyncResult)) : new ArgumentException(null, nameof(asyncResult))); + private sealed class FailedSynchronouslyCompletionSource : TaskCompletionSource + { + public FailedSynchronouslyCompletionSource(Exception exception) : base(exception) + { + SetException(exception); + } + } + + private sealed class FailedSynchronouslyCompletionSource : TaskCompletionSource + { + public FailedSynchronouslyCompletionSource(Exception exception) : base(exception) + { + SetException(exception); + } + } + /// Provides a simple IAsyncResult that wraps a Task. /// /// We could use the Task as the IAsyncResult if the Task's AsyncState is the same as the object state, diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index bbddbb391d54b3..5361b650fc6ffb 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -43,7 +43,6 @@ - @@ -90,7 +89,6 @@ - @@ -185,7 +183,6 @@ Link="Common\System\Net\CompletionPortHelper.Windows.cs" /> - diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Unix.cs deleted file mode 100644 index 657544b27c319c..00000000000000 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Unix.cs +++ /dev/null @@ -1,54 +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; -using System.Diagnostics; -using System.Net; -using System.Runtime.InteropServices; -using System.Threading; -using Microsoft.Win32; - -namespace System.Net.Sockets -{ - // AcceptOverlappedAsyncResult - used to take care of storage for async Socket BeginAccept call. - internal sealed partial class AcceptOverlappedAsyncResult : BaseOverlappedAsyncResult - { - private Socket? _acceptedSocket; - - internal Socket? AcceptSocket - { - set - { - // *nix does not support the reuse of an existing socket as the accepted - // socket. - Debug.Assert(value == null, $"Unexpected value: {value}"); - } - } - - public void CompletionCallback(IntPtr acceptedFileDescriptor, byte[] socketAddress, int socketAddressLen, SocketError errorCode) - { - _buffer = null; - _numBytes = 0; - - if (errorCode == SocketError.Success) - { - Debug.Assert(_listenSocket._rightEndPoint != null); - - Internals.SocketAddress remoteSocketAddress = IPEndPointExtensions.Serialize(_listenSocket._rightEndPoint); - System.Buffer.BlockCopy(socketAddress, 0, remoteSocketAddress.Buffer, 0, socketAddressLen); - - _acceptedSocket = _listenSocket.CreateAcceptSocket( - SocketPal.CreateSocket(acceptedFileDescriptor), - _listenSocket._rightEndPoint.Create(remoteSocketAddress)); - } - - base.CompletionCallback(0, errorCode); - } - - internal override object? PostCompletion(int numBytes) - { - _numBytes = numBytes; - return (SocketError)ErrorCode == SocketError.Success ? _acceptedSocket : null; - } - } -} diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Windows.cs deleted file mode 100644 index d85b2bfc8c4aff..00000000000000 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.Windows.cs +++ /dev/null @@ -1,134 +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.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.Net.Sockets -{ - // AcceptOverlappedAsyncResult - used to take care of storage for async Socket BeginAccept call. - internal sealed partial class AcceptOverlappedAsyncResult : BaseOverlappedAsyncResult - { - private Socket? _acceptSocket; - private int _addressBufferLength; - - // This method will be called by us when the IO completes synchronously and - // by the ThreadPool when the IO completes asynchronously. (only called on WinNT) - internal override object? PostCompletion(int numBytes) - { - SocketError errorCode = (SocketError)ErrorCode; - - Internals.SocketAddress? remoteSocketAddress = null; - if (errorCode == SocketError.Success) - { - _numBytes = numBytes; - if (NetEventSource.Log.IsEnabled()) LogBuffer(numBytes); - - // get the endpoint - remoteSocketAddress = IPEndPointExtensions.Serialize(_listenSocket._rightEndPoint!); - - IntPtr localAddr; - int localAddrLength; - IntPtr remoteAddr; - - // set the socket context - bool refAdded = false; - SafeHandle safeHandle = _listenSocket.SafeHandle; - try - { - safeHandle.DangerousAddRef(ref refAdded); - IntPtr handle = safeHandle.DangerousGetHandle(); - - Debug.Assert(_buffer != null); - _listenSocket.GetAcceptExSockaddrs( - Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, 0), - _buffer.Length - (_addressBufferLength * 2), - _addressBufferLength, - _addressBufferLength, - out localAddr, - out localAddrLength, - out remoteAddr, - out remoteSocketAddress.InternalSize); - - Marshal.Copy(remoteAddr, remoteSocketAddress.Buffer, 0, remoteSocketAddress.Size); - - errorCode = Interop.Winsock.setsockopt( - _acceptSocket!.SafeHandle, - SocketOptionLevel.Socket, - SocketOptionName.UpdateAcceptContext, - ref handle, - IntPtr.Size); - - if (errorCode == SocketError.SocketError) - { - errorCode = SocketPal.GetLastSocketError(); - } - - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"setsockopt handle:{handle}, AcceptSocket:{_acceptSocket}, returns:{errorCode}"); - } - catch (ObjectDisposedException) - { - errorCode = SocketError.OperationAborted; - } - finally - { - if (refAdded) - { - safeHandle.DangerousRelease(); - } - } - - ErrorCode = (int)errorCode; - } - - if (errorCode != SocketError.Success) - { - return null; - } - - return _listenSocket.UpdateAcceptSocket(_acceptSocket!, _listenSocket._rightEndPoint!.Create(remoteSocketAddress!)); - } - - // SetUnmanagedStructures - // - // This method fills in overlapped structures used in an asynchronous - // overlapped Winsock call. These calls are outside the runtime and are - // unmanaged code, so we need to prepare specific structures and ints that - // lie in unmanaged memory since the overlapped calls may complete asynchronously. - internal void SetUnmanagedStructures(byte[] buffer, int addressBufferLength) - { - // has to be called first to pin memory - base.SetUnmanagedStructures(buffer); - - // Fill in Buffer Array structure that will be used for our send/recv Buffer - _addressBufferLength = addressBufferLength; - _buffer = buffer; - } - - private void LogBuffer(long size) - { - // This should only be called if tracing is enabled. However, there is the potential for a race - // condition where tracing is disabled between a calling check and here, in which case the assert - // may fire erroneously. - Debug.Assert(NetEventSource.Log.IsEnabled()); - Debug.Assert(_buffer != null); - - if (size > -1) - { - NetEventSource.DumpBuffer(this, _buffer, 0, Math.Min((int)size, _buffer.Length)); - } - else - { - NetEventSource.DumpBuffer(this, _buffer); - } - } - - internal Socket AcceptSocket - { - set - { - _acceptSocket = value; - } - } - } -} diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.cs deleted file mode 100644 index 5e6609fedffa0d..00000000000000 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/AcceptOverlappedAsyncResult.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Net.Sockets -{ - // AcceptOverlappedAsyncResult - used to take care of storage for async Socket BeginAccept call. - internal sealed partial class AcceptOverlappedAsyncResult : BaseOverlappedAsyncResult - { - private readonly Socket _listenSocket; - private byte[]? _buffer; - - internal AcceptOverlappedAsyncResult(Socket listenSocket, object? asyncState, AsyncCallback? asyncCallback) : - base(listenSocket, asyncState, asyncCallback) - { - _listenSocket = listenSocket; - } - - internal byte[]? Buffer - { - get - { - return _buffer; - } - } - - internal int BytesTransferred - { - get - { - return _numBytes; - } - } - } -} 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 461122cfd09a6b..d18f92510f89b8 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 @@ -72,8 +72,7 @@ public Task AcceptAsync(Socket? acceptSocket) { // The operation completed synchronously. Get a task for it. t = saea.SocketError == SocketError.Success ? - Task.FromResult(saea.AcceptSocket!) : - Task.FromException(GetException(saea.SocketError)); + Task.FromResult(saea.AcceptSocket!) : TaskToApm.GetSynchronousExceptionTask(GetException(saea.SocketError)); // There won't be a callback, and we're done with the SAEA, so return it to the pool. ReturnSocketAsyncEventArgs(saea); @@ -959,8 +958,7 @@ public ValueTask SendAsync(Socket socket, CancellationToken cancellationTok Release(); return error == SocketError.Success ? - new ValueTask(bytesTransferred) : - ValueTask.FromException(CreateException(error)); + new ValueTask(bytesTransferred) : TaskToApm.GetSynchronousExceptionValueTask(CreateException(error)); } public ValueTask SendAsyncForNetworkStream(Socket socket, CancellationToken cancellationToken) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs index 79ba1e95c1d3fe..a46a30555fd436 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs @@ -27,26 +27,6 @@ public SocketInformation DuplicateAndClose(int targetProcessId) throw new PlatformNotSupportedException(SR.net_sockets_duplicateandclose_notsupported); } - public IAsyncResult BeginAccept(int receiveSize, AsyncCallback? callback, object? state) - { - throw new PlatformNotSupportedException(SR.net_sockets_accept_receive_apm_notsupported); - } - - public IAsyncResult BeginAccept(Socket? acceptSocket, int receiveSize, AsyncCallback? callback, object? state) - { - throw new PlatformNotSupportedException(SR.net_sockets_accept_receive_apm_notsupported); - } - - public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) - { - throw new PlatformNotSupportedException(SR.net_sockets_accept_receive_apm_notsupported); - } - - public Socket EndAccept(out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) - { - throw new PlatformNotSupportedException(SR.net_sockets_accept_receive_apm_notsupported); - } - internal bool PreferInlineCompletions { get => _handle.PreferInlineCompletions; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs index 11325495e0a311..99940c441493b8 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Threading; +using System.Threading.Tasks; using System.Runtime.Versioning; namespace System.Net.Sockets @@ -145,30 +146,6 @@ public SocketInformation DuplicateAndClose(int targetProcessId) return info; } - public IAsyncResult BeginAccept(int receiveSize, AsyncCallback? callback, object? state) - { - return BeginAccept(acceptSocket: null, receiveSize, callback, state); - } - - // This is the truly async version that uses AcceptEx. - public IAsyncResult BeginAccept(Socket? acceptSocket, int receiveSize, AsyncCallback? callback, object? state) - { - return BeginAcceptCommon(acceptSocket, receiveSize, callback, state); - } - - public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) - { - Socket socket = EndAccept(out byte[] innerBuffer, out int bytesTransferred, asyncResult); - buffer = new byte[bytesTransferred]; - Buffer.BlockCopy(innerBuffer, 0, buffer, 0, bytesTransferred); - return socket; - } - - public Socket EndAccept(out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) - { - return EndAcceptCommon(out buffer!, out bytesTransferred, asyncResult); - } - private DynamicWinsockMethods GetDynamicWinsockMethods() { return _dynamicWinsockMethods ??= DynamicWinsockMethods.GetMethods(_addressFamily, _socketType, _protocolType); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 2671112ffa139d..244e77fcf045fb 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -2221,8 +2221,9 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s { ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); - - return TaskToApm.Begin(SendAsync(new ReadOnlyMemory(buffer, offset, size), socketFlags, default).AsTask(), callback, state); + var task = SendAsync(new ReadOnlyMemory(buffer, offset, size), socketFlags, default).AsTask(); + task.ThrowIfFailedSynchronously(); + return TaskToApm.Begin(task, callback, state); } public IAsyncResult? BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) @@ -2244,6 +2245,8 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s public IAsyncResult BeginSend(IList> buffers, SocketFlags socketFlags, AsyncCallback? callback, object? state) { ThrowIfDisposed(); + Task task = SendAsync(buffers, socketFlags); + task.ThrowIfFailedSynchronously(); return TaskToApm.Begin(SendAsync(buffers, socketFlags), callback, state); } @@ -2484,166 +2487,71 @@ public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) return result.ReceivedBytes; } - // Routine Description: - // - // BeginAccept - Does an async winsock accept, creating a new socket on success - // - // Works by creating a pending accept request the first time, - // and subsequent calls are queued so that when the first accept completes, - // the next accept can be resubmitted in the callback. - // this routine may go pending at which time, - // but any case the callback Delegate will be called upon completion - // - // Arguments: - // - // Callback - Async Callback Delegate that is called upon Async Completion - // State - State used to track callback, set by caller, not required - // - // Return Value: - // - // IAsyncResult - Async result used to retrieve resultant new socket - public IAsyncResult BeginAccept(AsyncCallback? callback, object? state) - { - if (!_isDisconnected) - { - return BeginAcceptCommon(acceptSocket: null, receiveSize: 0, callback, state); - } - - Debug.Assert(Disposed); - ThrowObjectDisposedException(); - return null; // unreachable - } + public IAsyncResult BeginAccept(AsyncCallback? callback, object? state) => + TaskToApm.Begin(AcceptAsync(), callback, state); - private IAsyncResult BeginAcceptCommon(Socket? acceptSocket, int receiveSize, AsyncCallback? callback, object? state) + public Socket EndAccept(IAsyncResult asyncResult) { ThrowIfDisposed(); + return TaskToApm.End(asyncResult); + } + // This method provides support for legacy BeginAccept methods that take a "receiveSize" argument and + // allow data to be received as part of the accept operation. + // There's no direct equivalent of this in the Task APIs, so we mimic it here. + private Task<(Socket s, byte[] buffer, int bytesReceived)> AcceptAndReceiveHelperAsync(Socket? acceptSocket, int receiveSize) + { // Validate input parameters. if (receiveSize < 0) { throw new ArgumentOutOfRangeException(nameof(receiveSize)); } - // Set up the async result with flowing. - AcceptOverlappedAsyncResult asyncResult = new AcceptOverlappedAsyncResult(this, state, callback); - asyncResult.StartPostingAsyncOp(false); + Task acceptTask = AcceptAsync(acceptSocket); + acceptTask.ThrowIfFailedSynchronously(); - // Start the accept. - if (_rightEndPoint == null) + static async Task<(Socket s, byte[] buffer, int bytesReceived)> Run(Task acceptTask, int receiveSize) { - throw new InvalidOperationException(SR.net_sockets_mustbind); - } - - if (!_isListening) - { - throw new InvalidOperationException(SR.net_sockets_mustlisten); - } - - SafeSocketHandle? acceptHandle; - asyncResult.AcceptSocket = GetOrCreateAcceptSocket(acceptSocket, false, nameof(acceptSocket), out acceptHandle); - - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"AcceptSocket:{acceptSocket}"); - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AcceptStart(_rightEndPoint); - - int socketAddressSize = GetAddressSize(_rightEndPoint); - SocketError errorCode; - try - { - errorCode = SocketPal.AcceptAsync(this, _handle, acceptHandle, receiveSize, socketAddressSize, asyncResult); - } - catch (Exception ex) - { - if (SocketsTelemetry.Log.IsEnabled()) + Socket s = await acceptTask.ConfigureAwait(false); + byte[] buffer; + int bytesReceived; + if (receiveSize == 0) { - SocketsTelemetry.Log.AfterAccept(SocketError.Interrupted, ex.Message); + buffer = Array.Empty(); + bytesReceived = 0; + } + else + { + buffer = new byte[receiveSize]; + bytesReceived = await s.ReceiveAsync(buffer, SocketFlags.None).ConfigureAwait(false); } - throw; + return (s, buffer, bytesReceived); } - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"AcceptAsync returns:{errorCode} {asyncResult}"); - - // Throw an appropriate SocketException if the native call fails synchronously. - if (!CheckErrorAndUpdateStatus(errorCode)) - { - UpdateAcceptSocketErrorForDisposed(ref errorCode); - - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AfterAccept(errorCode); - - throw new SocketException((int)errorCode); - } + return Run(acceptTask, receiveSize); + } - // Finish the flow capture, maybe complete here. - asyncResult.FinishPostingAsyncOp(ref Caches.AcceptClosureCache); + public IAsyncResult BeginAccept(int receiveSize, AsyncCallback? callback, object? state) => + BeginAccept(acceptSocket: null, receiveSize, callback, state); - return asyncResult; - } + public IAsyncResult BeginAccept(Socket? acceptSocket, int receiveSize, AsyncCallback? callback, object? state) => + TaskToApm.Begin(AcceptAndReceiveHelperAsync(acceptSocket, receiveSize), callback, state); - // Routine Description: - // - // EndAccept - Called by user code after I/O is done or the user wants to wait. - // until Async completion, so it provides End handling for async Accept calls, - // and retrieves new Socket object - // - // Arguments: - // - // AsyncResult - the AsyncResult Returned from BeginAccept call - // - // Return Value: - // - // Socket - a valid socket if successful - public Socket EndAccept(IAsyncResult asyncResult) + public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) { - return EndAcceptCommon(out _, out _, asyncResult); + Socket socket = EndAccept(out byte[] innerBuffer, out int bytesTransferred, asyncResult); + buffer = new byte[bytesTransferred]; + Buffer.BlockCopy(innerBuffer, 0, buffer, 0, bytesTransferred); + return socket; } - private Socket EndAcceptCommon(out byte[]? buffer, out int bytesTransferred, IAsyncResult asyncResult) - { - if (Disposed) - { - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AfterAccept(SocketError.Interrupted); - - ThrowObjectDisposedException(); - } - - // Validate input parameters. - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } - AcceptOverlappedAsyncResult? castedAsyncResult = asyncResult as AcceptOverlappedAsyncResult; - if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this) - { - throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult)); - } - if (castedAsyncResult.EndCalled) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndAccept")); - } - - Socket socket = (Socket)castedAsyncResult.InternalWaitForCompletion()!; - bytesTransferred = (int)castedAsyncResult.BytesTransferred; - buffer = castedAsyncResult.Buffer; - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.BytesReceived(bytesTransferred); - - castedAsyncResult.EndCalled = true; - - // Throw an appropriate SocketException if the native call failed asynchronously. - SocketError errorCode = (SocketError)castedAsyncResult.ErrorCode; - - if (errorCode != SocketError.Success) - { - UpdateAcceptSocketErrorForDisposed(ref errorCode); - - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AfterAccept(errorCode); - - UpdateStatusAfterSocketErrorAndThrowException(errorCode); - } - - if (SocketsTelemetry.Log.IsEnabled()) SocketsTelemetry.Log.AfterAccept(SocketError.Success); - - if (NetEventSource.Log.IsEnabled()) NetEventSource.Accepted(socket, socket.RemoteEndPoint, socket.LocalEndPoint); - return socket; + public Socket EndAccept(out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) + { + ThrowIfDisposed(); + Socket s; + (s, buffer, bytesTransferred) = TaskToApm.End<(Socket, byte[], int)>(asyncResult); + return s; } // Disables sends and receives on a socket. @@ -2668,7 +2576,7 @@ public void Shutdown(SocketShutdown how) InternalSetBlocking(_willBlockInternal); } - #region Async methods +#region Async methods public bool AcceptAsync(SocketAsyncEventArgs e) { ThrowIfDisposed(); @@ -3155,10 +3063,10 @@ private bool SendToAsync(SocketAsyncEventArgs e, CancellationToken cancellationT return socketError == SocketError.IOPending; } - #endregion - #endregion +#endregion +#endregion - #region Internal and private properties +#region Internal and private properties private CacheSet Caches { @@ -3174,9 +3082,9 @@ private CacheSet Caches } internal bool Disposed => _disposed != 0; - #endregion +#endregion - #region Internal and private methods +#region Internal and private methods internal static void GetIPProtocolInformation(AddressFamily addressFamily, Internals.SocketAddress socketAddress, out bool isIPv4, out bool isIPv6) { @@ -3889,6 +3797,6 @@ private static SocketError GetSocketErrorFromFaultedTask(Task t) }; } - #endregion +#endregion } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 735ece8f8d0a73..9839235a96273e 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -1959,23 +1959,6 @@ public static async void SendPacketsAsync( } } - public static SocketError AcceptAsync(Socket socket, SafeSocketHandle handle, SafeSocketHandle? acceptHandle, int receiveSize, int socketAddressSize, AcceptOverlappedAsyncResult asyncResult) - { - Debug.Assert(acceptHandle == null, $"Unexpected acceptHandle: {acceptHandle}"); - Debug.Assert(receiveSize == 0, $"Unexpected receiveSize: {receiveSize}"); - - byte[] socketAddressBuffer = new byte[socketAddressSize]; - - IntPtr acceptedFd; - SocketError socketError = handle.AsyncContext.AcceptAsync(socketAddressBuffer, ref socketAddressSize, out acceptedFd, asyncResult.CompletionCallback); - if (socketError == SocketError.Success) - { - asyncResult.CompletionCallback(acceptedFd, socketAddressBuffer, socketAddressSize, SocketError.Success); - } - - return socketError; - } - internal static SocketError DisconnectAsync(Socket socket, SafeSocketHandle handle, bool reuseSocket, DisconnectOverlappedAsyncResult asyncResult) { SocketError socketError = Disconnect(socket, handle, reuseSocket); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs index cf6e12e66dbbad..c1cf9623e5b033 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs @@ -1,15 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.Win32.SafeHandles; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +using Microsoft.Win32.SafeHandles; #if BIGENDIAN using System.Buffers.Binary; @@ -1099,39 +1098,6 @@ public static unsafe SocketError SendFileAsync(SafeSocketHandle handle, FileStre } } - public static unsafe SocketError AcceptAsync(Socket socket, SafeSocketHandle handle, SafeSocketHandle acceptHandle, int receiveSize, int socketAddressSize, AcceptOverlappedAsyncResult asyncResult) - { - // The buffer needs to contain the requested data plus room for two sockaddrs and 16 bytes - // of associated data for each. - int addressBufferSize = socketAddressSize + 16; - byte[] buffer = new byte[receiveSize + ((addressBufferSize) * 2)]; - - // Set up asyncResult for overlapped AcceptEx. - // This call will use completion ports on WinNT. - asyncResult.SetUnmanagedStructures(buffer, addressBufferSize); - try - { - // This can throw ObjectDisposedException. - int bytesTransferred; - bool success = socket.AcceptEx( - handle, - acceptHandle, - Marshal.UnsafeAddrOfPinnedArrayElement(asyncResult.Buffer!, 0), - receiveSize, - addressBufferSize, - addressBufferSize, - out bytesTransferred, - asyncResult.DangerousOverlappedPointer); // SafeHandle was just created in SetUnmanagedStructures - - return asyncResult.ProcessOverlappedResult(success, 0); - } - catch - { - asyncResult.ReleaseUnmanagedStructures(); - throw; - } - } - public static void CheckDualModeReceiveSupport(Socket socket) { // Dual-mode sockets support received packet info on Windows. diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs index 79756096973be7..a4bfa0fccea86a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs @@ -222,7 +222,7 @@ public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reus [OuterLoop] [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)] - public void Accept_WithAlreadyBoundTargetSocket_Fails() + public async Task Accept_WithAlreadyBoundTargetSocket_Fails() { if (!SupportsAcceptIntoExistingSocket) return; @@ -236,7 +236,7 @@ public void Accept_WithAlreadyBoundTargetSocket_Fails() server.BindToAnonymousPort(IPAddress.Loopback); - Assert.Throws(() => { AcceptAsync(listener, server); }); + await Assert.ThrowsAsync(async () => { await AcceptAsync(listener, server); }); } } @@ -262,7 +262,7 @@ public async Task Accept_WithInUseTargetSocket_Fails() Assert.Same(server, accepted); Assert.True(accepted.Connected); - Assert.Throws(() => { AcceptAsync(listener, server); }); + await Assert.ThrowsAsync(async () => { await AcceptAsync(listener, server); }); } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index bdaf68ffb497e2..6e3d7754a15a38 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -135,7 +135,10 @@ public override Task AcceptAsync(Socket s) => return (socket, buffer); } public override Task AcceptAsync(Socket s, Socket acceptSocket) => - Task.Factory.FromAsync(s.BeginAccept, s.EndAccept, acceptSocket, 0, null); + Task.Factory.FromAsync( + (callback, state) => s.BeginAccept(acceptSocket, 0, callback, state), + result => s.EndAccept(out _, out _, result), + null); public override Task ConnectAsync(Socket s, EndPoint endPoint) => Task.Factory.FromAsync(s.BeginConnect, s.EndConnect, endPoint, null); public override Task MultiConnectAsync(Socket s, IPAddress[] addresses, int port) =>