From 487eadae1954a6815944a71d78bac6badac5bcbe Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Mon, 1 Dec 2025 18:37:02 +0100 Subject: [PATCH 1/5] Avoid overflow when calculating maxCapacity --- .../Runtime/Transports/UTP/UnityTransport.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index cf207cc725..26c4cb96ec 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -11,6 +11,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; +using Unity.Mathematics; using Unity.Netcode.Runtime; using Unity.Networking.Transport; using Unity.Networking.Transport.Error; @@ -1535,7 +1536,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.Max(fullCalculation, int.MaxValue); + } queue = new BatchedSendQueue(Math.Max(maxCapacity, m_MaxPayloadSize)); m_SendQueue.Add(sendTarget, queue); From d12f35f9e0b18d1c3e46753451856d49edfe20b1 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Fri, 5 Dec 2025 19:23:45 +0100 Subject: [PATCH 2/5] CHANGELOG update --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 46c5d0b495..53b966b60b 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -31,6 +31,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) From c0703c36bfa46f5f17f43418e0082db75575d211 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 5 Dec 2025 13:35:40 -0500 Subject: [PATCH 3/5] Add test --- .../Transports/UTP/BatchedSendQueue.cs | 2 ++ .../Runtime/Transports/UTP/UnityTransport.cs | 2 +- .../Transports/UnityTransportTestHelpers.cs | 9 +++--- .../Runtime/Transports/UnityTransportTests.cs | 28 +++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) 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 274899c844..89eb427aa4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -1520,7 +1520,7 @@ public override void Send(ulong clientId, ArraySegment payload, NetworkDel if (maxCapacity <= 0) { var fullCalculation = Math.BigMul(m_DisconnectTimeoutMS, k_MaxReliableThroughput); - maxCapacity = (int)Math.Max(fullCalculation, int.MaxValue); + maxCapacity = (int)Math.Min(fullCalculation, BatchedSendQueue.MaximumMaximumCapacity); } queue = new BatchedSendQueue(Math.Max(maxCapacity, m_MaxPayloadSize)); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 91c33c0d7d..65b6a056b6 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 = 0) { - 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( From 4d79ac108521b2ad1c73f036e2a650cd06348416 Mon Sep 17 00:00:00 2001 From: Noellie Velez Date: Fri, 5 Dec 2025 21:11:28 +0100 Subject: [PATCH 4/5] Removed unused using --- .../Runtime/Transports/UTP/UnityTransport.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 89eb427aa4..ada4619be7 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -11,7 +11,6 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; -using Unity.Mathematics; using Unity.Netcode.Runtime; using Unity.Networking.Transport; using Unity.Networking.Transport.Error; From 17541bf217fe524f81ba4f0be39cce5d115863ea Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 5 Dec 2025 16:19:53 -0500 Subject: [PATCH 5/5] Fix tests --- .../Tests/Runtime/Transports/UnityTransportTestHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 65b6a056b6..f473b1eef3 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -96,7 +96,7 @@ 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, int disconnectTimeout = 0) + 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, disconnectTimeout); }