Skip to content

Commit b7c08c5

Browse files
update
Bringing the updates from #3441 to the v1.x.x branch.
1 parent 9cf9ec7 commit b7c08c5

File tree

6 files changed

+198
-25
lines changed

6 files changed

+198
-25
lines changed

com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
using System;
99
using System.Collections.Generic;
10+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
11+
using System.Text.RegularExpressions;
12+
#endif
1013
using UnityEngine;
1114
using NetcodeNetworkEvent = Unity.Netcode.NetworkEvent;
1215
using TransportNetworkEvent = Unity.Networking.Transport.NetworkEvent;
@@ -317,7 +320,14 @@ private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port, bool
317320
if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4) &&
318321
!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6))
319322
{
323+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
320324
return default;
325+
#else // If the user does not have the most recent version of UnityTransport installed
326+
if (!silent)
327+
{
328+
Debug.LogError($"Invalid network endpoint: {ip}:{port}.");
329+
}
330+
#endif
321331
}
322332

323333
return endpoint;
@@ -514,6 +524,16 @@ private NetworkPipeline SelectSendPipeline(NetworkDelivery delivery)
514524
}
515525
}
516526

527+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
528+
private bool IsValidFqdn(string fqdn)
529+
{
530+
// Regular expression to validate FQDN
531+
string pattern = @"^(?=.{1,255}$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)\.(?!-)(?:[A-Za-z0-9-]{1,63}\.?)+[A-Za-z]{2,6}$";
532+
var regex = new Regex(pattern);
533+
return regex.IsMatch(fqdn);
534+
}
535+
#endif
536+
517537
private bool ClientBindAndConnect()
518538
{
519539
var serverEndpoint = default(NetworkEndpoint);
@@ -542,11 +562,21 @@ private bool ClientBindAndConnect()
542562
if (serverEndpoint.Family == NetworkFamily.Invalid)
543563
{
544564
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
545-
// If it's not valid, try to treat it like a URL.
546-
InitDriver();
547-
serverConnection = m_Driver.Connect(ConnectionData.Address, ConnectionData.Port);
548-
m_ServerClientId = ParseClientId(serverConnection);
549-
return true;
565+
// If it's not valid, assure it meets FQDN standards
566+
if (IsValidFqdn(ConnectionData.Address))
567+
{
568+
// If so, then proceed with driver initialization and attempt to connect
569+
InitDriver();
570+
serverConnection = m_Driver.Connect(ConnectionData.Address, ConnectionData.Port);
571+
m_ServerClientId = ParseClientId(serverConnection);
572+
return true;
573+
}
574+
else
575+
{
576+
// If not then log an error and return false
577+
Debug.LogError($"Target server network address ({ConnectionData.Address}) is not a valid Fully Qualified Domain Name!");
578+
return false;
579+
}
550580
#else
551581
Debug.LogError($"Target server network address ({ConnectionData.Address}) is {nameof(NetworkFamily.Invalid)}!");
552582
return false;
@@ -574,8 +604,22 @@ private bool ServerBindAndListen(NetworkEndpoint endPoint)
574604
// Verify the endpoint is valid before proceeding
575605
if (endPoint.Family == NetworkFamily.Invalid)
576606
{
607+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
608+
// If it's not valid, assure it meets FQDN standards
609+
if (!IsValidFqdn(ConnectionData.Address))
610+
{
611+
// If not then log an error and return false
612+
Debug.LogError($"Listen network address ({ConnectionData.Address}) is not a valid {NetworkFamily.Ipv4} or {NetworkFamily.Ipv6} address!");
613+
}
614+
else
615+
{
616+
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!");
617+
}
618+
return false;
619+
#else
577620
Debug.LogError($"Network listen address ({ConnectionData.Address}) is {nameof(NetworkFamily.Invalid)}!");
578621
return false;
622+
#endif
579623
}
580624

581625
InitDriver();

com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ public void UnityTransport_RestartSucceedsAfterFailure()
118118
transport.SetConnectionData("127.0.0.", 4242, "127.0.0.");
119119

120120
Assert.False(transport.StartServer());
121-
121+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
122+
LogAssert.Expect(LogType.Error, $"Listen network address (127.0.0.) is not a valid {Networking.Transport.NetworkFamily.Ipv4} or {Networking.Transport.NetworkFamily.Ipv6} address!");
123+
#else
124+
LogAssert.Expect(LogType.Error, "Invalid network endpoint: 127.0.0.:4242.");
122125
LogAssert.Expect(LogType.Error, "Network listen address (127.0.0.) is Invalid!");
126+
#endif
123127

124128
transport.SetConnectionData("127.0.0.1", 4242, "127.0.0.1");
125129
Assert.True(transport.StartServer());
@@ -140,6 +144,25 @@ public void UnityTransport_StartServerWithoutAddresses()
140144
transport.Shutdown();
141145
}
142146

147+
// Check that StartClient returns false with bad connection data.
148+
[Test]
149+
public void UnityTransport_StartClientFailsWithBadAddress()
150+
{
151+
UnityTransport transport = new GameObject().AddComponent<UnityTransport>();
152+
transport.Initialize();
153+
154+
transport.SetConnectionData("foobar", 4242);
155+
Assert.False(transport.StartClient());
156+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
157+
LogAssert.Expect(LogType.Error, "Target server network address (foobar) is not a valid Fully Qualified Domain Name!");
158+
#else
159+
LogAssert.Expect(LogType.Error, "Invalid network endpoint: foobar:4242.");
160+
LogAssert.Expect(LogType.Error, "Target server network address (foobar) is Invalid!");
161+
#endif
162+
163+
transport.Shutdown();
164+
}
165+
143166
#if UTP_TRANSPORT_2_0_ABOVE
144167
[Test]
145168
public void UnityTransport_EmptySecurityStringsShouldThrow([Values("", null)] string cert, [Values("", null)] string secret)

com.unity.netcode.gameobjects/Tests/Editor/com.unity.netcode.editortests.asmdef

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@
3838
"name": "com.unity.transport",
3939
"expression": "2.0.0-exp",
4040
"define": "UTP_TRANSPORT_2_0_ABOVE"
41+
},
42+
{
43+
"name": "com.unity.transport",
44+
"expression": "2.4.0",
45+
"define": "UTP_TRANSPORT_2_4_ABOVE"
46+
},
47+
{
48+
"name": "Unity",
49+
"expression": "6000.1.0a1",
50+
"define": "HOSTNAME_RESOLUTION_AVAILABLE"
4151
}
4252
]
4353
}

com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportConnectionTests.cs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class UnityTransportConnectionTests
2222
[UnityTearDown]
2323
public IEnumerator Cleanup()
2424
{
25+
VerboseDebug = false;
2526
if (m_Server)
2627
{
2728
m_Server.Shutdown();
@@ -45,6 +46,33 @@ public IEnumerator Cleanup()
4546
yield return null;
4647
}
4748

49+
// Check that invalid endpoint addresses are detected and return false if detected
50+
[Test]
51+
public void DetectInvalidEndpoint()
52+
{
53+
using var netcodeLogAssert = new NetcodeLogAssert(true);
54+
InitializeTransport(out m_Server, out m_ServerEvents);
55+
InitializeTransport(out m_Clients[0], out m_ClientsEvents[0]);
56+
m_Server.ConnectionData.Address = "Fubar";
57+
m_Server.ConnectionData.ServerListenAddress = "Fubar";
58+
m_Clients[0].ConnectionData.Address = "MoreFubar";
59+
Assert.False(m_Server.StartServer(), "Server failed to detect invalid endpoint!");
60+
Assert.False(m_Clients[0].StartClient(), "Client failed to detect invalid endpoint!");
61+
#if HOSTNAME_RESOLUTION_AVAILABLE && UTP_TRANSPORT_2_4_ABOVE
62+
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!");
63+
LogAssert.Expect(LogType.Error, $"Target server network address ({m_Clients[0].ConnectionData.Address}) is not a valid Fully Qualified Domain Name!");
64+
65+
m_Server.ConnectionData.Address = "my.fubar.com";
66+
m_Server.ConnectionData.ServerListenAddress = "my.fubar.com";
67+
Assert.False(m_Server.StartServer(), "Server failed to detect invalid endpoint!");
68+
LogAssert.Expect(LogType.Error, $"While ({m_Server.ConnectionData.Address}) is a valid Fully Qualified Domain Name, you must use a " +
69+
$"valid {Networking.Transport.NetworkFamily.Ipv4} or {Networking.Transport.NetworkFamily.Ipv6} address when binding and listening for connections!");
70+
#else
71+
netcodeLogAssert.LogWasReceived(LogType.Error, $"Network listen address ({m_Server.ConnectionData.Address}) is Invalid!");
72+
netcodeLogAssert.LogWasReceived(LogType.Error, $"Target server network address ({m_Clients[0].ConnectionData.Address}) is Invalid!");
73+
#endif
74+
}
75+
4876
// Check connection with a single client.
4977
[UnityTest]
5078
public IEnumerator ConnectSingleClient()
@@ -170,35 +198,36 @@ public IEnumerator ClientDisconnectSingleClient()
170198
[UnityTest]
171199
public IEnumerator ClientDisconnectMultipleClients()
172200
{
173-
InitializeTransport(out m_Server, out m_ServerEvents);
174-
m_Server.StartServer();
201+
VerboseDebug = true;
202+
InitializeTransport(out m_Server, out m_ServerEvents, identifier: "Server");
203+
Assert.True(m_Server.StartServer(), "Failed to start server!");
175204

176205
for (int i = 0; i < k_NumClients; i++)
177206
{
178-
InitializeTransport(out m_Clients[i], out m_ClientsEvents[i]);
179-
m_Clients[i].StartClient();
207+
InitializeTransport(out m_Clients[i], out m_ClientsEvents[i], identifier: $"Client-{i + 1}");
208+
Assert.True(m_Clients[i].StartClient(), $"Failed to start client-{i + 1}");
209+
// Assure all clients have connected before disconnecting them
210+
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[i], 5);
180211
}
181212

182-
yield return WaitForNetworkEvent(NetworkEvent.Connect, m_ClientsEvents[k_NumClients - 1]);
183-
184213
// Disconnect a single client.
214+
VerboseLog($"Disconnecting Client-1");
185215
m_Clients[0].DisconnectLocalClient();
186216

187-
yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents);
217+
yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents, 1);
188218

189219
// Disconnect all the other clients.
190220
for (int i = 1; i < k_NumClients; i++)
191221
{
222+
VerboseLog($"Disconnecting Client-{i + 1}");
192223
m_Clients[i].DisconnectLocalClient();
193224
}
194225

195-
yield return WaitForNetworkEvent(NetworkEvent.Disconnect, m_ServerEvents);
226+
yield return WaitForMultipleNetworkEvents(NetworkEvent.Disconnect, m_ServerEvents, 4, 20);
196227

197228
// Check that we got the correct number of Disconnect events on the server.
198229
Assert.AreEqual(k_NumClients * 2, m_ServerEvents.Count);
199230
Assert.AreEqual(k_NumClients, m_ServerEvents.Count(e => e.Type == NetworkEvent.Disconnect));
200-
201-
yield return null;
202231
}
203232

204233
// Check that server re-disconnects are no-ops.

com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTestHelpers.cs

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,63 @@ public static class UnityTransportTestHelpers
1919
// Wait for an event to appear in the given event list (must be the very next event).
2020
public static IEnumerator WaitForNetworkEvent(NetworkEvent type, List<TransportEvent> events, float timeout = MaxNetworkEventWaitTime)
2121
{
22-
int initialCount = events.Count;
23-
float startTime = Time.realtimeSinceStartup;
24-
25-
while (Time.realtimeSinceStartup - startTime < timeout)
22+
var initialCount = events.Count;
23+
var startTime = Time.realtimeSinceStartup + timeout;
24+
var waitPeriod = new WaitForSeconds(0.01f);
25+
var conditionMet = false;
26+
while (startTime > Time.realtimeSinceStartup)
2627
{
2728
if (events.Count > initialCount)
2829
{
2930
Assert.AreEqual(type, events[initialCount].Type);
30-
yield break;
31+
conditionMet = true;
32+
break;
3133
}
3234

33-
yield return new WaitForSeconds(0.01f);
35+
yield return waitPeriod;
36+
}
37+
if (!conditionMet)
38+
{
39+
Assert.Fail("Timed out while waiting for network event.");
3440
}
41+
}
3542

36-
Assert.Fail("Timed out while waiting for network event.");
43+
public static IEnumerator WaitForMultipleNetworkEvents(NetworkEvent type, List<TransportEvent> events, int count, float timeout = MaxNetworkEventWaitTime)
44+
{
45+
var initialCount = events.Count;
46+
var startTime = Time.realtimeSinceStartup + timeout;
47+
var waitPeriod = new WaitForSeconds(0.01f);
48+
var conditionMet = false;
49+
while (startTime > Time.realtimeSinceStartup)
50+
{
51+
// Wait until we have received at least (count) number of events
52+
if ((events.Count - initialCount) >= count)
53+
{
54+
var foundTypes = 0;
55+
// Look through all events received to match against the type we
56+
// are looking for.
57+
for (int i = initialCount; i < initialCount + count; i++)
58+
{
59+
if (type.Equals(events[i].Type))
60+
{
61+
foundTypes++;
62+
}
63+
}
64+
// If we reached the number of events we were expecting
65+
conditionMet = foundTypes == count;
66+
if (conditionMet)
67+
{
68+
// break from the wait loop
69+
break;
70+
}
71+
}
72+
73+
yield return waitPeriod;
74+
}
75+
if (!conditionMet)
76+
{
77+
Assert.Fail("Timed out while waiting for network event.");
78+
}
3779
}
3880

3981
// Wait to ensure no event is sent.
@@ -55,9 +97,12 @@ public static IEnumerator EnsureNoNetworkEvent(List<TransportEvent> events, floa
5597

5698
// Common code to initialize a UnityTransport that logs its events.
5799
public static void InitializeTransport(out UnityTransport transport, out List<TransportEvent> events,
58-
int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4)
100+
int maxPayloadSize = UnityTransport.InitialMaxPayloadSize, int maxSendQueueSize = 0, NetworkFamily family = NetworkFamily.Ipv4, string identifier = "")
59101
{
60-
var logger = new TransportEventLogger();
102+
var logger = new TransportEventLogger()
103+
{
104+
Identifier = identifier,
105+
};
61106
events = logger.Events;
62107

63108
transport = new GameObject().AddComponent<UnityTransport>();
@@ -74,6 +119,16 @@ public static void InitializeTransport(out UnityTransport transport, out List<Tr
74119
transport.Initialize();
75120
}
76121

122+
public static bool VerboseDebug = false;
123+
124+
public static void VerboseLog(string msg)
125+
{
126+
if (VerboseDebug)
127+
{
128+
Debug.Log($"{msg}");
129+
}
130+
}
131+
77132
// Information about an event generated by a transport (basically just the parameters that
78133
// are normally passed along to a TransportEventDelegate).
79134
public struct TransportEvent
@@ -90,8 +145,10 @@ public class TransportEventLogger
90145
{
91146
private readonly List<TransportEvent> m_Events = new List<TransportEvent>();
92147
public List<TransportEvent> Events => m_Events;
148+
public string Identifier;
93149
public void HandleEvent(NetworkEvent type, ulong clientID, ArraySegment<byte> data, float receiveTime)
94150
{
151+
VerboseLog($"[{Identifier}]Tansport Event][{type}][{receiveTime}] Client-{clientID}");
95152
// Copy the data since the backing array will be reused for future messages.
96153
if (data != default(ArraySegment<byte>))
97154
{

com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@
5353
"name": "com.unity.transport",
5454
"expression": "2.0.0-exp",
5555
"define": "UTP_TRANSPORT_2_0_ABOVE"
56+
},
57+
{
58+
"name": "com.unity.transport",
59+
"expression": "2.4.0",
60+
"define": "UTP_TRANSPORT_2_4_ABOVE"
61+
},
62+
{
63+
"name": "Unity",
64+
"expression": "6000.1.0a1",
65+
"define": "HOSTNAME_RESOLUTION_AVAILABLE"
5666
}
5767
],
5868
"noEngineReferences": false

0 commit comments

Comments
 (0)