diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 88c351890a..72b511f95d 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -49,6 +49,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed issue where maxCapacity calculation overflows if a developer sets a very, very high (large) m_DisconnectTimeoutMS in the Editor for Unity Transport. (#3810) - Fixed issues with the "Client-server quickstart for Netcode for GameObjects" script having static methods and properties. (#3787) - Fixed issue where a warning message was being logged upon a client disconnecting from a server when the log level is set to developer. (#3786) - Fixed issue where the server or host would no longer have access to the transport id to client id table when processing a transport level client disconnect event. (#3786) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/BatchedSendQueue.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/BatchedSendQueue.cs index cb56bf0026..ec892a0b61 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/BatchedSendQueue.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/BatchedSendQueue.cs @@ -31,6 +31,8 @@ internal struct BatchedSendQueue : IDisposable public const int PerMessageOverhead = sizeof(int); internal const int MinimumMinimumCapacity = 4096; + // int.MaxValue is odd and maximum must be even. + internal const int MaximumMaximumCapacity = int.MaxValue - 1; // Indices into m_HeadTailIndicies. private const int k_HeadInternalIndex = 0; diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 1340117f36..ada4619be7 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -1515,7 +1515,12 @@ public override void Send(ulong clientId, ArraySegment payload, NetworkDel // the only case where a full send queue causes a connection loss. Full unreliable // send queues are dealt with by flushing it out to the network or simply dropping // new messages if that fails. - var maxCapacity = m_MaxSendQueueSize > 0 ? m_MaxSendQueueSize : m_DisconnectTimeoutMS * k_MaxReliableThroughput; + var maxCapacity = m_MaxSendQueueSize; + if (maxCapacity <= 0) + { + var fullCalculation = Math.BigMul(m_DisconnectTimeoutMS, k_MaxReliableThroughput); + maxCapacity = (int)Math.Min(fullCalculation, BatchedSendQueue.MaximumMaximumCapacity); + } queue = new BatchedSendQueue(Math.Max(maxCapacity, m_MaxPayloadSize)); m_SendQueue.Add(sendTarget, queue); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 91c33c0d7d..f473b1eef3 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -96,16 +96,16 @@ public static IEnumerator EnsureNoNetworkEvent(List events, floa } // Common code to initialize a UnityTransport that logs its events. - public static void InitializeTransport(out UnityTransport transport, out List events, int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4) + public static void InitializeTransport(out UnityTransport transport, out List events, int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, int disconnectTimeout = NetworkParameterConstants.DisconnectTimeoutMS) { - InitializeTransport(out transport, out events, string.Empty, maxPayloadSize, maxSendQueueSize, family); + InitializeTransport(out transport, out events, string.Empty, maxPayloadSize, maxSendQueueSize, family, disconnectTimeout); } /// - /// Interanl version with identifier parameter + /// Internal version with identifier parameter /// internal static void InitializeTransport(out UnityTransport transport, out List events, string identifier, - int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4) + int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, int disconnectTimeout = NetworkParameterConstants.DisconnectTimeoutMS) { var logger = new TransportEventLogger() { @@ -118,6 +118,7 @@ internal static void InitializeTransport(out UnityTransport transport, out List< transport.OnTransportEvent += logger.HandleEvent; transport.MaxPayloadSize = maxPayloadSize; transport.MaxSendQueueSize = maxSendQueueSize; + transport.DisconnectTimeoutMS = disconnectTimeout; if (family == NetworkFamily.Ipv6) { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs index b6e7d2a012..8edc9c4227 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs @@ -189,6 +189,34 @@ public IEnumerator SendMaximumPayloadSize( yield return null; } + [UnityTest] + public IEnumerator VeryLargeDisconnectTimeout() + { + // We want something that's over the old limit of ~44KB for reliable payloads. + var payloadSize = 64 * 1024; + + var disconnectTimeout = int.MaxValue; + + InitializeTransport(out m_Server, out m_ServerEvents, payloadSize, disconnectTimeout: disconnectTimeout); + InitializeTransport(out m_Client1, out m_Client1Events, payloadSize, disconnectTimeout: disconnectTimeout); + Assert.That(m_Server.DisconnectTimeoutMS, Is.EqualTo(disconnectTimeout)); + Assert.That(m_Client1.DisconnectTimeoutMS, Is.EqualTo(disconnectTimeout)); + + m_Server.StartServer(); + m_Client1.StartClient(); + + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_Client1Events); + + var payload = new ArraySegment(Encoding.ASCII.GetBytes("Some message")); + m_Client1.Send(m_Client1.ServerClientId, payload, NetworkDelivery.Reliable); + + yield return WaitForNetworkEvent(NetworkEvent.Data, m_ServerEvents, MaxNetworkEventWaitTime * 4); + + Assert.That(m_ServerEvents[1].Data, Is.EquivalentTo(Encoding.ASCII.GetBytes("Some message"))); + + yield return null; + } + // Check making multiple sends to a client in a single frame. [UnityTest] public IEnumerator MultipleSendsSingleFrame(