godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.77k stars 21.13k forks source link

[Mono] Creating a dual-mode Socket (both IPv4 and IPv6) throws "SocketException: The system could not find the environment option that was entered" #65508

Open tom-weiland opened 2 years ago

tom-weiland commented 2 years ago

Godot version

v3.5.stable.mono.official.991bb6ac7

System information

Windows 10

Issue description

I've developed a networking library in C#, and one of my users recently informed me that it doesn't work in Godot (I personally primarily use Unity). After some investigating, I've determined the cause of the problem:

Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);

throws the following exception:

E 0:00:00.711   System.Net.Sockets.Socket..ctor(System.Net.Sockets.AddressFamily , System.Net.Sockets.SocketType , System.Net.Sockets.ProtocolType ): System.Net.Sockets.SocketException: The system could not find the environment option that was entered.

  <C++ Error>   Unhandled exception
  <C++ Source>  :0 @ System.Net.Sockets.Socket..ctor(System.Net.Sockets.AddressFamily , System.Net.Sockets.SocketType , System.Net.Sockets.ProtocolType )()
  <Stack Trace> :0 @ System.Net.Sockets.Socket..ctor(System.Net.Sockets.AddressFamily , System.Net.Sockets.SocketType , System.Net.Sockets.ProtocolType )()
                :0 @ System.Net.Sockets.Socket..ctor(System.Net.Sockets.SocketType , System.Net.Sockets.ProtocolType )()
                SocketTest.cs:9 @ void SocketTest._Ready()()

The important thing to note about the Socket(SocketType, ProtocolType) constructor is that

if the operating system supports IPv6, this constructor creates a dual-mode socket; otherwise, it creates an IPv4 socket.

Windows supports IPv6 and dual-mode sockets, as evidenced by the fact that outside of Godot, this constructor gives me a socket that works with both IPv4 and IPv6, and whose DualMode property is enabled.

Setting the socket's AddressFamily to InterNetwork (aka IPv4 only) doesn't throw the same error:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

However, setting the AddressFamily to InterNetworkV6 (aka IPv4 and IPv6—a dual-mode socket) does throw the same error as the constructor where no AddressFamily is supplied:

Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

I may just add some kind of option/setting to my library that allows users to disable IPv6/dual-mode sockets entirely, although I'm not sure how much use that would get outside of situations like this one where having it enabled causes a crash (since under normal circumstances the constructor should be disabling it automatically if it isn't supported).

I did come across issue #54758, which may be related based on the fact that the workaround presented there is also to disable IPv6, and apparently doing so wasn't necessary before Godot 3.4.

Steps to reproduce

Open the attached project, play it, and check the debugger for the error message mentioned above.

Alternatively, simply paste the following into the _Ready method of a C# script which is attached to a node (requires the System.Net.Sockets namespace):

Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);

Minimal reproduction project

SocketTest.zip

eumario commented 2 years ago

Did a quick test with Godot 4.0, which is now using Dotnet6, and it looks like this issue is no longer a problem in the dotnet architecture. So this may specifically be with the version of Mono that we are using, compared to what version of Mono Unity is using, and how the internals are linked up. Similar situation to the SSL bug. Not the same, just similar root, being Mono.