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

Socket.Select() method doesn't work as expected on macOS #920

Closed
earlbread opened this issue Jul 19, 2019 · 11 comments · Fixed by #104915
Closed

Socket.Select() method doesn't work as expected on macOS #920

earlbread opened this issue Jul 19, 2019 · 11 comments · Fixed by #104915
Assignees
Labels
area-System.Net.Sockets bug in-pr There is an active PR which will close this issue when it is merged os-mac-os-x macOS aka OSX tenet-compatibility Incompatibility with previous versions or .NET Framework
Milestone

Comments

@earlbread
Copy link

On macOS, Socket.Select method doesn't work as expected. In .NET Framework, it works as expected.

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;

namespace SelectTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
            Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);

            receiver.Bind(new IPEndPoint(IPAddress.Loopback, 0));
            receiver.Listen(1);
            sender.Connect(receiver.LocalEndPoint);
            receiver = receiver.Accept();

            sender.Send(new byte[] { 1 });

            var readList = new List<Socket> { receiver };
            var errorList = new List<Socket> { receiver };

            Socket.Select(readList, null, errorList, -1);
            Console.WriteLine($"readList Count: {readList.Count}");
            Console.WriteLine($"errorList Count: {errorList.Count}");
        }
    }
}

Expected result:

The following output is written to stdout:

readList Count: 1
errorList Count: 0

Actual result:

The following output is written to stdout:

readList Count: 0
errorList Count: 0

Dotnet Info

.NET Core SDK (reflecting any global.json):
 Version:   2.2.105
 Commit:    7cecb35b92

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.14
 OS Platform: Darwin
 RID:         osx.10.14-x64
 Base Path:   /usr/local/share/dotnet/sdk/2.2.105/

Host (useful for support):
  Version: 2.2.3
  Commit:  6b8ad509b6

.NET Core SDKs installed:
  2.2.105 [/usr/local/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download
@earlbread earlbread changed the title Socket.Select doesn't work as expected on macOS Socket.Select() method doesn't work as expected on macOS Jul 19, 2019
@davidsh
Copy link
Contributor

davidsh commented Jul 21, 2019

@wfurt @tmds

@wfurt
Copy link
Member

wfurt commented Jul 26, 2019

It seems like we use poll() under the cover to avoid select() limitations. I did some tracing and I see broken behavior described here: https://daniel.haxx.se/blog/2016/10/11/poll-on-mac-10-12-is-broken/

poll() system calls returns immediately with 0 and no events even if infinite (or long) time is specified.
It seems like curl project ditched Apple's poll() altogether curl/curl#1057

While this looks like system bug we can either use select() on OSX or use kqueue under the cover.

from OSX man page:
[EINVAL] ndfs is greater than FD_SETSIZE and _DARWIN_UNLIMITED_SELECT is not defined.

It seems like there is option to avoid limits we were trying to workaround in first place.

https://github.com/dotnet/corefx/blob/master/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs#L1386-L1398

@karelz
Copy link
Member

karelz commented Sep 9, 2019

Looks like most people are using async for these scenarios. Only 1 complaint so far.
When we fix that, we should add a test.

Compat angle: It works on other platforms.

@karelz
Copy link
Member

karelz commented Sep 9, 2019

This might be fairly straightforward.

@maryamariyan maryamariyan transferred this issue from dotnet/corefx Dec 16, 2019
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Dec 16, 2019
@maryamariyan maryamariyan added area-System.Net.Sockets bug os-mac-os-x macOS aka OSX tenet-compatibility Incompatibility with previous versions or .NET Framework labels Dec 16, 2019
@maryamariyan maryamariyan added this to the Future milestone Dec 16, 2019
@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Jan 7, 2020
@mattjbird
Copy link

Is there any update on this issue?

When I run the above snippet in dotnet 6.0.102 on macOS the Select call hangs. If I compile the same code using mono it works as expected. Happy to provide more info if that'd help.

@wfurt
Copy link
Member

wfurt commented Nov 30, 2022

triage: we should document that there are OS behavior differences. And perhaps re-test it on recent macOS versions.

@wfurt wfurt modified the milestones: Future, 8.0.0 Nov 30, 2022
@wfurt wfurt modified the milestones: 8.0.0, Future Jun 7, 2023
@karelz karelz modified the milestones: Future, 9.0.0 Jul 18, 2023
@maxstue-exx
Copy link

Is there any update on this issue?
because the usage of another software (see last connected issue) depends on this.
Is there a probability that this fix is coming earlier than dotnet 9?

@wfurt
Copy link
Member

wfurt commented Feb 5, 2024

9 is probably earliest. Even if we have fix soon I don't think this would qualify for servicing @maxstue-exx

@wfurt
Copy link
Member

wfurt commented Mar 1, 2024

I did some testing with plain C and the outcome is interesting.

        struct pollfd polls[2];

        polls[0].fd = sockfd;
        polls[0].events = POLLIN | POLLHUP ;
        polls[1].fd = sockfd;
        polls[1].events = POLLPRI;

        int err = poll(&polls, 2, 1000);

fails the way described above e.g. the `poll' will never notice there are data available to read.

But this works as expected

        struct pollfd polls[1];

        polls[0].fd = sockfd;
        polls[0].events = POLLIN | POLLHUP | POLLPRI;

        int err = poll(&polls, 1, 1000);

so it seems like Darwin kernel does not like repeating descriptors in the array.
At least for the error list. It seems like POLLOUT still works as expected.

So we can rearrange the code to merge readList and errorList together and set the events accordingly.
Or we can switch and real accept on macOS as it does support unlimited number of file descriptors.

Any preference here @stephentoub? The merging will add some expense but I would not expect people to use select with huge number of sockets. Regardless of this issue, it does not scale well anyway.

from the c# API, can you avoild using the errorList @earlbread @maxstue-exx and simply relay on read errors?
It should detect connection close just fine.

@stephentoub
Copy link
Member

Or we can switch and real accept on macOS as it does support unlimited number of file descriptors.

Did you mean select rather than accept? Or if you meant accept, I'm not understanding; can you clarify?

Any preference here @stephentoub?

I'd opt to specialize an answer for the affected platforms rather than make the others worse perf-wise. And then I'd opt to do whichever is easiest in the macOS specialization, as this doesn't seem like something likely to be super hot path, especially if it only manifests when providing a non-empty error list.

@wfurt
Copy link
Member

wfurt commented Apr 1, 2024

Did you mean select rather than accept? Or if you meant accept, I'm not understanding; can you clarify?

yes, I meant 'select. We now emulate the behavior on top of poll

@wfurt wfurt self-assigned this Jun 25, 2024
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Jul 15, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Aug 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Sockets bug in-pr There is an active PR which will close this issue when it is merged os-mac-os-x macOS aka OSX tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
Development

Successfully merging a pull request may close this issue.

9 participants