]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Added remote disconnections
authorJamJar00 <jamster.30@btinternet.com>
Sat, 14 May 2016 18:48:35 +0000 (19:48 +0100)
committerJamJar00 <jamster.30@btinternet.com>
Sat, 14 May 2016 18:48:35 +0000 (19:48 +0100)
12 files changed:
Hazel.UnitTests/TcpConnectionTests.cs
Hazel.UnitTests/TestHelper.cs
Hazel.UnitTests/UdpConnectionTests.cs
Hazel/Connection.cs
Hazel/HazelException.cs
Hazel/SendOptionInternal.cs
Hazel/TcpConnection.cs
Hazel/UdpClientConnection.cs
Hazel/UdpConnection.KeepAlive.cs
Hazel/UdpConnection.cs
Hazel/UdpConnectionListener.cs
Hazel/UdpServerConnection.cs

index 290eeae64a71a4d10b20c40bb87d4654f6c6de57..e30ef29277159f47e0aa8d95a1be741730955598 100644 (file)
@@ -1,6 +1,7 @@
 using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.Net;
+using System.Threading;
 
 namespace Hazel.UnitTests
 {
@@ -56,5 +57,31 @@ namespace Hazel.UnitTests
                 TestHelper.RunClientToServerTest(listener, connection, 4, 0, SendOption.OrderedFragmentedReliable);
             }
         }
+
+        /// <summary>
+        ///     Tests disconnection from the client.
+        /// </summary>
+        [TestMethod]
+        public void ClientDisconnectTest()
+        {
+            using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
+            using (TcpConnection connection = new TcpConnection())
+            {
+                TestHelper.RunClientDisconnectTest(listener, connection);
+            }
+        }
+
+        /// <summary>
+        ///     Tests disconnection from the server.
+        /// </summary>
+        [TestMethod]
+        public void ServerDisconnectTest()
+        {
+            using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
+            using (TcpConnection connection = new TcpConnection())
+            {
+                TestHelper.RunServerDisconnectTest(listener, connection);
+            }
+        }
     }
 }
index 02cc11337a81d2230e29e7a20837734b90f6b7aa..5708a49a96dd06dcdea413c373406849b412fd18 100644 (file)
@@ -110,5 +110,57 @@ namespace Hazel.UnitTests
             Assert.AreEqual(totalHandshakeSize + data.Length + headerSize, connection.Statistics.TotalBytesSent);
             Assert.AreEqual(0, connection.Statistics.TotalBytesReceived);
         }
+
+        /// <summary>
+        ///     Runs a server disconnect test on the given listener and connection.
+        /// </summary>
+        /// <param name="listener">The listener to test.</param>
+        /// <param name="connection">The connection to test.</param>
+        internal static void RunServerDisconnectTest(ConnectionListener listener, Connection connection)
+        {
+            ManualResetEvent mutex = new ManualResetEvent(false);
+
+            connection.Disconnected += delegate(object sender, DisconnectedEventArgs args)
+            {
+                mutex.Set();
+            };
+
+            listener.NewConnection += delegate(object sender, NewConnectionEventArgs args)
+            {
+                args.Connection.Close();
+            };
+
+            listener.Start();
+
+            connection.Connect(new NetworkEndPoint(IPAddress.Loopback, 4296));
+
+            mutex.WaitOne();
+        }
+
+        /// <summary>
+        ///     Runs a client disconnect test on the given listener and connection.
+        /// </summary>
+        /// <param name="listener">The listener to test.</param>
+        /// <param name="connection">The connection to test.</param>
+        internal static void RunClientDisconnectTest(ConnectionListener listener, Connection connection)
+        {
+            ManualResetEvent mutex = new ManualResetEvent(false);
+
+            listener.NewConnection += delegate(object sender, NewConnectionEventArgs args)
+            {
+                args.Connection.Disconnected += delegate(object sender2, DisconnectedEventArgs args2)
+                {
+                    mutex.Set();
+                };
+            };
+
+            listener.Start();
+
+            connection.Connect(new NetworkEndPoint(IPAddress.Loopback, 4296));
+
+            connection.Close();
+
+            mutex.WaitOne();
+        }
     }
 }
index e2abd18bd4de8e0da7a6bf03799bf98b7d1b4856..a6ce448a9a56f4954e69f8e399e432d4d5e3dedc 100644 (file)
@@ -132,5 +132,31 @@ namespace Hazel.UnitTests
                 mutex.WaitOne();
             }
         }
+
+        /// <summary>
+        ///     Tests disconnection from the client.
+        /// </summary>
+        [TestMethod]
+        public void ClientDisconnectTest()
+        {
+            using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
+            using (UdpConnection connection = new UdpClientConnection())
+            {
+                TestHelper.RunClientDisconnectTest(listener, connection);
+            }
+        }
+
+        /// <summary>
+        ///     Tests disconnection from the server.
+        /// </summary>
+        [TestMethod]
+        public void ServerDisconnectTest()
+        {
+            using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
+            using (UdpConnection connection = new UdpClientConnection())
+            {
+                TestHelper.RunServerDisconnectTest(listener, connection);
+            }
+        }
     }
 }
index 4c7c5ed27b98a8adf27b7ca4f32411a56a7efdbc..72cd2457527fdcaaf4ccc23c665e93f8d8faad88 100644 (file)
@@ -130,7 +130,7 @@ namespace Hazel
         /// <summary>
         ///     Closes this connection safely.
         /// </summary>
-        public void Close()
+        public virtual void Close()
         {
             Dispose();
         }
index 86f157b1d163a920c48bbaf7a81282ab555b0a44..f04a4b0b986c0dc3a9e232b098b930e00828ae06 100644 (file)
@@ -8,7 +8,8 @@ namespace Hazel
     /// <summary>
     ///     Wrapper for exceptions thrown from Hazel.
     /// </summary>
-    class HazelException : Exception
+    [Serializable]
+    public class HazelException : Exception
     {
         internal HazelException(string msg) : base (msg)
         {
index 5e4f6210f89d7cbe9f675a83f61e77e3b78310c4..16624f1ab439257e9024a44618487dd054604a2e 100644 (file)
@@ -14,7 +14,12 @@ namespace Hazel
         /// <summary>
         ///     Hello message for initiating communication.
         /// </summary>
-        Hello = 254,
+        Hello = 253,
+
+        /// <summary>
+        ///     Message for discontinuing communication.
+        /// </summary>
+        Disconnect = 254,
 
         /// <summary>
         ///     Message acknowledging the receipt of a message.
index f39514b1aa0ca5257b45c833f42255582ed2b848..04e8598077b739215ea59747ec2cf73e7256384b 100644 (file)
@@ -47,9 +47,9 @@ namespace Hazel
             lock (this.Socket)
             {
                 this.Socket.NoDelay = true;
-            }
 
-            State = ConnectionState.Connected;
+                State = ConnectionState.Connected;
+            }
         }
 
         /// <summary>
@@ -223,7 +223,13 @@ namespace Hazel
         protected virtual void StartWaitingForChunk(StateObject state)
         {
             lock (Socket)
-                Socket.BeginReceive(state.buffer, state.totalBytesReceived, state.buffer.Length, SocketFlags.None, ChunkReadCallback, state);
+            {
+                //Double check we've not disconnected then begin receiving
+                if (State == ConnectionState.Connected || State == ConnectionState.Connecting)
+                    Socket.BeginReceive(state.buffer, state.totalBytesReceived, state.buffer.Length, SocketFlags.None, ChunkReadCallback, state);
+                else
+                    HandleDisconnect();
+            }
         }
 
         /// <summary>
index 000e8038df6f331b68c4a0d32badf2c561e6917c..5194cc50d9a27705c33ea4c738dc1fb9ca18af87 100644 (file)
@@ -116,7 +116,10 @@ namespace Hazel
                 }
                 catch (ObjectDisposedException)
                 {
-                    throw new HazelException("Could not begin read as the socket has been disposed of, did you disconnect?");
+                    //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...
+                    State = ConnectionState.NotConnected;
+                    return;
                 }
                 catch (SocketException e)
                 {
@@ -190,7 +193,8 @@ namespace Hazel
             }
             catch (ObjectDisposedException)
             {
-                throw new HazelException("Could not begin read as the socket has been disposed of.");
+                //If the socket's been disposed then we can just end there.
+                return;
             }
             
             if (buffer != null)
@@ -201,7 +205,7 @@ namespace Hazel
         ///     Called when the socket has been disconnected at the remote host.
         /// </summary>
         /// <param name="e">The exception if one was the cause.</param>
-        void HandleDisconnect(HazelException e = null)
+        protected override void HandleDisconnect(HazelException e = null)
         {
             bool invoke = false;
 
index 153187423dc0678effb0c2e1b137ea722aed7618..ee1b90a698e9be3c484719ef4e1051963ae21fd0 100644 (file)
@@ -46,6 +46,11 @@ namespace Hazel
         /// </summary>
         Object keepAliveTimerLock = new Object();
 
+        /// <summary>
+        ///     Has the keep alive timer been disposed already?
+        /// </summary>
+        bool keepAliveTimerDisposed;
+
         /// <summary>
         ///     Starts the keepalive timer.
         /// </summary>
@@ -81,7 +86,11 @@ namespace Hazel
         void DisposeKeepAliveTimer()
         {
             lock(keepAliveTimerLock)
-                keepAliveTimer.Dispose();
+            {
+                if (!keepAliveTimerDisposed)
+                    keepAliveTimer.Dispose();
+                keepAliveTimerDisposed = true;
+            }
         }
     }
 }
index 557e7dc9955ac11ec202408f1252ac5a91df66ab..69628ea353dcd7cfa39a802b893292647876ca37 100644 (file)
@@ -112,6 +112,11 @@ namespace Hazel
                 case (byte)SendOptionInternal.Hello:
                     HandleReliableReceive(buffer);
 
+                    return null;
+
+                case (byte)SendOptionInternal.Disconnect:
+                    HandleDisconnect();
+
                     return null;
             }
 
@@ -132,6 +137,22 @@ namespace Hazel
             HandleSend(new byte[0], (byte)SendOptionInternal.Hello, acknowledgeCallback);
         }
 
+        /// <summary>
+        ///     Closes this connection safely.
+        /// </summary>
+        public override void Close()
+        {
+            HandleSend(new byte[0], (byte)SendOptionInternal.Disconnect);       //TODO Should disconnect wait for an ack?
+
+            base.Close();
+        }
+
+        /// <summary>
+        ///     Called when the socket has been disconnected at the remote host.
+        /// </summary>
+        /// <param name="e">The exception if one was the cause.</param>
+        protected abstract void HandleDisconnect(HazelException e = null);
+
         /// <summary>
         ///     Called when things are being disposed of
         /// </summary>
index cd362f7a92f6f8c286ab0ffd54a52198b615e121..b03f160f4d34e2bbb5198abde690587cec41f4c3 100644 (file)
@@ -110,7 +110,7 @@ namespace Hazel
                 //If the socket's been disposed then we can just end there.
                 return;
             }
-            catch (SocketException e)
+            catch (SocketException)
             {
                 //TODO Errr...;
                 return;
@@ -140,6 +140,10 @@ namespace Hazel
                 //If this is a new client then connect with them!
                 else
                 {
+                    //Check for malformed connection attempts
+                    if (buffer[0] != (byte)SendOptionInternal.Hello || buffer.Length != 3)
+                        return;
+
                     connection = new UdpServerConnection(this, remoteEndPoint);
                     connections.Add(remoteEndPoint, connection);
                     
index 07735bf13ca9322d578ebc239f9b4167e5f69960..5ea8a495f19cf54c932aeea7c28596a7d4bcc840 100644 (file)
@@ -88,6 +88,33 @@ namespace Hazel
                 InvokeDataReceived(new DataEventArgs(data, (SendOption)buffer[0]));
         }
 
+        /// <summary>
+        ///     Called when the socket has been disconnected at the remote host.
+        /// </summary>
+        /// <param name="e">The exception if one was the cause.</param>
+        protected override void HandleDisconnect(HazelException e = null)
+        {
+            bool invoke = false;
+
+            lock (stateLock)
+            {
+                //Only invoke the disconnected event if we're not already disconnecting
+                if (State == ConnectionState.Connected)
+                {
+                    State = ConnectionState.Disconnecting;
+                    invoke = true;
+                }
+            }
+
+            //Invoke event outide lock if need be
+            if (invoke)
+            {
+                InvokeDisconnected(new DisconnectedEventArgs(e));
+
+                Dispose();
+            }
+        }
+
         /// <summary>
         ///     Safely closes this connection.
         /// </summary>