-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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.Connect methods that connect to multiple endpoints are broken on Unix #16263
Comments
I feel like I should also point out another option: we could replace all of the instance I'm personally in favor of option (b) with the possible addition of a toolable notification that the existing APIs should not be used for cross-platform code (e.g. a Roslyn diagnostic or some appropriate attribute). |
I would vote for b). |
Sounds like we should go for (b), ideally where the message in the PlatformNotSupportedException provides some guidance. |
I just tried to run a .NET Core app (that uses sockets) on Ubuntu 14.04. Calling I did not find this exception message to be helpful in explaining the underlying issue or advising how to avoid it. At first I thought the message meant that I was attempting to reuse a socket after a failed connection attempt (which didn't make sense). Eventually I found 30bd4b7 and (thanks to the very helpful commit message) understood the problem (and the workaround). I propose two improvements:
I'd be happy to open a PR for either/both of these suggestions if you're in favour of them. |
@bgrainger, sorry the error message wasn't as helpful as it could have been (but I'm glad the commit message was). You're welcome to submit a PR to improve it. As for marking the overloads as [Obsolete], that's a question for @davidsh or @CIPop. |
Socket.Connect overloads that might attempt to create connections to multiple IP addresses are not supported: https://github.com/dotnet/corefx/issues/5829. As per dotnet/corefx@30bd4b7, the workaround is to resolve the name to a collection of IP addresses and try them sequentially. Also implemented support for comma-delimited hostnames (even though this appears to have been dropped from the official connector in mysql/mysql-connector-net@03f3a23.)
@stephentoub Was the intent here really to disable connecting to sockets via hostname on some platforms? Option 2 in that commit rather needlessly breaks We just got this issue filed: StackExchange/StackExchange.Redis#410 All of the socket code I've written goes to a single host and that's all broken cross-platform now, without merit I think. IMO, we can and should break far less code with Option 3 and a clearer commit message here. There's no need to break people aside from erroring on what would actually break. |
@NickCraver, if you open a new issue to @ericeil, we can reevaluate. |
@stephentoub k, will do that when time allows today - thanks. |
…forms. Having the socket do the DNS lookup is apparently not supported by corefx. See issue: https://github.com/dotnet/corefx/issues/5829 and https://github.com/dotnet/corefx/issues/8768.
Unlike Windows, the sockets API on Linux and OSX does not allow a single socket to attempt more than one connection. We had attempted to do this on Linux, but it did not work (see #16238).
Socket
has multiple methods that depend on being able to try connections to multiple endpoints on a single socket:...attempts to connect to each of
addresses
, returning when one of them is successful....does a DNS lookup, which may return multiple addresses, then attempts to connect to each of them until successful.
If this is passed a
DnsEndPoint
, then this behaves the same asConnect(string, int)
, trying all resolved addresses.Additionally, we support async variants of all of these.
On Unix we currently "fake" this by creating multiple temporary sockets behind the scenes, trying to connect each of them to a different address. If one succeeds, we immediately disconnect it and connect the "real" socket to that address. This workaround has some possibly unacceptable implications:
Whichever endpoint we finally choose, we will end up connecting to it twice, once for the "probe" connection, to see if it will work, and again for the "real" connection. This will cause issues for servers that do not expect more than one connection, for load balancers that try to distribute connections, etc. It's also a lot of undesired network overhead.
Even though the first connection attempt succeeded, the second will not necessarily succeed. This is especially true in scenarios like DNS-based load balancing. So we have a functional issue here, where we may fail to connect the "real" socket in cases where we would have succeeded.
I do not think we should leave this as-is, as it will create too many unexpected strange behaviors in code that uses these, expecting them to behave the same way as they do on Windows. So I propose doing one of the following:
a) Remove the
Connect
overloads that take multiple endpoints, and theDnsEndpoint
type, from the public contracts.-- or --
b) Change these Connect overloads to throw
PlatformNotSupportedException
on Unix, Also, changeConnect(EndPoint, int)
to throwPlatformNotSupportedException
if passed aDnsEndPoint
.In either case, we should provide sample code for how to code equivalent behavior using the remaining APIs.
@stephentoub, @pgavlin, @CIPop, @davidsh, @SidharthNabar, please provide feedback.
The text was updated successfully, but these errors were encountered: