From: Forest Date: Wed, 19 Dec 2018 21:35:03 +0000 (-0800) Subject: Many of the recent changes are very good, some I'm not so sure about, but unfortunate... X-Git-Tag: 1.0.0~68 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=439af6e44f01a43be07908cfbca05ff98197054f;p=rhonda%2Fimpostor.hazel.git Many of the recent changes are very good, some I'm not so sure about, but unfortunately my optimizations were influenced by an unknown, outside force (AWS was capping my CPU and I didn't know). So now that that problem is fixed, we'll see how much I undo/alter. --- diff --git a/Hazel/Connection.cs b/Hazel/Connection.cs index b328530..2a96dda 100644 --- a/Hazel/Connection.cs +++ b/Hazel/Connection.cs @@ -48,7 +48,7 @@ namespace Hazel /// /// /// - public event EventHandler DataReceived; + public Action DataReceived; public int TestLagMs = -1; @@ -123,20 +123,20 @@ namespace Hazel { get { - return state; + return this.state; } protected set { state = value; - if (state == ConnectionState.Connected) connectWaitLock.Set(); else connectWaitLock.Reset(); } } - volatile ConnectionState state; + + protected ConnectionState state; /// /// Reset event that is triggered when the connection is marked Connected. @@ -246,12 +246,12 @@ namespace Hazel protected void InvokeDataReceived(MessageReader msg, SendOption sendOption, ushort reliableId) { //Make a copy to avoid race condition between null check and invocation - EventHandler handler = DataReceived; + Action handler = DataReceived; if (handler != null) { DataReceivedEventArgs args = DataReceivedEventArgs.GetObject(); args.Set(msg, sendOption, reliableId); - handler.Invoke(this, args); + handler.Invoke(args); } else { diff --git a/Hazel/ConnectionListener.cs b/Hazel/ConnectionListener.cs index 377e49b..3acda8e 100644 --- a/Hazel/ConnectionListener.cs +++ b/Hazel/ConnectionListener.cs @@ -46,7 +46,7 @@ namespace Hazel /// /// /// - public event EventHandler NewConnection; + public Action NewConnection; /// /// Makes this connection listener begin listening for connections. @@ -77,12 +77,12 @@ namespace Hazel protected void InvokeNewConnection(MessageReader msg, Connection connection) { //Make a copy to avoid race condition between null check and invocation - EventHandler handler = NewConnection; + Action handler = NewConnection; if (handler != null) { NewConnectionEventArgs args = NewConnectionEventArgs.GetObject(); args.Set(msg, connection); - handler(this, args); + handler(args); } else { diff --git a/Hazel/Udp/UdpClientConnection.cs b/Hazel/Udp/UdpClientConnection.cs index e987643..21abdb2 100644 --- a/Hazel/Udp/UdpClientConnection.cs +++ b/Hazel/Udp/UdpClientConnection.cs @@ -20,11 +20,6 @@ namespace Hazel.Udp /// Socket socket; - /// - /// Object for locking the state. - /// - Object stateLock = new Object(); - /// /// The buffer to store incomming data in. /// @@ -73,11 +68,8 @@ namespace Hazel.Udp { InvokeDataSentRaw(bytes, length); - lock (stateLock) - { - if (State != ConnectionState.Connected && State != ConnectionState.Connecting) - throw new InvalidOperationException("Could not send data as this Connection is not connected and is not connecting. Did you disconnect?"); - } + if (State != ConnectionState.Connected && State != ConnectionState.Connecting) + throw new InvalidOperationException("Could not send data as this Connection is not connected and is not connecting. Did you disconnect?"); try { @@ -123,41 +115,7 @@ namespace Hazel.Udp HandleDisconnect(he); } } - - /// - protected override void WriteBytesToConnectionSync(byte[] bytes, int length) - { - InvokeDataSentRaw(bytes, length); - - lock (stateLock) - { - if (State != ConnectionState.Connected && State != ConnectionState.Connecting) - throw new InvalidOperationException("Could not send data as this Connection is not connected and is not connecting. Did you disconnect?"); - } - - try - { - socket.SendTo( - bytes, - 0, - length, - SocketFlags.None, - RemoteEndPoint - ); - } - catch (ObjectDisposedException) - { - //User probably called Disconnect in between this method starting and here so report the issue - throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); - } - catch (SocketException e) - { - HazelException he = new HazelException("Could not send data as a SocketException occured.", e); - HandleDisconnect(he); - throw he; - } - } - + /// public override void Connect(byte[] bytes = null, int timeout = 5000) { @@ -177,13 +135,10 @@ namespace Hazel.Udp /// public override void ConnectAsync(byte[] bytes = null, int timeout = 5000) { - lock (stateLock) - { if (State != ConnectionState.NotConnected) throw new InvalidOperationException("Cannot connect as the Connection is already connected."); - State = ConnectionState.Connecting; - } + State = ConnectionState.Connecting; //Begin listening try @@ -207,8 +162,7 @@ namespace Hazel.Udp { //If the socket's been disposed then we can just end there but make sure we're in NotConnected state. //If we end up here I'm really lost... - lock (stateLock) - State = ConnectionState.NotConnected; + State = ConnectionState.NotConnected; return; } catch (SocketException e) @@ -219,7 +173,7 @@ namespace Hazel.Udp //Write bytes to the server to tell it hi (and to punch a hole in our NAT, if present) //When acknowledged set the state to connected - SendHello(bytes, () => { lock (stateLock) State = ConnectionState.Connected; }); + SendHello(bytes, () => { State = ConnectionState.Connected; }); } /// @@ -292,29 +246,18 @@ namespace Hazel.Udp /// protected override void HandleDisconnect(HazelException e = null) { - bool invoke = false; - - lock (stateLock) + if (State == ConnectionState.Connected) { - //Only invoke the disconnected event if we're not already disconnecting - if (State == ConnectionState.Connected) - { - State = ConnectionState.Disconnecting; - invoke = true; - } - } + State = ConnectionState.Disconnecting; - //Invoke event outide lock if need be - if (invoke) - { try { InvokeDisconnected(e); } catch { } - - Dispose(); } + + Dispose(); } /// @@ -323,16 +266,15 @@ namespace Hazel.Udp if (disposing) { //Send disconnect message if we're not already disconnecting - bool connected; - lock (stateLock) - connected = State == ConnectionState.Connected; - - if (connected) - SendDisconnect(); - - //Dispose of the socket - lock (stateLock) + if (State == ConnectionState.Connected) + { State = ConnectionState.NotConnected; + try + { + SendDisconnect(); + } + catch { } + } } if (socket != null) diff --git a/Hazel/Udp/UdpConnection.KeepAlive.cs b/Hazel/Udp/UdpConnection.KeepAlive.cs index 57beecb..b3353fa 100644 --- a/Hazel/Udp/UdpConnection.KeepAlive.cs +++ b/Hazel/Udp/UdpConnection.KeepAlive.cs @@ -62,7 +62,7 @@ namespace Hazel.Udp { try { - ReliableSend((byte)UdpSendOption.Hello); // TODO: Change to ping after server can handle it, before clients update + ReliableSend((byte)UdpSendOption.Ping); Trace.WriteLine("Keepalive packet sent."); } catch diff --git a/Hazel/Udp/UdpConnection.Reliable.cs b/Hazel/Udp/UdpConnection.Reliable.cs index 39619ab..fcc5497 100644 --- a/Hazel/Udp/UdpConnection.Reliable.cs +++ b/Hazel/Udp/UdpConnection.Reliable.cs @@ -149,16 +149,8 @@ namespace Hazel.Udp PacketPool.PutObject(this); } } - - private Timer reliableTimer; - private int activePackets; - - private void InitializeReliableTimer() - { - reliableTimer = new Timer(ManageReliablePackets, null, 100, 100); - } - - private void ManageReliablePackets(object state) + + internal void ManageReliablePackets(object state) { if (this.reliableDataPacketsSent.Count > 0) { @@ -195,11 +187,12 @@ namespace Hazel.Udp //Create packet object Packet packet = Packet.GetObject(); - do + id = (ushort)Interlocked.Increment(ref lastIDAllocated); + + if (!reliableDataPacketsSent.TryAdd(id, packet)) { - id = (ushort)Interlocked.Increment(ref lastIDAllocated); + throw new Exception("That shouldn't be possible"); } - while (!reliableDataPacketsSent.TryAdd(id, packet)); int timeout = resendTimeout > 0 ? resendTimeout : (int)Math.Max(50, Math.Min(AveragePingMs * 2, 1000)); @@ -222,7 +215,6 @@ namespace Hazel.Udp { if (reliableDataPacketsSent.TryRemove(p.Id, out self)) { - Interlocked.Decrement(ref this.activePackets); HandleDisconnect(new HazelException($"Reliable packet {self.Id} was not ack'd after {self.Retransmissions} resends")); self.Recycle(); @@ -421,7 +413,6 @@ namespace Hazel.Udp Packet packet; if (reliableDataPacketsSent.TryRemove(id, out packet)) { - Interlocked.Decrement(ref this.activePackets); float rt = packet.Stopwatch.ElapsedMilliseconds; packet.AckCallback?.Invoke(); @@ -461,8 +452,6 @@ namespace Hazel.Udp void DisposeReliablePackets() { - this.reliableTimer.Dispose(); - foreach (var kvp in reliableDataPacketsSent) { Packet pkt; diff --git a/Hazel/Udp/UdpConnection.cs b/Hazel/Udp/UdpConnection.cs index ca6a986..ee05df1 100644 --- a/Hazel/Udp/UdpConnection.cs +++ b/Hazel/Udp/UdpConnection.cs @@ -21,7 +21,6 @@ namespace Hazel.Udp protected UdpConnection() { InitializeKeepAliveTimer(); - InitializeReliableTimer(); } /// @@ -29,13 +28,7 @@ namespace Hazel.Udp /// /// The bytes to write. protected abstract void WriteBytesToConnection(byte[] bytes, int length); - - /// - /// Writes the given bytes to the connection synchronously. - /// - /// The bytes to write. - protected abstract void WriteBytesToConnectionSync(byte[] bytes, int length); - + /// public override void Send(MessageWriter msg) { @@ -267,7 +260,7 @@ namespace Hazel.Udp /// public override void SendDisconnect() { - WriteBytesToConnectionSync(new byte[] { (byte)UdpSendOption.Disconnect }, 1); + WriteBytesToConnection(new byte[] { (byte)UdpSendOption.Disconnect }, 1); } /// diff --git a/Hazel/Udp/UdpConnectionListener.cs b/Hazel/Udp/UdpConnectionListener.cs index b4d6261..a951f2a 100644 --- a/Hazel/Udp/UdpConnectionListener.cs +++ b/Hazel/Udp/UdpConnectionListener.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; @@ -29,6 +30,8 @@ namespace Hazel.Udp private Action Logger; + Timer reliablePacketTimer; + /// /// The connections we currently hold /// @@ -56,6 +59,8 @@ namespace Hazel.Udp this.listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); this.listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); } + + reliablePacketTimer = new Timer(ManageReliablePackets, null, 100, Timeout.Infinite); } ~UdpConnectionListener() @@ -63,6 +68,21 @@ namespace Hazel.Udp this.Dispose(false); } + public float AveragePacketsTime = 1; + Stopwatch stopwatch = new Stopwatch(); + private void ManageReliablePackets(object state) + { + stopwatch.Restart(); + foreach (var kvp in this.allConnections) + { + kvp.Value.ManageReliablePackets(state); + } + + this.AveragePacketsTime = this.AveragePacketsTime * .7f + stopwatch.ElapsedMilliseconds * .3f; + + this.reliablePacketTimer.Change(100, Timeout.Infinite); + } + /// public override void Start() { @@ -111,7 +131,7 @@ namespace Hazel.Udp /// Called when data has been received by the listener. /// /// The asyncronous operation's result. - + public int ActiveListeners; public int ActiveCallbacks; void ReadCallback(IAsyncResult result) @@ -149,6 +169,13 @@ namespace Hazel.Udp // This thread suggests the IP is not passed out from WinSoc so maybe not possible // http://stackoverflow.com/questions/2576926/python-socket-error-on-udp-data-receive-10054 message.Recycle(); + + UdpServerConnection dead; + if (this.allConnections.TryRemove(remoteEndPoint, out dead)) + { + dead.Dispose(); + } + StartListeningForData(); return; } @@ -309,14 +336,9 @@ namespace Hazel.Udp /// protected override void Dispose(bool disposing) { - var keys = this.allConnections.Keys.ToArray(); - foreach (var k in keys) + foreach (var kvp in this.allConnections) { - UdpServerConnection conn; - if (this.allConnections.TryGetValue(k, out conn)) - { - conn.Dispose(); - } + kvp.Value.Dispose(); } if (listener != null) @@ -326,6 +348,8 @@ namespace Hazel.Udp this.listener = null; } + this.reliablePacketTimer.Dispose(); + base.Dispose(disposing); } } diff --git a/Hazel/Udp/UdpServerConnection.cs b/Hazel/Udp/UdpServerConnection.cs index 2bf3435..99b9bc8 100644 --- a/Hazel/Udp/UdpServerConnection.cs +++ b/Hazel/Udp/UdpServerConnection.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; - +using System.Threading; namespace Hazel.Udp { @@ -58,20 +58,6 @@ namespace Hazel.Udp Listener.SendData(bytes, length, RemoteEndPoint); } - /// - protected override void WriteBytesToConnectionSync(byte[] bytes, int length) - { - InvokeDataSentRaw(bytes, length); - - lock (stateLock) - { - if (State != ConnectionState.Connected) - throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); - } - - Listener.SendDataSync(bytes, length, RemoteEndPoint); - } - /// /// /// This will always throw a HazelException. @@ -124,19 +110,19 @@ namespace Hazel.Udp //Here we just need to inform the listener we no longer need data. if (disposing) { - //Send disconnect message if we're not already disconnecting - bool connected; - - lock (stateLock) - connected = State == ConnectionState.Connected; + // Send disconnect message if we're not already disconnecting + if (this.state == ConnectionState.Connected) + { + try + { + SendDisconnect(); + } + catch { } + this.state = ConnectionState.Disconnecting; + } - if (connected) - SendDisconnect(); - Listener.RemoveConnectionTo(RemoteEndPoint); - lock (stateLock) - State = ConnectionState.NotConnected; } base.Dispose(disposing);