未验证 提交 c112de11 编写于 作者: A Ahmet İbrahim AKSOY 提交者: GitHub

[Unix]: AcceptAsync with existing AcceptSocket support on Unix (#73499)

* Fix: Initial attempt to fix - ut passed

* Update: Forgotten save

* Update: Clear and Dispose ops on handles

* Update: Activate tests for Unix and correct no reuse behavior

* Update: Review Changes

* Update: Deleted forgotten comment

* Update: Review change
上级 2ac87a95
...@@ -53,6 +53,8 @@ public SafeSocketHandle(IntPtr preexistingHandle, bool ownsHandle) ...@@ -53,6 +53,8 @@ public SafeSocketHandle(IntPtr preexistingHandle, bool ownsHandle)
internal bool OwnsHandle { get; } internal bool OwnsHandle { get; }
internal bool HasShutdownSend => _hasShutdownSend;
private bool TryOwnClose() private bool TryOwnClose()
=> Interlocked.CompareExchange(ref _ownClose, 1, 0) == 0; => Interlocked.CompareExchange(ref _ownClose, 1, 0) == 0;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
using System.Reflection;
using System.Collections;
namespace System.Net.Sockets namespace System.Net.Sockets
{ {
...@@ -166,16 +168,20 @@ private static void ThrowMultiConnectNotSupported() ...@@ -166,16 +168,20 @@ private static void ThrowMultiConnectNotSupported()
} }
#pragma warning disable CA1822 #pragma warning disable CA1822
private Socket? GetOrCreateAcceptSocket(Socket? acceptSocket, bool unused, string propertyName, out SafeSocketHandle? handle) private Socket? GetOrCreateAcceptSocket(Socket? acceptSocket, bool checkDisconnected, string propertyName, out SafeSocketHandle? handle)
{ {
// AcceptSocket is not supported on Unix. if (acceptSocket != null && acceptSocket._handle.HasShutdownSend)
if (acceptSocket != null)
{ {
throw new PlatformNotSupportedException(SR.PlatformNotSupported_AcceptSocket); throw new SocketException((int)SocketError.InvalidArgument);
}
if (acceptSocket != null && acceptSocket._rightEndPoint != null && (!checkDisconnected || !acceptSocket._isDisconnected))
{
throw new InvalidOperationException(SR.Format(SR.net_sockets_namedmustnotbebound, propertyName));
} }
handle = null; handle = null;
return null; return acceptSocket;
} }
#pragma warning restore CA1822 #pragma warning restore CA1822
...@@ -228,5 +234,81 @@ private void SendFileInternal(string? fileName, ReadOnlySpan<byte> preBuffer, Re ...@@ -228,5 +234,81 @@ private void SendFileInternal(string? fileName, ReadOnlySpan<byte> preBuffer, Re
Send(postBuffer); Send(postBuffer);
} }
} }
internal void DisposeHandle()
{
_handle.Dispose();
}
internal void ClearHandle()
{
_handle = null!;
}
internal Socket CopyStateFromSource(Socket source)
{
_addressFamily = source._addressFamily;
_closeTimeout = source._closeTimeout;
_disposed = source._disposed;
_handle = source._handle;
_isConnected = source._isConnected;
_isDisconnected = source._isDisconnected;
_isListening = source._isListening;
_nonBlockingConnectInProgress = source._nonBlockingConnectInProgress;
_protocolType = source._protocolType;
_receivingPacketInformation = source._receivingPacketInformation;
_remoteEndPoint = source._remoteEndPoint;
_rightEndPoint = source._rightEndPoint;
_socketType = source._socketType;
_willBlock = source._willBlock;
_willBlockInternal = source._willBlockInternal;
_localEndPoint = source._localEndPoint;
_multiBufferReceiveEventArgs = source._multiBufferReceiveEventArgs;
_multiBufferSendEventArgs = source._multiBufferSendEventArgs;
_pendingConnectRightEndPoint = source._pendingConnectRightEndPoint;
_singleBufferReceiveEventArgs = source._singleBufferReceiveEventArgs;
#if DEBUG
// Try to detect if a property gets added that we're not copying correctly.
foreach (PropertyInfo pi in typeof(Socket).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
object? origValue = pi.GetValue(source);
object? cloneValue = pi.GetValue(this);
if (origValue is IEnumerable origEnumerable)
{
IEnumerable? cloneEnumerable = cloneValue as IEnumerable;
Debug.Assert(cloneEnumerable != null, $"{pi.Name}. Expected enumerable cloned value.");
IEnumerator e1 = origEnumerable.GetEnumerator();
try
{
IEnumerator e2 = cloneEnumerable.GetEnumerator();
try
{
while (e1.MoveNext())
{
Debug.Assert(e2.MoveNext(), $"{pi.Name}. Cloned enumerator too short.");
Debug.Assert(Equals(e1.Current, e2.Current), $"{pi.Name}. Cloned enumerator's values don't match.");
}
Debug.Assert(!e2.MoveNext(), $"{pi.Name}. Cloned enumerator too long.");
}
finally
{
(e2 as IDisposable)?.Dispose();
}
}
finally
{
(e1 as IDisposable)?.Dispose();
}
}
else
{
Debug.Assert(Equals(origValue, cloneValue), $"{pi.Name}. Expected: {origValue}, Actual: {cloneValue}");
}
}
#endif
return this;
}
} }
} }
...@@ -335,9 +335,21 @@ internal void LogBuffer(int size) ...@@ -335,9 +335,21 @@ internal void LogBuffer(int size)
private SocketError FinishOperationAccept(Internals.SocketAddress remoteSocketAddress) private SocketError FinishOperationAccept(Internals.SocketAddress remoteSocketAddress)
{ {
System.Buffer.BlockCopy(_acceptBuffer!, 0, remoteSocketAddress.Buffer, 0, _acceptAddressBufferCount); System.Buffer.BlockCopy(_acceptBuffer!, 0, remoteSocketAddress.Buffer, 0, _acceptAddressBufferCount);
Socket? sukru = _acceptSocket;
_acceptSocket = _currentSocket!.CreateAcceptSocket( _acceptSocket = _currentSocket!.CreateAcceptSocket(
SocketPal.CreateSocket(_acceptedFileDescriptor), SocketPal.CreateSocket(_acceptedFileDescriptor),
_currentSocket._rightEndPoint!.Create(remoteSocketAddress)); _currentSocket._rightEndPoint!.Create(remoteSocketAddress));
if (sukru != null)
{
sukru.DisposeHandle();
sukru.CopyStateFromSource(_acceptSocket);
// We keep this socket to make clean-up.
Socket temp = _acceptSocket;
_acceptSocket = sukru;
temp.ClearHandle();
temp.Dispose();
GC.SuppressFinalize(temp);
}
return SocketError.Success; return SocketError.Success;
} }
......
...@@ -145,7 +145,6 @@ public async Task Accept_ConcurrentAcceptsAfterConnects_Success(int numberAccept ...@@ -145,7 +145,6 @@ public async Task Accept_ConcurrentAcceptsAfterConnects_Success(int numberAccept
[OuterLoop] [OuterLoop]
[Fact] [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithTargetSocket_Success() public async Task Accept_WithTargetSocket_Success()
{ {
if (!SupportsAcceptIntoExistingSocket) if (!SupportsAcceptIntoExistingSocket)
...@@ -167,7 +166,6 @@ public async Task Accept_WithTargetSocket_Success() ...@@ -167,7 +166,6 @@ public async Task Accept_WithTargetSocket_Success()
} }
} }
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
[OuterLoop] [OuterLoop]
[Theory] [Theory]
[InlineData(false)] [InlineData(false)]
...@@ -222,7 +220,6 @@ public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reus ...@@ -222,7 +220,6 @@ public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reus
[OuterLoop] [OuterLoop]
[Fact] [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithAlreadyBoundTargetSocket_Fails() public async Task Accept_WithAlreadyBoundTargetSocket_Fails()
{ {
if (!SupportsAcceptIntoExistingSocket) if (!SupportsAcceptIntoExistingSocket)
...@@ -243,7 +240,6 @@ public async Task Accept_WithAlreadyBoundTargetSocket_Fails() ...@@ -243,7 +240,6 @@ public async Task Accept_WithAlreadyBoundTargetSocket_Fails()
[OuterLoop] [OuterLoop]
[Fact] [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithInUseTargetSocket_Fails() public async Task Accept_WithInUseTargetSocket_Fails()
{ {
if (!SupportsAcceptIntoExistingSocket) if (!SupportsAcceptIntoExistingSocket)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册