diff --git a/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/CachedUdpClient.cs b/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/CachedUdpClient.cs index 03f84667..20e21e64 100644 --- a/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/CachedUdpClient.cs +++ b/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/CachedUdpClient.cs @@ -21,10 +21,10 @@ // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -46,6 +46,19 @@ namespace BeardedManStudios.Forge.Networking { public class CachedUdpClient : IDisposable { + /// + /// Winsock ioctl code which will disable ICMP errors from being propagated to a UDP socket. + /// This can occur if a UDP packet is sent to a valid destination but there is no socket + /// registered to listen on the given port. + /// + /// http://msdn.microsoft.com/en-us/library/cc242275.aspx + /// http://msdn.microsoft.com/en-us/library/bb736550(VS.85).aspx + /// https://stackoverflow.com/questions/7201862/an-existing-connection-was-forcibly-closed-by-the-remote-host/7478498#7478498 + /// uint IOC_IN = 0x80000000; + /// uint IOC_VENDOR = 0x18000000; + /// uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; + private const int SIO_UDP_CONNRESET = -1744830452; + public const char HOST_PORT_CHARACTER_SEPARATOR = '+'; private bool disposed = false; private bool active = false; @@ -143,6 +156,7 @@ private void InitSocket(EndPoint localEP) recBuffer.SetSize(65536); } + #region Close public void Close() { @@ -226,6 +240,17 @@ public void Connect(string hostname, int port) } } } + + /// + /// Enable/disable whether the socket should disregard ICMP Port unreachable errors + /// + /// + public void IgnoreICMPErrors(bool enabled) + { + // set socket to disregard ICMP errors. + socket.IOControl(SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(!enabled)}, null); + } + #endregion #region Multicast methods public void DropMulticastGroup(IPAddress multicastAddr) diff --git a/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/UDPClient.cs b/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/UDPClient.cs index 926c1018..a3b2399d 100644 --- a/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/UDPClient.cs +++ b/ForgeUnity/Assets/BeardedManStudios/Scripts/Networking/Forge/Networking/UDPClient.cs @@ -108,12 +108,14 @@ private void AttemptServerConnection(object _) // This is a typical Websockets accept header to be validated byte[] connectHeader = Websockets.ConnectionHeader(headerHash, Port); + Client.IgnoreICMPErrors(true); do { // Send the accept headers to the server to validate Client.Send(connectHeader, connectHeader.Length, ServerPlayer.IPEndPointHandle); Thread.Sleep(3000); } while (!initialConnectHeaderExchanged && IsBound && ++connectCounter < CONNECT_TRIES); + Client.IgnoreICMPErrors(false); if (connectCounter >= CONNECT_TRIES && connectAttemptFailed != null) connectAttemptFailed(this);