Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,16 @@ public void AfterConnect(SocketError error, Activity? activity, string? exceptio
long newCount = Interlocked.Decrement(ref _currentOutgoingConnectAttempts);
Debug.Assert(newCount >= 0);

// _currentOutgoingConnectAttempts tracks managed Connect calls. A non-blocking Connect call
// can return WouldBlock (Windows) or InProgress (Unix) while the OS connect attempt remains
// pending after this method decrements that counter; its eventual outcome is not observable
// here. Don't report these pending results as failures.
// See https://github.com/dotnet/runtime/issues/129252
bool connectPending = error is SocketError.WouldBlock or SocketError.InProgress;
Comment thread
tulior marked this conversation as resolved.
Comment thread
tulior marked this conversation as resolved.

if (activity is not null)
{
if (error != SocketError.Success)
if (error != SocketError.Success && !connectPending)
{
activity.SetStatus(ActivityStatusCode.Error);
activity.SetTag("error.type", GetErrorType(error));
Expand All @@ -163,7 +170,7 @@ public void AfterConnect(SocketError error, Activity? activity, string? exceptio
Debug.Assert(exceptionMessage is null);
Interlocked.Increment(ref _outgoingConnectionsEstablished);
}
else
else if (!connectPending)
{
ConnectFailed(error, exceptionMessage);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,37 @@ static void VerifyTcpConnectActivity(Activity activity, IPEndPoint remoteEndPoin
ActivityAssert.HasTag(activity, "network.transport", "tcp");
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public async Task Connect_NonBlockingPending_ActivityNotMarkedAsError()
{
await RemoteExecutor.Invoke(static () =>
{
using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.BindToAnonymousPort(IPAddress.Loopback);
server.Listen();

using Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
Blocking = false
};

using ActivityRecorder recorder = new ActivityRecorder(ActivitySourceName, ActivityName);

// A non-blocking connect reports WouldBlock (Windows) or InProgress (Unix) by design while
// the attempt continues in the background. The "socket connect" activity is started and
// stopped synchronously inside Connect, so its final state can be asserted immediately.
SocketException ex = Assert.Throws<SocketException>(() => client.Connect(server.LocalEndPoint));
Assert.True(ex.SocketErrorCode is SocketError.WouldBlock or SocketError.InProgress,
$"Unexpected SocketError: {ex.SocketErrorCode}");
Comment thread
tulior marked this conversation as resolved.
Comment thread
tulior marked this conversation as resolved.

recorder.VerifyActivityRecorded(1);
Activity activity = recorder.LastFinishedActivity;
VerifyTcpConnectActivity(activity, (IPEndPoint)server.LocalEndPoint, ipv6: false);
Assert.Equal(ActivityStatusCode.Unset, activity.Status);
Assert.Null(activity.GetTagItem("error.type"));
}).DisposeAsync();
}
Comment thread
tulior marked this conversation as resolved.

[OuterLoop("Connection failure takes long on Windows.")]
[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(nameof(SocketMethods_WithBools_MemberData))]
Expand Down
Loading