Skip to content

Commit 37bdf52

Browse files
feat: Allow Unity Transport to bind clients to a specific port (#3764)
* Improve documentation on SetConnectionData * Add possibility of binding clients to a specific port * Don't overwrite the client bind port in SetConnectionData * Add CHANGELOG entry * Bump version to 2.8.0 --------- Co-authored-by: Noel Stephens <[email protected]>
1 parent 9bec5ba commit 37bdf52

File tree

4 files changed

+44
-7
lines changed

4 files changed

+44
-7
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
1010

1111
### Added
1212

13+
- It is now possible to control which port clients will bind to using the `UnityTransport.ConnectionData.ClientBindPort` field. If not set, clients will bind to an ephemeral port (same as before this change). (#3764)
14+
1315

1416
### Changed
1517

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ internal static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port)
245245
return endpoint;
246246
}
247247

248+
/// <summary>
249+
/// The port the client will bind to. If 0 (the default), an ephemeral port will be used.
250+
/// </summary>
251+
[SerializeField]
252+
public ushort ClientBindPort;
253+
248254
/// <summary>
249255
/// Endpoint (IP address and port) clients will connect to.
250256
/// </summary>
@@ -683,6 +689,20 @@ private bool ClientBindAndConnect()
683689
}
684690

685691
InitDriver();
692+
693+
// Don't bind yet if connecting to a hostname, since we don't know if it will resolve to IPv4 or IPv6.
694+
if (serverEndpoint.Family != NetworkFamily.Invalid && ConnectionData.ClientBindPort != 0)
695+
{
696+
var bindEndpoint = serverEndpoint.Family == NetworkFamily.Ipv6
697+
? NetworkEndpoint.AnyIpv6.WithPort(ConnectionData.ClientBindPort)
698+
: NetworkEndpoint.AnyIpv4.WithPort(ConnectionData.ClientBindPort);
699+
if (m_Driver.Bind(bindEndpoint) != 0)
700+
{
701+
Debug.LogError($"Couldn't create socket. Possibly another process is using port {ConnectionData.ClientBindPort}.");
702+
return false;
703+
}
704+
}
705+
686706
Connect(serverEndpoint);
687707

688708
return true;
@@ -788,16 +808,17 @@ public void SetClientRelayData(string ipAddress, ushort port, byte[] allocationI
788808
/// <summary>
789809
/// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/>
790810
/// </summary>
791-
/// <param name="ipv4Address">The remote IP address (despite the name, can be an IPv6 address or a domain name)</param>
792-
/// <param name="port">The remote port</param>
793-
/// <param name="listenAddress">The local listen address</param>
811+
/// <param name="ipv4Address">The remote IP address (despite the name, can be an IPv6 address or a domain name).</param>
812+
/// <param name="port">The remote port to connect to.</param>
813+
/// <param name="listenAddress">The address the server is going to listen on.</param>
794814
public void SetConnectionData(string ipv4Address, ushort port, string listenAddress = null)
795815
{
796816
ConnectionData = new ConnectionAddressData
797817
{
798818
Address = ipv4Address,
799819
Port = port,
800-
ServerListenAddress = listenAddress ?? ipv4Address
820+
ServerListenAddress = listenAddress ?? ipv4Address,
821+
ClientBindPort = ConnectionData.ClientBindPort
801822
};
802823

803824
SetProtocol(ProtocolType.UnityTransport);
@@ -806,8 +827,8 @@ public void SetConnectionData(string ipv4Address, ushort port, string listenAddr
806827
/// <summary>
807828
/// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/>
808829
/// </summary>
809-
/// <param name="endPoint">The remote end point</param>
810-
/// <param name="listenEndPoint">The local listen endpoint</param>
830+
/// <param name="endPoint">The remote endpoint the client should connect to.</param>
831+
/// <param name="listenEndPoint">The endpoint the server should listen on.</param>
811832
public void SetConnectionData(NetworkEndpoint endPoint, NetworkEndpoint listenEndPoint = default)
812833
{
813834
string serverAddress = endPoint.Address.Split(':')[0];

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,20 @@ public void UnityTransport_EmptySecurityStringsShouldThrow([Values("", null)] st
184184
}
185185
}
186186

187+
[Test]
188+
public void UnityTransport_BindClientToSpecificPort()
189+
{
190+
UnityTransport transport = new GameObject().AddComponent<UnityTransport>();
191+
transport.Initialize();
192+
transport.SetConnectionData("127.0.0.1", 4242);
193+
transport.ConnectionData.ClientBindPort = 14242;
194+
195+
Assert.True(transport.StartClient());
196+
Assert.AreEqual(14242, transport.GetLocalEndpoint().Port);
197+
198+
transport.Shutdown();
199+
}
200+
187201
#if HOSTNAME_RESOLUTION_AVAILABLE
188202
private static readonly (string, bool)[] k_HostnameChecks =
189203
{

com.unity.netcode.gameobjects/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "com.unity.netcode.gameobjects",
33
"displayName": "Netcode for GameObjects",
44
"description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.",
5-
"version": "2.7.1",
5+
"version": "2.8.0",
66
"unity": "6000.0",
77
"dependencies": {
88
"com.unity.nuget.mono-cecil": "1.11.4",

0 commit comments

Comments
 (0)