From c8a6ae930e69241c55bc162af3c50d6c244b3483 Mon Sep 17 00:00:00 2001 From: Noble Whale Date: Wed, 11 Oct 2023 07:32:41 -0400 Subject: [PATCH] Exposed local endpoint on IgnoranceClient. Also added the ability to specify the local endpoint if desired. This is useful for Noble Connect specifically, but also anyone else doing anything like port-forwarding, nat traversal, or relays. --- .../Ignorance/Core/IgnoranceClient.cs | 56 ++++++++++++++++++- .../Mirror/Transports/Ignorance/Ignorance.cs | 13 +++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Assets/Mirror/Transports/Ignorance/Core/IgnoranceClient.cs b/Assets/Mirror/Transports/Ignorance/Core/IgnoranceClient.cs index 1a04989..ae0a511 100644 --- a/Assets/Mirror/Transports/Ignorance/Core/IgnoranceClient.cs +++ b/Assets/Mirror/Transports/Ignorance/Core/IgnoranceClient.cs @@ -36,6 +36,29 @@ public class IgnoranceClient public int ConnectionEventBufferSize = 100; // Client connection address public string ConnectAddress = "127.0.0.1"; + // The local end-point that the client connects from + public bool BindToRandomLocalEndPoint = true; + private string UnsafeBindAddress = "127.0.0.1"; + public string BindAddress { + get { + lock (BindAddressLock) return UnsafeBindAddress; + } + set { + lock (BindAddressLock) UnsafeBindAddress = value; + } + } + private ushort UnsafeBindPort = 0; + public ushort BindPort + { + get + { + lock (BindPortLock) return UnsafeBindPort; + } + set + { + lock (BindPortLock) UnsafeBindPort = value; + } + } // Queues public RingBuffer Incoming; @@ -49,6 +72,9 @@ public class IgnoranceClient private volatile bool CeaseOperation = false; private Thread WorkerThread; + private object BindAddressLock = new object(); + private object BindPortLock = new object(); + public void Start() { if (WorkerThread != null && WorkerThread.IsAlive) @@ -70,7 +96,10 @@ public void Start() MaxNativeTimeout = MaxClientNativeTimeout > 0 ? MaxClientNativeTimeout : 0, PollTime = PollTime, PacketSizeLimit = MaximumPacketSize, - Verbosity = Verbosity + Verbosity = Verbosity, + BindToRandomLocalEndPoint = BindToRandomLocalEndPoint, + BindAddress = UnsafeBindAddress, + BindPort = UnsafeBindPort }; // Drain queues. @@ -139,13 +168,31 @@ private void ThreadWorker(Object parameters) { try { - clientHost.Create(); + if (BindToRandomLocalEndPoint) + { + clientHost.Create(); + } + else + { + Address explicitBindAddress = new Address(); + explicitBindAddress.SetHost(setupInfo.BindAddress); + explicitBindAddress.Port = (ushort)setupInfo.BindPort; + clientHost.Create(explicitBindAddress, 1); + } Debug.Log($"Ignorance: Client worker thread attempting connection to '{setupInfo.Address}:{setupInfo.Port}'."); clientPeer = clientHost.Connect(clientAddress, setupInfo.Channels); + if (setupInfo.BindToRandomLocalEndPoint) + { + // Store the local endpoint, useful for implementing port-forwarding, nat traversal, ice, turn, stun, etc. + // This is thread safe since the properties lock + BindAddress = clientPeer.IP; + BindPort = clientPeer.Port; + } + // Apply the custom native timeout if needed. - if(setupInfo.MaxNativeTimeout > 0) + if (setupInfo.MaxNativeTimeout > 0) { clientPeer.Timeout(Library.timeoutLimit, Library.timeoutMinimum, (uint)MaxClientNativeTimeout * 1000); } @@ -356,6 +403,9 @@ private void SetupRingBuffersIfNull() private struct ThreadParamInfo { + public bool BindToRandomLocalEndPoint; + public string BindAddress; + public int BindPort; public int Channels; public int PollTime; public int MaxNativeTimeout; diff --git a/Assets/Mirror/Transports/Ignorance/Ignorance.cs b/Assets/Mirror/Transports/Ignorance/Ignorance.cs index 0e556cc..3064e7f 100644 --- a/Assets/Mirror/Transports/Ignorance/Ignorance.cs +++ b/Assets/Mirror/Transports/Ignorance/Ignorance.cs @@ -9,6 +9,7 @@ using Mirror; using System; using System.Collections.Generic; +using System.Net; using UnityEngine; namespace IgnoranceTransport @@ -322,6 +323,18 @@ public override Uri ServerUri() return builder.Uri; } + public IPEndPoint GetLocalEndPoint() + { + if (Server != null) + { + return new IPEndPoint(IPAddress.Parse(Server.BindAddress), Server.BindPort); + } + else + { + return new IPEndPoint(IPAddress.Parse(Client.BindAddress), Client.BindPort); + } + } + public override void Shutdown() { // TODO: Nothing needed here?