Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unblock Unix Domain Socket on Dispose on macOS #101753

Merged
merged 9 commits into from
May 22, 2024
Merged
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 @@ -586,6 +586,56 @@ public async Task ReceiveFrom_EndPoints_Correct(bool useAsync)
}
}

[ConditionalFact(typeof(Socket), nameof(Socket.OSSupportsUnixDomainSockets))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task UnixDomainSocket_Receive_GetsCanceledByDispose()
{
string path = GetRandomNonExistingFilePath();
var endPoint = new UnixDomainSocketEndPoint(path);

using (var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
using (var client = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
{
server.Bind(endPoint);
server.Listen(1);

client.Connect(endPoint);
int msDelay = 100;
bool readFailed = false;
byte[] buffer = new byte[100];
using (Socket accepted = server.Accept())
{
while (msDelay < 10_000)
{
Task disposeTask = Task.Run(() =>
wfurt marked this conversation as resolved.
Show resolved Hide resolved
{
Thread.Sleep(msDelay);
client.Dispose();
});

try
{
client.Receive(buffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a regression that causes TryUnblockSocket to break, the test will hang at client.Receive and never time out.

Copy link
Member

@tmds tmds May 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do some things like:

await Task.WhenAny(disposeTask, socketOperation)
.WaitAsync(TimeSpan.FromMilliseconds(TestSettings.PassingTestTimeout));
await disposeTask
.WaitAsync(TimeSpan.FromMilliseconds(TestSettings.PassingTestTimeout));
SocketError? localSocketError = null;
try
{
await socketOperation
.WaitAsync(TimeSpan.FromMilliseconds(TestSettings.PassingTestTimeout));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about it. However, I think we would notice it and fix it. XUnit now spits out warnings about long running tasks.

}
catch (SocketException)
{
await disposeTask;
readFailed = true;
break;
}
catch (ObjectDisposedException)
{
await disposeTask;
// Dispose happened before the operation, retry.
msDelay *= 2;
continue;
}
}
}
Assert.True(readFailed);
}
}

private static string GetRandomNonExistingFilePath()
{
string result;
Expand Down
5 changes: 5 additions & 0 deletions src/native/libs/System.Native/pal_networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -3143,6 +3143,11 @@ int32_t SystemNative_Disconnect(intptr_t socket)
#elif HAVE_DISCONNECTX
// disconnectx causes a FIN close on OSX. It's the best we can do.
err = disconnectx(fd, SAE_ASSOCID_ANY, SAE_CONNID_ANY);
if (err != 0)
{
// This happens on Unix Domain Sockets as disconnectx is only supported on AF_INET and AF_INET6
err = shutdown(fd, SHUT_RDWR);
}
#else
// best-effort, this may cause a FIN close.
err = shutdown(fd, SHUT_RDWR);
Expand Down
Loading