]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Many of the recent changes are very good, some I'm not so sure about, but unfortunate...
authorForest <chocozilla@gmail.com>
Wed, 19 Dec 2018 21:35:03 +0000 (13:35 -0800)
committerForest <chocozilla@gmail.com>
Wed, 19 Dec 2018 21:35:03 +0000 (13:35 -0800)
Hazel/Connection.cs
Hazel/ConnectionListener.cs
Hazel/Udp/UdpClientConnection.cs
Hazel/Udp/UdpConnection.KeepAlive.cs
Hazel/Udp/UdpConnection.Reliable.cs
Hazel/Udp/UdpConnection.cs
Hazel/Udp/UdpConnectionListener.cs
Hazel/Udp/UdpServerConnection.cs

index b328530bb9c2747b08842216be1a28c2bc8f8649..2a96ddaf5d66fcddefb1cfb998f0c783540de5e0 100644 (file)
@@ -48,7 +48,7 @@ namespace Hazel
         /// <example>
         ///     <code language="C#" source="DocInclude/TcpClientExample.cs"/>
         /// </example>
-        public event EventHandler<DataReceivedEventArgs> DataReceived;
+        public Action<DataReceivedEventArgs> 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;
 
         /// <summary>
         ///     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<DataReceivedEventArgs> handler = DataReceived;
+            Action<DataReceivedEventArgs> handler = DataReceived;
             if (handler != null)
             {
                 DataReceivedEventArgs args = DataReceivedEventArgs.GetObject();
                 args.Set(msg, sendOption, reliableId);
-                handler.Invoke(this, args);
+                handler.Invoke(args);
             }
             else
             {
index 377e49b6583ca69ec7666463494e8286f9b8077b..3acda8ec0559a6fc8a399aaaf2b2a4854edc6b4c 100644 (file)
@@ -46,7 +46,7 @@ namespace Hazel
         /// <example>
         ///     <code language="C#" source="DocInclude/TcpListenerExample.cs"/>
         /// </example>
-        public event EventHandler<NewConnectionEventArgs> NewConnection;
+        public Action<NewConnectionEventArgs> NewConnection;
 
         /// <summary>
         ///     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<NewConnectionEventArgs> handler = NewConnection;
+            Action<NewConnectionEventArgs> handler = NewConnection;
             if (handler != null)
             {
                 NewConnectionEventArgs args = NewConnectionEventArgs.GetObject();
                 args.Set(msg, connection);
-                handler(this, args);
+                handler(args);
             }
             else
             {
index e987643521ccaef06a4c27f861910a63863a77a0..21abdb29085c439ed1c4984e1036511ae27d1630 100644 (file)
@@ -20,11 +20,6 @@ namespace Hazel.Udp
         /// </summary>
         Socket socket;
 
-        /// <summary>
-        ///     Object for locking the state.
-        /// </summary>
-        Object stateLock = new Object();
-
         /// <summary>
         ///     The buffer to store incomming data in.
         /// </summary>
@@ -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);
             }
         }
-
-        /// <inheritdoc />
-        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;
-            }
-        }
-
+        
         /// <inheritdoc />
         public override void Connect(byte[] bytes = null, int timeout = 5000)
         {
@@ -177,13 +135,10 @@ namespace Hazel.Udp
         /// <inheritdoc />
         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; });
         }
 
         /// <summary>
@@ -292,29 +246,18 @@ namespace Hazel.Udp
         /// <inheritdoc />
         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();
         }
 
         /// <inheritdoc />
@@ -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)
index 57beecb1b341c85f1fd44fe399b575d72f4d4534..b3353fac0eb88f32a753c07972f0c4660b966088 100644 (file)
@@ -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
index 39619ab9e1fe0b8b28fcd701161b4a29d9dfb989..fcc5497ae505a004f2f699a9735179164e10ea3c 100644 (file)
@@ -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;
index ca6a9865b85780a925f2934e14eecdb214653ec7..ee05df15ea192570f8ebb73e97d9fe356188e722 100644 (file)
@@ -21,7 +21,6 @@ namespace Hazel.Udp
         protected UdpConnection()
         {
             InitializeKeepAliveTimer();
-            InitializeReliableTimer();
         }
 
         /// <summary>
@@ -29,13 +28,7 @@ namespace Hazel.Udp
         /// </summary>
         /// <param name="bytes">The bytes to write.</param>
         protected abstract void WriteBytesToConnection(byte[] bytes, int length);
-
-        /// <summary>
-        ///     Writes the given bytes to the connection synchronously.
-        /// </summary>
-        /// <param name="bytes">The bytes to write.</param>
-        protected abstract void WriteBytesToConnectionSync(byte[] bytes, int length);
-
+        
         /// <inheritdoc/>
         public override void Send(MessageWriter msg)
         {
@@ -267,7 +260,7 @@ namespace Hazel.Udp
         /// </summary>
         public override void SendDisconnect()
         {
-            WriteBytesToConnectionSync(new byte[] { (byte)UdpSendOption.Disconnect }, 1);
+            WriteBytesToConnection(new byte[] { (byte)UdpSendOption.Disconnect }, 1);
         }
 
         /// <inheritdoc/>
index b4d62614f372303b8a9670fded0dd36e3145db16..a951f2a9dba55e54da8b068dc7b91d4a0a05dcfa 100644 (file)
@@ -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<string> Logger;
 
+        Timer reliablePacketTimer;
+
         /// <summary>
         ///     The connections we currently hold
         /// </summary>
@@ -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);
+        }
+
         /// <inheritdoc />
         public override void Start()
         {
@@ -111,7 +131,7 @@ namespace Hazel.Udp
         ///     Called when data has been received by the listener.
         /// </summary>
         /// <param name="result">The asyncronous operation's result.</param>
-
+        
         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
         /// <inheritdoc />
         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);
         }
     }
index 2bf343569279230773b61e08f33ff4550214181b..99b9bc8380141d980292b1d3b2525f0d9609db1b 100644 (file)
@@ -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);
         }
 
-        /// <inheritdoc />
-        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);
-        }
-
         /// <inheritdoc />
         /// <remarks>
         ///     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);