Skip to content

Commit

Permalink
Fix integration test failures under .net 4.7.2
Browse files Browse the repository at this point in the history
If a socket is disposed after 'ConnectAsync' is invoked but before the
native 'connect' begins, you can get an 'unexpected'
objectdisposedexceptionw which causes the SocketAsyncEventArgs object to
be left in the 'operation is in progress' state forever.

This doesn't happen under newer frameworks, so use a fallback
implementation for .NET 4.7.2 and netstandard 2.0/2.1.
  • Loading branch information
alanmcgovern committed Jun 30, 2024
1 parent 19d86dc commit 7ce2393
Showing 1 changed file with 25 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,30 @@ static void HandleOperationCompleted (object? sender, SocketAsyncEventArgs e)
}


#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET472
public async ReusableTask<Socket> ConnectAsync (Uri uri, CancellationToken token)
{
var socket = new Socket ((uri.Scheme == "ipv4") ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint (IPAddress.Parse (uri.Host), uri.Port);

using var registration = token.Register (SocketDisposer, socket);

try {
// `Socket.ConnectAsync (SocketAsyncEventArgs)` cannot be safely used under .NET 4.7.2.
// .NET 4.7.2 has a bug whereby disposing a socket (so it's safehandle is invalid) before the async operation has fully begun
// causes the 'SocketAsyncEventArgs' to be left in an inconsistent state (permanently in the 'operation in progress' state)
// so it cannot be reused. Work around it by using the synchronous implementation.
//
// This issue caused random integration test deadlocks/hangs under .NET 4.7.2 as socket connections couldn't be made.
await new ThreadSwitcher ();
socket.Connect (endPoint);
} catch {
socket.Dispose ();
throw;
}
return socket;
}
#else
public async ReusableTask<Socket> ConnectAsync (Uri uri, CancellationToken token)
{
var socket = new Socket ((uri.Scheme == "ipv4") ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
Expand Down Expand Up @@ -98,5 +122,6 @@ public async ReusableTask<Socket> ConnectAsync (Uri uri, CancellationToken token
}
return socket;
}
#endif
}
}

0 comments on commit 7ce2393

Please sign in to comment.