From a8b72ec7a989aee3fd360c71b9f63b6111709452 Mon Sep 17 00:00:00 2001 From: Forest Date: Wed, 29 Apr 2020 15:46:21 -0700 Subject: [PATCH] Fix a severe issue with redundant acks Fix a potential issue in ObjectPool on Unity IL2CPP Improve naming of thread limited classes. --- ... => ThreadLimitedUdpConnectionListener.cs} | 29 +++++++------ ...cs => ThreadLimitedUdpServerConnection.cs} | 8 ++-- Hazel/Hazel.csproj | 8 ++-- Hazel/ObjectPool.cs | 31 +++++++++++++- Hazel/Udp/UdpConnection.KeepAlive.cs | 42 ++++++++++--------- Hazel/Udp/UdpConnection.Reliable.cs | 39 +++++++++-------- Hazel/Udp/UdpConnectionListener.cs | 6 +-- Hazel/Udp/UnityUdpClientConnection.cs | 9 +++- 8 files changed, 107 insertions(+), 65 deletions(-) rename Hazel/FewerThreads/{UdpConnectionListener2.cs => ThreadLimitedUdpConnectionListener.cs} (89%) rename Hazel/FewerThreads/{UdpServerConnection2.cs => ThreadLimitedUdpServerConnection.cs} (89%) diff --git a/Hazel/FewerThreads/UdpConnectionListener2.cs b/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs similarity index 89% rename from Hazel/FewerThreads/UdpConnectionListener2.cs rename to Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs index d4e8876..df5e000 100644 --- a/Hazel/FewerThreads/UdpConnectionListener2.cs +++ b/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs @@ -11,7 +11,7 @@ namespace Hazel.Udp.FewerThreads /// Listens for new UDP connections and creates UdpConnections for them. /// /// - public class UdpConnectionListener2 : IDisposable + public class ThreadLimitedUdpConnectionListener : IDisposable { private struct SendMessageInfo { @@ -49,7 +49,7 @@ namespace Hazel.Udp.FewerThreads private Thread sendThread; private HazelThreadPool processThreads; - private ConcurrentDictionary allConnections = new ConcurrentDictionary(); + private ConcurrentDictionary allConnections = new ConcurrentDictionary(); private Queue receiveQueue = new Queue(); private Queue sendQueue = new Queue(); @@ -60,7 +60,7 @@ namespace Hazel.Udp.FewerThreads private bool isActive; - public UdpConnectionListener2(IPEndPoint endPoint, ILogger logger, IPMode ipMode = IPMode.IPv4) + public ThreadLimitedUdpConnectionListener(int numWorkers, IPEndPoint endPoint, ILogger logger, IPMode ipMode = IPMode.IPv4) { this.Logger = logger; this.EndPoint = endPoint; @@ -75,10 +75,10 @@ namespace Hazel.Udp.FewerThreads this.reliablePacketThread = new Thread(ManageReliablePackets); this.sendThread = new Thread(SendLoop); this.receiveThread = new Thread(ReceiveLoop); - this.processThreads = new HazelThreadPool(4, ProcessingLoop); + this.processThreads = new HazelThreadPool(numWorkers, ProcessingLoop); } - ~UdpConnectionListener2() + ~ThreadLimitedUdpConnectionListener() { this.Dispose(false); } @@ -121,7 +121,7 @@ namespace Hazel.Udp.FewerThreads { if (this.socket.Poll(Timeout.Infinite, SelectMode.SelectRead)) { - EndPoint remoteEP = new IPEndPoint(IPMode == IPMode.IPv4 ? IPAddress.Any : IPAddress.IPv6Any, this.EndPoint.Port); + EndPoint remoteEP = new IPEndPoint(this.EndPoint.Address, this.EndPoint.Port); MessageReader message = MessageReader.GetSized(BufferSize); try { @@ -215,7 +215,7 @@ namespace Hazel.Udp.FewerThreads // If we're aware of this connection use the one already // If this is a new client then connect with them! - UdpServerConnection2 connection; + ThreadLimitedUdpServerConnection connection; if (!this.allConnections.TryGetValue(remoteEndPoint, out connection)) { lock (this.allConnections) @@ -244,7 +244,7 @@ namespace Hazel.Udp.FewerThreads } aware = false; - connection = new UdpServerConnection2(this, (IPEndPoint)remoteEndPoint, this.IPMode); + connection = new ThreadLimitedUdpServerConnection(this, (IPEndPoint)remoteEndPoint, this.IPMode); if (!this.allConnections.TryAdd(remoteEndPoint, connection)) { throw new HazelException("Failed to add a connection. This should never happen."); @@ -253,10 +253,9 @@ namespace Hazel.Udp.FewerThreads } } - //Inform the connection of the buffer (new connections need to send an ack back to client) - connection.HandleReceive(message, bytesReceived); - - //If it's a new connection invoke the NewConnection event. + // If it's a new connection invoke the NewConnection event. + // This needs to happen before handling the message because in localhost scenarios, the ACK and + // subsequent messages can happen before the NewConnection event sets up OnDataRecieved handlers if (!aware) { // Skip header and hello byte; @@ -265,7 +264,11 @@ namespace Hazel.Udp.FewerThreads message.Position = 0; this.NewConnection?.Invoke(new NewConnectionEventArgs(message, connection)); } - else if (isHello) + + // Inform the connection of the buffer (new connections need to send an ack back to client) + connection.HandleReceive(message, bytesReceived); + + if (isHello) { message.Recycle(); } diff --git a/Hazel/FewerThreads/UdpServerConnection2.cs b/Hazel/FewerThreads/ThreadLimitedUdpServerConnection.cs similarity index 89% rename from Hazel/FewerThreads/UdpServerConnection2.cs rename to Hazel/FewerThreads/ThreadLimitedUdpServerConnection.cs index c5e6795..ee5d2cd 100644 --- a/Hazel/FewerThreads/UdpServerConnection2.cs +++ b/Hazel/FewerThreads/ThreadLimitedUdpServerConnection.cs @@ -4,10 +4,10 @@ using System.Net; namespace Hazel.Udp.FewerThreads { /// - /// Represents a servers's connection to a client that uses the UDP protocol. + /// Represents a servers's connection to a client that uses the UDP protocol. /// /// - internal sealed class UdpServerConnection2 : UdpConnection + internal sealed class ThreadLimitedUdpServerConnection : UdpConnection { /// /// The connection listener that we use the socket of. @@ -16,7 +16,7 @@ namespace Hazel.Udp.FewerThreads /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that /// created this connection and is hence the listener this conenction sends and receives via. /// - public UdpConnectionListener2 Listener { get; private set; } + public ThreadLimitedUdpConnectionListener Listener { get; private set; } /// /// Creates a UdpConnection for the virtual connection to the endpoint. @@ -24,7 +24,7 @@ namespace Hazel.Udp.FewerThreads /// The listener that created this connection. /// The endpoint that we are connected to. /// The IPMode we are connected using. - internal UdpServerConnection2(UdpConnectionListener2 listener, IPEndPoint endPoint, IPMode IPMode) + internal ThreadLimitedUdpServerConnection(ThreadLimitedUdpConnectionListener listener, IPEndPoint endPoint, IPMode IPMode) : base() { this.Listener = listener; diff --git a/Hazel/Hazel.csproj b/Hazel/Hazel.csproj index e249199..f6b10e6 100644 --- a/Hazel/Hazel.csproj +++ b/Hazel/Hazel.csproj @@ -28,7 +28,7 @@ 7.3 - pdbonly + portable true bin\Release\ TRACE @@ -39,6 +39,7 @@ true false 7.3 + true true @@ -73,8 +74,8 @@ - - + + @@ -103,7 +104,6 @@ -