runtime: Socket.Select on linux gives wrong result when fails to connect
Description
When running Socket.Select against failing port it gives different result on Windows and on Linux. Futhermore, it seems on Linux the result does not make any sense.
This code can be used to reproduce the issue:
private static void Main()
{
using var socket = new Socket( SocketType.Stream, ProtocolType.Tcp)
{
Blocking = false
};
try
{
socket.Connect("127.0.0.1", 41324);
}
catch (SocketException socketException) when (socketException.SocketErrorCode==SocketError.WouldBlock)
{
IList lst = new List<Socket> {socket};
IList lst2 = new List<Socket> {socket};
IList lst3 = new List<Socket> {socket};
Socket.Select(lst,lst2,lst3,10000000);
Console.WriteLine($"Result: {socket.Connected} {lst.Count} {lst2.Count} {lst3.Count}");
}
}
On Linux it says
Result: True 1 1 1
But on windows (looks like correct)
Result: False 0 0 1
Configuration
- netcoreapp3.1
- Ubuntu 18 and Windows 10
Other information
If I try to connect with Blocking = true, then it gives SocketException both on Windows and Linux
Looks like related to https://github.com/dotnet/runtime/issues/920
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 19 (13 by maintainers)
I will try to chat with @geoffkizer on his opinion regarding being platform compatible VS consistent across multiple platforms (& breaking). May reopen this if we conclude that we can do a better job here.
This works cross-platform on all versions of .NET:
The OP has a case using nonblocking socket, connect “fails” with
SocketError.WouldBlock.The
1 1 1is what we get back from Linux, so this is a platform difference. I don’t think we can/should change this.The
Trueis the result of:https://github.com/dotnet/runtime/blob/5b0c6dd5756eea63a57b1f69b182f7386da0f631/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L435-L440
This is missing reading out the actual result from the async connect using
getsockoptwithSO_ERROR.The next operation that gets performed on the socket will throw (because the socket is actually not connected) and update the state to not connected. So this issue gets masked by that.