From f0e5bb451533b416d1e216beea5afeb470cc2415 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 15 Feb 2020 00:09:21 +0100 Subject: [PATCH] IPv6: Space Wizard Edition. This PR fixes the IPv6 support *properly*. The two previous PRs, #123 and #126, both made a mess out of it: PR #123 implemented IPv6 by breaking non-dualstack IPv4 support. PR #126 fixed IPv4 support by breaking non-dualstack IPv6 support. This change fixes the mess entirely. IPv4, IPv6 and IPv6-dual-stack are now all independently supported and work as expected. Namely IPv4 can't receive IPv6, IPv6 can only receive IPv4 if NetPeerConfiguration.DualStack is set. You can still have an IPv6-only socket. I'll leave some review comments on the PR for less-immediately obvious changes. --- Lidgren.Network/NetPeer.Internal.cs | 19 ++++++++++------- Lidgren.Network/NetPeer.cs | 28 +++++++++++++++---------- Lidgren.Network/NetPeerConfiguration.cs | 24 ++++++++++----------- Lidgren.Network/NetUtility.cs | 20 +++++++++--------- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index cac3378..c1507d6 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -132,14 +132,19 @@ namespace Lidgren.Network m_socket.SendBufferSize = m_configuration.SendBufferSize; m_socket.Blocking = false; - if(m_configuration.DualStack && m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6) - m_socket.DualMode = true; + if (m_configuration.DualStack) + { + if (m_configuration.LocalAddress.AddressFamily != AddressFamily.InterNetworkV6) + { + LogWarning("Configuration specifies Dual Stack but does not use IPv6 local address; Dual stack will not work."); + } + else + { + m_socket.DualMode = true; + } + } - var localAddress = m_configuration.DualStack - ? m_configuration.LocalAddress.MapToIPv6() - : m_configuration.LocalAddress; - - var ep = (EndPoint)new NetEndPoint(localAddress, reBind ? m_listenPort : m_configuration.Port); + var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress, reBind ? m_listenPort : m_configuration.Port); m_socket.Bind(ep); try diff --git a/Lidgren.Network/NetPeer.cs b/Lidgren.Network/NetPeer.cs index e1a74a3..dec79af 100644 --- a/Lidgren.Network/NetPeer.cs +++ b/Lidgren.Network/NetPeer.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Collections.Generic; using System.Net; - +using System.Net.Sockets; #if !__NOIPENDPOINT__ using NetEndPoint = System.Net.IPEndPoint; #endif @@ -32,8 +32,8 @@ namespace Lidgren.Network /// /// Signalling event which can be waited on to determine when a message is queued for reading. - /// Note that there is no guarantee that after the event is signaled the blocked thread will - /// find the message in the queue. Other user created threads could be preempted and dequeue + /// Note that there is no guarantee that after the event is signaled the blocked thread will + /// find the message in the queue. Other user created threads could be preempted and dequeue /// the message before the waiting thread wakes up. /// public AutoResetEvent MessageReceivedEvent @@ -121,10 +121,16 @@ namespace Lidgren.Network m_connections = new List(); m_connectionLookup = new Dictionary(); m_handshakes = new Dictionary(); - var address = config.DualStack ? IPAddress.IPv6Any : IPAddress.Any; - m_senderRemote = (EndPoint)new NetEndPoint(address, 0); + if (m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6) + { + m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); + } + else + { + m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0); + } m_status = NetPeerStatus.NotRunning; - m_receivedFragmentGroups = new Dictionary>(); + m_receivedFragmentGroups = new Dictionary>(); } /// @@ -149,7 +155,7 @@ namespace Lidgren.Network } InitializeNetwork(); - + // start network thread m_networkThread = new Thread(new ThreadStart(NetworkLoop)); m_networkThread.Name = m_configuration.NetworkThreadName; @@ -184,7 +190,7 @@ namespace Lidgren.Network public NetIncomingMessage WaitMessage(int maxMillis) { NetIncomingMessage msg = ReadMessage(); - + while (msg == null) { // This could return true... @@ -192,11 +198,11 @@ namespace Lidgren.Network { return null; } - + // ... while this will still returns null. That's why we need to cycle. msg = ReadMessage(); } - + return msg; } @@ -216,7 +222,7 @@ namespace Lidgren.Network } return retval; } - + /// /// Reads a pending message from any connection, if any. /// Returns true if message was read, otherwise false. diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index d33d938..5fc6a89 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -35,12 +35,12 @@ namespace Lidgren.Network // -4 bytes to be on the safe side and align to 8-byte boundary // Total 1408 bytes // Note that lidgren headers (5 bytes) are not included here; since it's part of the "mtu payload" - + /// /// Default MTU value in bytes /// public const int kDefaultMTU = 1408; - + private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer"; private bool m_isLocked; @@ -344,23 +344,21 @@ namespace Lidgren.Network } /// - /// Gets or sets a value indicating whether the library should use IPv6 dual stack mode + /// Gets or sets a value indicating whether the library should use IPv6 dual stack mode. + /// If you enable this you should make sure that the is an IPv6 address. + /// Cannot be changed once NetPeer is initialized. /// - public bool DualStack - { + public bool DualStack + { get { return m_dualStack; } - set - { + set + { if (m_isLocked) throw new NetException(c_isLockedMessage); m_dualStack = value; - if (m_dualStack && m_localAddress.Equals(IPAddress.Any)) - m_localAddress = IPAddress.IPv6Any; - if (!m_dualStack && m_localAddress.Equals(IPAddress.IPv6Any)) - m_localAddress = IPAddress.Any; - } + } } - + /// /// Gets or sets the local broadcast address to use when broadcasting /// diff --git a/Lidgren.Network/NetUtility.cs b/Lidgren.Network/NetUtility.cs index 19ed797..1120faa 100644 --- a/Lidgren.Network/NetUtility.cs +++ b/Lidgren.Network/NetUtility.cs @@ -163,7 +163,7 @@ namespace Lidgren.Network } } - /// + /// /// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname /// public static NetAddress Resolve(string ipOrHost) @@ -240,7 +240,7 @@ namespace Lidgren.Network } return new string(c); } - + /// /// Returns true if the endpoint supplied is on the same subnet as this host /// @@ -471,23 +471,23 @@ namespace Lidgren.Network /// /// Source. /// Destination. - internal static void CopyEndpoint(IPEndPoint src, IPEndPoint dst) - { + internal static void CopyEndpoint(IPEndPoint src, IPEndPoint dst) + { dst.Port = src.Port; if (src.AddressFamily == AddressFamily.InterNetwork) dst.Address = src.Address.MapToIPv6(); else - dst.Address = src.Address; + dst.Address = src.Address; } /// /// Maps the IPEndPoint object to an IPv6 address. Has allocation /// - internal static IPEndPoint MapToIPv6(IPEndPoint endPoint) - { + internal static IPEndPoint MapToIPv6(IPEndPoint endPoint) + { if (endPoint.AddressFamily == AddressFamily.InterNetwork) return new IPEndPoint(endPoint.Address.MapToIPv6(), endPoint.Port); - return endPoint; - } + return endPoint; + } } -} \ No newline at end of file +}