From 1a2301ddbc2b00583a7b1e566515fedf5617d106 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Fri, 3 May 2019 03:20:58 +0930 Subject: [PATCH 1/2] Implement IPv6 Dual Mode --- Lidgren.Network/NetPeer.Internal.cs | 5 +-- Lidgren.Network/NetPeer.LatencySimulation.cs | 34 ++++++++++-------- Lidgren.Network/NetPeer.cs | 3 +- Lidgren.Network/NetPeerConfiguration.cs | 4 +-- Lidgren.Network/NetUtility.cs | 36 ++++++++++++++++---- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 162e681..c80afc3 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -123,7 +123,7 @@ namespace Lidgren.Network mutex.WaitOne(); if (m_socket == null) - m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + m_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); if (reBind) m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1); @@ -131,8 +131,9 @@ namespace Lidgren.Network m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize; m_socket.SendBufferSize = m_configuration.SendBufferSize; m_socket.Blocking = false; + m_socket.DualMode = true; - var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress, reBind ? m_listenPort : m_configuration.Port); + var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress.MapToIPv6(), reBind ? m_listenPort : m_configuration.Port); m_socket.Bind(ep); try diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index 49b11b4..c221975 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -132,25 +132,31 @@ namespace Lidgren.Network catch { } } + //Avoids allocation on mapping to IPv6 + private IPEndPoint targetCopy = new IPEndPoint(IPAddress.Any, 0); + internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, out bool connectionReset) { connectionReset = false; IPAddress ba = default(IPAddress); try { - ba = NetUtility.GetCachedBroadcastAddress(); - - // TODO: refactor this check outta here - if (target.Address.Equals(ba)) - { - // Some networks do not allow - // a global broadcast so we use the BroadcastAddress from the configuration - // this can be resolved to a local broadcast addresss e.g 192.168.x.255 - target.Address = m_configuration.BroadcastAddress; - m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - } - - int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, target); + ba = NetUtility.GetCachedBroadcastAddress(); + + // TODO: refactor this check outta here + if (target.Address.Equals(ba)) + { + // Some networks do not allow + // a global broadcast so we use the BroadcastAddress from the configuration + // this can be resolved to a local broadcast addresss e.g 192.168.x.255 + targetCopy.Address = m_configuration.BroadcastAddress; + targetCopy.Port = target.Port; + m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); + } + else + NetUtility.CopyEndpoint(target, targetCopy); //Maps to IPv6 for Dual Mode + + int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, targetCopy); if (numBytes != bytesSent) LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!"); @@ -178,7 +184,7 @@ namespace Lidgren.Network } finally { - if (target.Address == ba) + if (target.Address.Equals(ba)) m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); } return true; diff --git a/Lidgren.Network/NetPeer.cs b/Lidgren.Network/NetPeer.cs index 737015c..459e091 100644 --- a/Lidgren.Network/NetPeer.cs +++ b/Lidgren.Network/NetPeer.cs @@ -121,7 +121,7 @@ namespace Lidgren.Network m_connections = new List(); m_connectionLookup = new Dictionary(); m_handshakes = new Dictionary(); - m_senderRemote = (EndPoint)new NetEndPoint(IPAddress.Any, 0); + m_senderRemote = (EndPoint)new NetEndPoint(IPAddress.IPv6Any, 0); m_status = NetPeerStatus.NotRunning; m_receivedFragmentGroups = new Dictionary>(); } @@ -303,6 +303,7 @@ namespace Lidgren.Network { if (remoteEndPoint == null) throw new ArgumentNullException("remoteEndPoint"); + remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint); lock (m_connections) { diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index cbcf34c..4e9f460 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -93,7 +93,7 @@ namespace Lidgren.Network // m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated | NetIncomingMessageType.NatIntroductionSuccess; m_networkThreadName = "Lidgren network thread"; - m_localAddress = IPAddress.Any; + m_localAddress = IPAddress.IPv6Any; m_broadcastAddress = IPAddress.Broadcast; var ip = NetUtility.GetBroadcastAddress(); if (ip != null) @@ -328,7 +328,7 @@ namespace Lidgren.Network } /// - /// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized. + /// Gets or sets the local ip address to bind to. Defaults to IPAddress.IPv6Any. Cannot be changed once NetPeer is initialized. /// public IPAddress LocalAddress { diff --git a/Lidgren.Network/NetUtility.cs b/Lidgren.Network/NetUtility.cs index 20ac1e6..a7798fb 100644 --- a/Lidgren.Network/NetUtility.cs +++ b/Lidgren.Network/NetUtility.cs @@ -98,7 +98,7 @@ namespace Lidgren.Network NetAddress ipAddress = null; if (NetAddress.TryParse(ipOrHost, out ipAddress)) { - if (ipAddress.AddressFamily == AddressFamily.InterNetwork) + if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6) { callback(ipAddress); return; @@ -139,7 +139,7 @@ namespace Lidgren.Network // check each entry for a valid IP address foreach (var ipCurrent in entry.AddressList) { - if (ipCurrent.AddressFamily == AddressFamily.InterNetwork) + if (ipCurrent.AddressFamily == AddressFamily.InterNetwork || ipCurrent.AddressFamily == AddressFamily.InterNetworkV6) { callback(ipCurrent); return; @@ -176,9 +176,9 @@ namespace Lidgren.Network NetAddress ipAddress = null; if (NetAddress.TryParse(ipOrHost, out ipAddress)) { - if (ipAddress.AddressFamily == AddressFamily.InterNetwork) + if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6) return ipAddress; - throw new ArgumentException("This method will not currently resolve other than ipv4 addresses"); + throw new ArgumentException("This method will not currently resolve other than IPv4 or IPv6 addresses"); } // ok must be a host name @@ -189,7 +189,7 @@ namespace Lidgren.Network return null; foreach (var address in addresses) { - if (address.AddressFamily == AddressFamily.InterNetwork) + if (address.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6) return address; } return null; @@ -465,5 +465,29 @@ namespace Lidgren.Network // this is defined in the platform specific files return ComputeSHAHash(bytes, 0, bytes.Length); } - } + + /// + /// Copies from to . Maps to an IPv6 address + /// + /// Source. + /// Destination. + 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; + } + + /// + /// Maps the IPEndPoint object to an IPv6 address. Has allocation + /// + internal static IPEndPoint MapToIPv6(IPEndPoint endPoint) + { + if (endPoint.AddressFamily == AddressFamily.InterNetwork) + return new IPEndPoint(endPoint.Address.MapToIPv6(), endPoint.Port); + return endPoint; + } + } } \ No newline at end of file From 85ad100f890c25382616bbcb400be0e954eefbf7 Mon Sep 17 00:00:00 2001 From: CallumDev Date: Mon, 10 Jun 2019 02:28:38 +0930 Subject: [PATCH 2/2] Can configure to be dual-mode, or plain IPv4/6 --- Lidgren.Network/NetPeer.Internal.cs | 6 +++-- Lidgren.Network/NetPeer.LatencySimulation.cs | 2 +- Lidgren.Network/NetPeer.cs | 3 ++- Lidgren.Network/NetPeerConfiguration.cs | 24 ++++++++++++++++---- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index c80afc3..6ed899e 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -123,7 +123,7 @@ namespace Lidgren.Network mutex.WaitOne(); if (m_socket == null) - m_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); + m_socket = new Socket(m_configuration.LocalAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp); if (reBind) m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1); @@ -131,7 +131,9 @@ namespace Lidgren.Network m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize; m_socket.SendBufferSize = m_configuration.SendBufferSize; m_socket.Blocking = false; - m_socket.DualMode = true; + + if(m_configuration.DualStack && m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6) + m_socket.DualMode = true; var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress.MapToIPv6(), reBind ? m_listenPort : m_configuration.Port); m_socket.Bind(ep); diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index c221975..5b699c6 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -153,7 +153,7 @@ namespace Lidgren.Network targetCopy.Port = target.Port; m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); } - else + else if(m_configuration.DualStack && m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6) NetUtility.CopyEndpoint(target, targetCopy); //Maps to IPv6 for Dual Mode int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, targetCopy); diff --git a/Lidgren.Network/NetPeer.cs b/Lidgren.Network/NetPeer.cs index 459e091..c17b776 100644 --- a/Lidgren.Network/NetPeer.cs +++ b/Lidgren.Network/NetPeer.cs @@ -303,7 +303,8 @@ namespace Lidgren.Network { if (remoteEndPoint == null) throw new ArgumentNullException("remoteEndPoint"); - remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint); + if(m_configuration.DualStack) + remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint); lock (m_connections) { diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index 4e9f460..b337e6d 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -48,6 +48,8 @@ namespace Lidgren.Network private string m_networkThreadName; private IPAddress m_localAddress; private IPAddress m_broadcastAddress; + private bool m_dualStack; + internal bool m_acceptIncomingConnections; internal int m_maximumConnections; internal int m_defaultOutgoingMessageCapacity; @@ -341,10 +343,24 @@ namespace Lidgren.Network } } - /// - /// Gets or sets the local broadcast address to use when broadcasting - /// - public IPAddress BroadcastAddress + /// + /// Gets or sets a value indicating whether the library should use IPv6 dual stack mode + /// + public bool DualStack + { + get { return m_dualStack; } + set + { + if (m_isLocked) + throw new NetException(c_isLockedMessage); + m_dualStack = value; + } + } + + /// + /// Gets or sets the local broadcast address to use when broadcasting + /// + public IPAddress BroadcastAddress { get { return m_broadcastAddress; } set