diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 162e681..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.InterNetwork, 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); @@ -132,7 +132,10 @@ namespace Lidgren.Network m_socket.SendBufferSize = m_configuration.SendBufferSize; m_socket.Blocking = false; - var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress, reBind ? m_listenPort : m_configuration.Port); + 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); try diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index 49b11b4..5b699c6 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 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); 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..c17b776 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,8 @@ namespace Lidgren.Network { if (remoteEndPoint == null) throw new ArgumentNullException("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 cbcf34c..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; @@ -93,7 +95,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 +330,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 { @@ -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 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