From a0fb9b36ee27fbf939caa64bf4992612fa811a51 Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Tue, 6 May 2025 12:06:46 -0500 Subject: [PATCH 01/14] Add support for connecting via a hostname instead of IP when using supported versions of unity and unity transport. --- .../Runtime/Transports/UTP/UnityTransport.cs | 14 +++++++++----- .../Runtime/com.unity.netcode.runtime.asmdef | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 210d7f660b..9ec69e1c1d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -256,10 +256,7 @@ private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port, bool if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4) && !NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6)) { - if (!silent) - { - Debug.LogError($"Invalid network endpoint: {ip}:{port}."); - } + return default; } return endpoint; @@ -512,8 +509,15 @@ private bool ClientBindAndConnect() // Verify the endpoint is valid before proceeding if (serverEndpoint.Family == NetworkFamily.Invalid) { +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + // If it's not valid, try to treat it like a URL. + InitDriver(); + m_Driver.Connect(ConnectionData.Address, ConnectionData.Port); + return true; +#else Debug.LogError($"Target server network address ({ConnectionData.Address}) is {nameof(NetworkFamily.Invalid)}!"); return false; +#endif } InitDriver(); @@ -625,7 +629,7 @@ public void SetClientRelayData(string ipAddress, ushort port, byte[] allocationI /// /// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call /// - /// The remote IP address (despite the name, can be an IPv6 address) + /// The remote IP address (despite the name, can be an IPv6 address or a domain name) /// The remote port /// The local listen address public void SetConnectionData(string ipv4Address, ushort port, string listenAddress = null) diff --git a/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef b/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef index d68a562768..e4de012706 100644 --- a/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef +++ b/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef @@ -67,6 +67,16 @@ "name": "Unity", "expression": "6000.0.11f1", "define": "COM_UNITY_MODULES_PHYSICS2D_LINEAR" + }, + { + "name": "com.unity.transport", + "expression": "2.4.0", + "define": "UTP_TRANSPORT_2_4_ABOVE" + }, + { + "name": "Unity", + "expression": "6000.1.0a1", + "define": "HOSTNAME_RESOLUTION_AVAILABLE" } ], "noEngineReferences": false From 9649c1b81fdf988785b3e3f7183bdf1fb77caeb1 Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Tue, 6 May 2025 12:08:48 -0500 Subject: [PATCH 02/14] Changelog --- 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 b817a0b6ea..3069602122 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Added +- When using UnityTransport >=2.4 and Unity >= 6000.1.0a1, SetConnectionData will accept a fully qualified hostname instead of an IP as a connect address on the client side. (#3441) ### Fixed From 1c8b4938e9b5c72ee0240cd84c89cb7389cee15a Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Tue, 6 May 2025 16:23:22 -0500 Subject: [PATCH 03/14] Fix failing tests --- .../Editor/Transports/UnityTransportTests.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs index bd9d9e937e..869c1fab76 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs @@ -131,7 +131,6 @@ public void UnityTransport_RestartSucceedsAfterFailure() Assert.False(transport.StartServer()); - LogAssert.Expect(LogType.Error, "Invalid network endpoint: 127.0.0.:4242."); LogAssert.Expect(LogType.Error, "Network listen address (127.0.0.) is Invalid!"); transport.SetConnectionData("127.0.0.1", 4242, "127.0.0.1"); @@ -153,22 +152,6 @@ public void UnityTransport_StartServerWithoutAddresses() transport.Shutdown(); } - // Check that StartClient returns false with bad connection data. - [Test] - public void UnityTransport_StartClientFailsWithBadAddress() - { - UnityTransport transport = new GameObject().AddComponent(); - transport.Initialize(); - - transport.SetConnectionData("foobar", 4242); - Assert.False(transport.StartClient()); - - LogAssert.Expect(LogType.Error, "Invalid network endpoint: foobar:4242."); - LogAssert.Expect(LogType.Error, "Target server network address (foobar) is Invalid!"); - - transport.Shutdown(); - } - [Test] public void UnityTransport_EmptySecurityStringsShouldThrow([Values("", null)] string cert, [Values("", null)] string secret) { From 842635864d8e246674d84089a74e7a2dd041c6a4 Mon Sep 17 00:00:00 2001 From: Kitty Draper Date: Tue, 6 May 2025 16:55:37 -0500 Subject: [PATCH 04/14] Removed test that is no longer valid. --- .../Transports/UnityTransportConnectionTests.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index 3e2c746082..e721c97f8a 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -46,23 +46,6 @@ public IEnumerator Cleanup() yield return null; } - // Check that invalid endpoint addresses are detected and return false if detected - [Test] - public void DetectInvalidEndpoint() - { - using var netcodeLogAssert = new NetcodeLogAssert(true); - InitializeTransport(out m_Server, out m_ServerEvents); - InitializeTransport(out m_Clients[0], out m_ClientsEvents[0]); - m_Server.ConnectionData.Address = "Fubar"; - m_Server.ConnectionData.ServerListenAddress = "Fubar"; - m_Clients[0].ConnectionData.Address = "MoreFubar"; - Assert.False(m_Server.StartServer(), "Server failed to detect invalid endpoint!"); - Assert.False(m_Clients[0].StartClient(), "Client failed to detect invalid endpoint!"); - netcodeLogAssert.LogWasReceived(LogType.Error, $"Network listen address ({m_Server.ConnectionData.Address}) is Invalid!"); - netcodeLogAssert.LogWasReceived(LogType.Error, $"Target server network address ({m_Clients[0].ConnectionData.Address}) is Invalid!"); - UnityTransportTestComponent.CleanUp(); - } - // Check connection with a single client. [UnityTest] public IEnumerator ConnectSingleClient() From a67baa72373c6ff6e5f0a72ef245b7c6fdfed731 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 12:20:07 -0500 Subject: [PATCH 05/14] test and updates Adding FQDN validation and updating log errors provided to users. Adding back the invalid address tests to handle newer and older versions of UTP. --- .../Runtime/Transports/UTP/UnityTransport.cs | 53 +++++++++++++++++-- .../Editor/Transports/UnityTransportTests.cs | 22 +++++++- .../com.unity.netcode.editortests.asmdef | 10 ++++ .../UnityTransportConnectionTests.cs | 29 ++++++++++ .../com.unity.netcode.runtimetests.asmdef | 10 ++++ 5 files changed, 119 insertions(+), 5 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 9ec69e1c1d..468bb3662a 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -7,6 +7,9 @@ using System; using System.Collections.Generic; +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE +using System.Text.RegularExpressions; +#endif using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; @@ -256,7 +259,14 @@ private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port, bool if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4) && !NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6)) { +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE return default; +#else // If the user does not have the most recent version of UnityTransport installed + if (!silent) + { + Debug.LogError($"Invalid network endpoint: {ip}:{port}."); + } +#endif } return endpoint; @@ -483,6 +493,15 @@ private NetworkPipeline SelectSendPipeline(NetworkDelivery delivery) return NetworkPipeline.Null; } } +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + private bool IsValidFqdn(string fqdn) + { + // Regular expression to validate FQDN + string pattern = @"^(?=.{1,255}$)(?!-)[A-Za-z0-9-]{1,63}(?(); + transport.Initialize(); + + transport.SetConnectionData("foobar", 4242); + Assert.False(transport.StartClient()); +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + LogAssert.Expect(LogType.Error, "Target server network address (foobar) is not a valid Fully Qualified Domain Name!"); +#else + LogAssert.Expect(LogType.Error, "Invalid network endpoint: foobar:4242."); + LogAssert.Expect(LogType.Error, "Target server network address (foobar) is Invalid!"); +#endif + transport.Shutdown(); + } + [Test] public void UnityTransport_EmptySecurityStringsShouldThrow([Values("", null)] string cert, [Values("", null)] string secret) { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/com.unity.netcode.editortests.asmdef b/com.unity.netcode.gameobjects/Tests/Editor/com.unity.netcode.editortests.asmdef index b2c942a948..56f600746b 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/com.unity.netcode.editortests.asmdef +++ b/com.unity.netcode.gameobjects/Tests/Editor/com.unity.netcode.editortests.asmdef @@ -33,6 +33,16 @@ "name": "Unity", "expression": "(0,2022.2.0a5)", "define": "UNITY_UNET_PRESENT" + }, + { + "name": "com.unity.transport", + "expression": "2.4.0", + "define": "UTP_TRANSPORT_2_4_ABOVE" + }, + { + "name": "Unity", + "expression": "6000.1.0a1", + "define": "HOSTNAME_RESOLUTION_AVAILABLE" } ] } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index e721c97f8a..192996c729 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -46,6 +46,35 @@ public IEnumerator Cleanup() yield return null; } + // Check that invalid endpoint addresses are detected and return false if detected + [Test] + public void DetectInvalidEndpoint() + { + using var netcodeLogAssert = new NetcodeLogAssert(true); + InitializeTransport(out m_Server, out m_ServerEvents); + InitializeTransport(out m_Clients[0], out m_ClientsEvents[0]); + m_Server.ConnectionData.Address = "Fubar"; + m_Server.ConnectionData.ServerListenAddress = "Fubar"; + m_Clients[0].ConnectionData.Address = "MoreFubar"; + Assert.False(m_Server.StartServer(), "Server failed to detect invalid endpoint!"); + Assert.False(m_Clients[0].StartClient(), "Client failed to detect invalid endpoint!"); +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + LogAssert.Expect(LogType.Error, $"Listen network address ({m_Server.ConnectionData.Address}) is not a valid {Networking.Transport.NetworkFamily.Ipv4} or {Networking.Transport.NetworkFamily.Ipv6} address!"); + LogAssert.Expect(LogType.Error, $"Target server network address ({m_Clients[0].ConnectionData.Address}) is not a valid Fully Qualified Domain Name!"); + + m_Server.ConnectionData.Address = "my.fubar.com"; + m_Server.ConnectionData.ServerListenAddress = "my.fubar.com"; + Assert.False(m_Server.StartServer(), "Server failed to detect invalid endpoint!"); + LogAssert.Expect(LogType.Error, $"While ({m_Server.ConnectionData.Address}) is a valid Fully Qualified Domain Name, you must use a " + + $"valid {Networking.Transport.NetworkFamily.Ipv4} or {Networking.Transport.NetworkFamily.Ipv6} address when binding and listening for connections!"); +#else + netcodeLogAssert.LogWasReceived(LogType.Error, $"Network listen address ({m_Server.ConnectionData.Address}) is Invalid!"); + netcodeLogAssert.LogWasReceived(LogType.Error, $"Target server network address ({m_Clients[0].ConnectionData.Address}) is Invalid!"); +#endif + + UnityTransportTestComponent.CleanUp(); + } + // Check connection with a single client. [UnityTest] public IEnumerator ConnectSingleClient() diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef b/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef index ce8ab1c7eb..7153a15480 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef +++ b/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef @@ -48,6 +48,16 @@ "name": "com.unity.modules.physics", "expression": "", "define": "COM_UNITY_MODULES_PHYSICS" + }, + { + "name": "com.unity.transport", + "expression": "2.4.0", + "define": "UTP_TRANSPORT_2_4_ABOVE" + }, + { + "name": "Unity", + "expression": "6000.1.0a1", + "define": "HOSTNAME_RESOLUTION_AVAILABLE" } ], "noEngineReferences": false From 844dc2dd049ca4e730162ceed68d001d69b63792 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 12:21:46 -0500 Subject: [PATCH 06/14] style removing comment. --- .../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 468bb3662a..36580bbf68 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -592,7 +592,6 @@ private bool ServerBindAndListen(NetworkEndpoint endPoint) Debug.LogError($"While ({ConnectionData.Address}) is a valid Fully Qualified Domain Name, you must use a valid {NetworkFamily.Ipv4} or {NetworkFamily.Ipv6} address when binding and listening for connections!"); } return false; - // Otherwise, attempt to bind to the FQDN's IP resolution #else Debug.LogError($"Network listen address ({ConnectionData.Address}) is {nameof(NetworkFamily.Invalid)}!"); return false; From 947dffae89f088320ae30a256834143ed517fec7 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 13:17:38 -0500 Subject: [PATCH 07/14] test - fix Forgot to update for one of the newer error messages when using an invalid address. --- .../Tests/Editor/Transports/UnityTransportTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs index 0ad2aab37d..8abb6fe6f5 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs @@ -130,11 +130,12 @@ public void UnityTransport_RestartSucceedsAfterFailure() transport.SetConnectionData("127.0.0.", 4242, "127.0.0."); Assert.False(transport.StartServer()); -#if !HOSTNAME_RESOLUTION_AVAILABLE && !UTP_TRANSPORT_2_4_ABOVE +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + LogAssert.Expect(LogType.Error, $"Listen network address (127.0.0.) is not a valid {Networking.Transport.NetworkFamily.Ipv4} or {Networking.Transport.NetworkFamily.Ipv6} address!"); +#else LogAssert.Expect(LogType.Error, "Invalid network endpoint: 127.0.0.:4242."); -#endif LogAssert.Expect(LogType.Error, "Network listen address (127.0.0.) is Invalid!"); - +#endif transport.SetConnectionData("127.0.0.1", 4242, "127.0.0.1"); Assert.True(transport.StartServer()); From f926fae093be4ddda03f576709d32b40b4c51968 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 14:35:51 -0500 Subject: [PATCH 08/14] test - update Fixing an issue with `ClientDisconnectMultipleClients` beginning to disconnect clients before they were connected. Added `UnityTransportTestHelpers.WaitForMultipleNetworkEvents` helper method to wait for a specific number of events of a specified type. Added a `UnityTransportTestHelpers.VerboseDebug` helper method. --- .../UnityTransportConnectionTests.cs | 21 +++-- .../Transports/UnityTransportTestHelpers.cs | 81 ++++++++++++++++--- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index 192996c729..713f9b9b7a 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -22,6 +22,7 @@ internal class UnityTransportConnectionTests [UnityTearDown] public IEnumerator Cleanup() { + LogEventsReceived = false; if (m_Server) { m_Server.Shutdown(); @@ -198,26 +199,32 @@ public IEnumerator ClientDisconnectSingleClient() [UnityTest] public IEnumerator ClientDisconnectMultipleClients() { - InitializeTransport(out m_Server, out m_ServerEvents); - m_Server.StartServer(); + LogEventsReceived = true; + InitializeTransport(out m_Server, out m_ServerEvents, identifier: "Server"); + Assert.True(m_Server.StartServer(), "Failed to start server!"); + for (int i = 0; i < k_NumClients; i++) { - InitializeTransport(out m_Clients[i], out m_ClientsEvents[i]); - m_Clients[i].StartClient(); + InitializeTransport(out m_Clients[i], out m_ClientsEvents[i], identifier: $"Client-{i + 1}"); + Assert.True(m_Clients[i].StartClient(), $"Failed to start client-{i + 1}"); + // Assure all clients have connected before disconnecting them + yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[i], 5); } - yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[k_NumClients - 1]); // Disconnect a single client. + VerboseLog($"Disconnecting Client-1"); m_Clients[0].DisconnectLocalClient(); - yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents); + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents, 1); // Disconnect all the other clients. for (int i = 1; i < k_NumClients; i++) { + VerboseLog($"Disconnecting Client-{i + 1}"); m_Clients[i].DisconnectLocalClient(); } - yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents, 5); + + yield return WaitForMultipleNetworkEvents(NetworkEvent.Disconnect, m_ServerEvents, 4, 20); // Check that we got the correct number of Disconnect events on the server. Assert.AreEqual(k_NumClients * 2, m_ServerEvents.Count); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 926b2fa7bc..76faa794db 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -19,21 +19,63 @@ internal static class UnityTransportTestHelpers // Wait for an event to appear in the given event list (must be the very next event). public static IEnumerator WaitForNetworkEvent(NetworkEvent type, List events, float timeout = MaxNetworkEventWaitTime) { - int initialCount = events.Count; - float startTime = Time.realtimeSinceStartup; - - while (Time.realtimeSinceStartup - startTime < timeout) + var initialCount = events.Count; + var startTime = Time.realtimeSinceStartup + timeout; + var waitPeriod = new WaitForSeconds(0.01f); + var conditionMet = false; + while (startTime > Time.realtimeSinceStartup) { if (events.Count > initialCount) { Assert.AreEqual(type, events[initialCount].Type); - yield break; + conditionMet = true; + break; } - yield return new WaitForSeconds(0.01f); + yield return waitPeriod; + } + if (!conditionMet) + { + Assert.Fail("Timed out while waiting for network event."); } + } + + public static IEnumerator WaitForMultipleNetworkEvents(NetworkEvent type, List events, int count, float timeout = MaxNetworkEventWaitTime) + { + var initialCount = events.Count; + var startTime = Time.realtimeSinceStartup + timeout; + var waitPeriod = new WaitForSeconds(0.01f); + var conditionMet = false; + while (startTime > Time.realtimeSinceStartup) + { + // Wait until we have received at least (count) number of events + if ((events.Count - initialCount) >= count) + { + var foundTypes = 0; + // Look through all events received to match against the type we + // are looking for. + for (int i = initialCount; i < initialCount + count; i++) + { + if (type.Equals(events[i].Type)) + { + foundTypes++; + } + } + // If we reached the number of events we were expecting + conditionMet = foundTypes == count; + if (conditionMet) + { + // break from the wait loop + break; + } + } - Assert.Fail("Timed out while waiting for network event."); + yield return waitPeriod; + } + if (!conditionMet) + { + Assert.Fail("Timed out while waiting for network event."); + } } // Wait to ensure no event is sent. @@ -53,12 +95,14 @@ 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 maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, string identifier = "") { - var logger = new TransportEventLogger(); + var logger = new TransportEventLogger() + { + Identifier = identifier, + }; events = logger.Events; transport = new GameObject().AddComponent(); @@ -75,6 +119,16 @@ public static void InitializeTransport(out UnityTransport transport, out List m_Events = new List(); public List Events => m_Events; + + public string Identifier; public void HandleEvent(NetworkEvent type, ulong clientID, ArraySegment data, float receiveTime) { + if (LogEventsReceived) + { + VerboseLog($"[{Identifier}]Tansport Event][{type}][{receiveTime}] Client-{clientID}"); + } + // Copy the data since the backing array will be reused for future messages. if (data != default(ArraySegment)) { From c72854d9bf24be829a9f151ac9f07d4a20c9e84b Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 14:39:21 -0500 Subject: [PATCH 09/14] style renaming the verbose debug flag to VerboseDebug --- .../Runtime/Transports/UnityTransportConnectionTests.cs | 4 ++-- .../Tests/Runtime/Transports/UnityTransportTestHelpers.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index 713f9b9b7a..95cef48ccd 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -22,7 +22,7 @@ internal class UnityTransportConnectionTests [UnityTearDown] public IEnumerator Cleanup() { - LogEventsReceived = false; + VerboseDebug = false; if (m_Server) { m_Server.Shutdown(); @@ -199,7 +199,7 @@ public IEnumerator ClientDisconnectSingleClient() [UnityTest] public IEnumerator ClientDisconnectMultipleClients() { - LogEventsReceived = true; + VerboseDebug = true; InitializeTransport(out m_Server, out m_ServerEvents, identifier: "Server"); Assert.True(m_Server.StartServer(), "Failed to start server!"); diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 76faa794db..b5ac144c59 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -119,11 +119,11 @@ public static void InitializeTransport(out UnityTransport transport, out List data, float receiveTime) { - if (LogEventsReceived) + if (VerboseDebug) { VerboseLog($"[{Identifier}]Tansport Event][{type}][{receiveTime}] Client-{clientID}"); } From c872a74f53b2c11894edc95c3d8b1f8089b247bb Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 14:42:19 -0500 Subject: [PATCH 10/14] style removing VerboseDebug check on a VerboseLog call. --- .../Tests/Runtime/Transports/UnityTransportTestHelpers.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index b5ac144c59..69dd3bfcc6 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -149,10 +149,7 @@ internal class TransportEventLogger public string Identifier; public void HandleEvent(NetworkEvent type, ulong clientID, ArraySegment data, float receiveTime) { - if (VerboseDebug) - { - VerboseLog($"[{Identifier}]Tansport Event][{type}][{receiveTime}] Client-{clientID}"); - } + VerboseLog($"[{Identifier}]Tansport Event][{type}][{receiveTime}] Client-{clientID}"); // Copy the data since the backing array will be reused for future messages. if (data != default(ArraySegment)) From 52f0e8c9e1c130383e4ceaa4756cadd59cbafbcc Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 15:11:19 -0500 Subject: [PATCH 11/14] test increasing disconnect timeout for 1st client during the ClientDisconnectMultipleClients to account for a slower than expected system. --- .../Tests/Runtime/Transports/UnityTransportConnectionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs index 95cef48ccd..520873a341 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs @@ -215,7 +215,7 @@ public IEnumerator ClientDisconnectMultipleClients() VerboseLog($"Disconnecting Client-1"); m_Clients[0].DisconnectLocalClient(); - yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents, 1); + yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents, 5); // Disconnect all the other clients. for (int i = 1; i < k_NumClients; i++) From 9232fdb8bc00d4f69ca389e294d6da9247a5e082 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 15:17:16 -0500 Subject: [PATCH 12/14] style - PVP Working around PVP issue. --- .../Runtime/Transports/UnityTransportTestHelpers.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index 69dd3bfcc6..e7aff489a0 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -40,7 +40,7 @@ public static IEnumerator WaitForNetworkEvent(NetworkEvent type, List events, int count, float timeout = MaxNetworkEventWaitTime) + internal static IEnumerator WaitForMultipleNetworkEvents(NetworkEvent type, List events, int count, float timeout = MaxNetworkEventWaitTime) { var initialCount = events.Count; var startTime = Time.realtimeSinceStartup + timeout; @@ -96,7 +96,15 @@ 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, + public static void InitializeTransport(out UnityTransport transport, out List events, int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4) + { + InitializeTransport(out transport, out events, maxPayloadSize, maxSendQueueSize, family, string.Empty); + } + + /// + /// Interanl version with identifier parameter + /// + internal static void InitializeTransport(out UnityTransport transport, out List events, int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, string identifier = "") { var logger = new TransportEventLogger() From bdcb1d449d09f459c41dbbae9ace21f250b97d98 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Thu, 8 May 2025 15:22:01 -0500 Subject: [PATCH 13/14] fix Re-arranging parameters between both methods. --- .../Tests/Runtime/Transports/UnityTransportTestHelpers.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs index e7aff489a0..91c33c0d7d 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs @@ -98,14 +98,14 @@ 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) { - InitializeTransport(out transport, out events, maxPayloadSize, maxSendQueueSize, family, string.Empty); + InitializeTransport(out transport, out events, string.Empty, maxPayloadSize, maxSendQueueSize, family); } /// /// Interanl version with identifier parameter /// - internal static void InitializeTransport(out UnityTransport transport, out List events, - int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, string identifier = "") + internal static void InitializeTransport(out UnityTransport transport, out List events, string identifier, + int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4) { var logger = new TransportEventLogger() { From d5cf0cfb7c8a97bf822dba65c7093a82e591ddbd Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Tue, 13 May 2025 16:07:24 -0500 Subject: [PATCH 14/14] update Refactoring the end point parsing within ConnectionAddressData. --- .../Runtime/Transports/UTP/UnityTransport.cs | 58 ++++++++++++------- .../Editor/Transports/UnityTransportTests.cs | 7 ++- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs index 36580bbf68..31b20b6630 100644 --- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs +++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs @@ -252,30 +252,41 @@ public struct ConnectionAddressData [SerializeField] public string ServerListenAddress; - private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port, bool silent = false) + private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port) { NetworkEndpoint endpoint = default; - - if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4) && - !NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6)) + if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4)) { -#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE - return default; -#else // If the user does not have the most recent version of UnityTransport installed - if (!silent) - { - Debug.LogError($"Invalid network endpoint: {ip}:{port}."); - } -#endif + NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6); } - return endpoint; } + private void InvalidEndpointError() + { + Debug.LogError($"Invalid network endpoint: {Address}:{Port}."); + } + /// /// Endpoint (IP address and port) clients will connect to. /// - public NetworkEndpoint ServerEndPoint => ParseNetworkEndpoint(Address, Port); + public NetworkEndpoint ServerEndPoint + { + get + { + var networkEndpoint = ParseNetworkEndpoint(Address, Port); + if (networkEndpoint == default) + { +#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE + if (!IsValidFqdn(Address)) +#endif + { + InvalidEndpointError(); + } + } + return networkEndpoint; + } + } /// /// Endpoint (IP address and port) server will listen/bind on. @@ -284,30 +295,35 @@ public NetworkEndpoint ListenEndPoint { get { + NetworkEndpoint endpoint = default; if (string.IsNullOrEmpty(ServerListenAddress)) { - var ep = NetworkEndpoint.LoopbackIpv4; + endpoint = NetworkEndpoint.LoopbackIpv4; // If an address was entered and it's IPv6, switch to using ::1 as the // default listen address. (Otherwise we always assume IPv4.) if (!string.IsNullOrEmpty(Address) && ServerEndPoint.Family == NetworkFamily.Ipv6) { - ep = NetworkEndpoint.LoopbackIpv6; + endpoint = NetworkEndpoint.LoopbackIpv6; } - - return ep.WithPort(Port); + endpoint = endpoint.WithPort(Port); } else { - return ParseNetworkEndpoint(ServerListenAddress, Port); + endpoint = ParseNetworkEndpoint(ServerListenAddress, Port); + if (endpoint == default) + { + InvalidEndpointError(); + } } + return endpoint; } } /// /// Returns true if the end point address is of type . /// - public bool IsIpv6 => !string.IsNullOrEmpty(Address) && ParseNetworkEndpoint(Address, Port, true).Family == NetworkFamily.Ipv6; + public bool IsIpv6 => !string.IsNullOrEmpty(Address) && NetworkEndpoint.TryParse(Address, Port, out NetworkEndpoint _, NetworkFamily.Ipv6); } @@ -494,7 +510,7 @@ private NetworkPipeline SelectSendPipeline(NetworkDelivery delivery) } } #if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE - private bool IsValidFqdn(string fqdn) + private static bool IsValidFqdn(string fqdn) { // Regular expression to validate FQDN string pattern = @"^(?=.{1,255}$)(?!-)[A-Za-z0-9-]{1,63}(?