Skip to content

Commit

Permalink
[Unix]: AcceptAsync with existing AcceptSocket support on Unix (#73499)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
liveans authored Aug 26, 2022
1 parent 2ac87a9 commit c112de1
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public SafeSocketHandle(IntPtr preexistingHandle, bool ownsHandle)

internal bool OwnsHandle { get; }

internal bool HasShutdownSend => _hasShutdownSend;

private bool TryOwnClose()
=> Interlocked.CompareExchange(ref _ownClose, 1, 0) == 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using System.Threading.Tasks;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
using System.Reflection;
using System.Collections;

namespace System.Net.Sockets
{
Expand Down Expand Up @@ -166,16 +168,20 @@ private static void ThrowMultiConnectNotSupported()
}

#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)
if (acceptSocket != null && acceptSocket._handle.HasShutdownSend)
{
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;
return null;
return acceptSocket;
}
#pragma warning restore CA1822

Expand Down Expand Up @@ -228,5 +234,81 @@ private void SendFileInternal(string? fileName, ReadOnlySpan<byte> preBuffer, Re
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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,21 @@ internal void LogBuffer(int size)
private SocketError FinishOperationAccept(Internals.SocketAddress remoteSocketAddress)
{
System.Buffer.BlockCopy(_acceptBuffer!, 0, remoteSocketAddress.Buffer, 0, _acceptAddressBufferCount);
Socket? sukru = _acceptSocket;
_acceptSocket = _currentSocket!.CreateAcceptSocket(
SocketPal.CreateSocket(_acceptedFileDescriptor),
_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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ public async Task Accept_ConcurrentAcceptsAfterConnects_Success(int numberAccept

[OuterLoop]
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithTargetSocket_Success()
{
if (!SupportsAcceptIntoExistingSocket)
Expand All @@ -167,7 +166,6 @@ public async Task Accept_WithTargetSocket_Success()
}
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
[OuterLoop]
[Theory]
[InlineData(false)]
Expand Down Expand Up @@ -222,7 +220,6 @@ public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reus

[OuterLoop]
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithAlreadyBoundTargetSocket_Fails()
{
if (!SupportsAcceptIntoExistingSocket)
Expand All @@ -243,7 +240,6 @@ public async Task Accept_WithAlreadyBoundTargetSocket_Fails()

[OuterLoop]
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/1483", TestPlatforms.AnyUnix)]
public async Task Accept_WithInUseTargetSocket_Fails()
{
if (!SupportsAcceptIntoExistingSocket)
Expand Down

0 comments on commit c112de1

Please sign in to comment.