]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Fixed reliable sends and added keepalive
authorJamJar00 <jamster.30@btinternet.com>
Thu, 28 Apr 2016 21:18:38 +0000 (22:18 +0100)
committerJamJar00 <jamster.30@btinternet.com>
Thu, 28 Apr 2016 21:18:38 +0000 (22:18 +0100)
14 files changed:
Hazel.UnitTests/TcpConnectionTests.cs
Hazel.UnitTests/TestHelper.cs
Hazel.UnitTests/UdpConnectionTests.cs
Hazel/Connection.cs
Hazel/Hazel.csproj
Hazel/SendOptionInternal.cs
Hazel/TcpConnection.cs
Hazel/TcpConnectionListener.cs
Hazel/UdpClientConnection.cs
Hazel/UdpConnection.KeepAlive.cs [new file with mode: 0644]
Hazel/UdpConnection.Reliable.cs
Hazel/UdpConnection.cs
Hazel/UdpConnectionListener.cs
Hazel/UdpServerConnection.cs

index cde4049b870c22b7d853df4bbb913f621c46c1f7..290eeae64a71a4d10b20c40bb87d4654f6c6de57 100644 (file)
@@ -40,7 +40,7 @@ namespace Hazel.UnitTests
             using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
             using (TcpConnection connection = new TcpConnection())
             {
-                TestHelper.RunServerToClientTest(listener, connection, 4, 0, 0, SendOption.OrderedFragmentedReliable);
+                TestHelper.RunServerToClientTest(listener, connection, 4, 0, SendOption.OrderedFragmentedReliable);
             }
         }
 
@@ -53,7 +53,7 @@ namespace Hazel.UnitTests
             using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
             using (TcpConnection connection = new TcpConnection())
             {
-                TestHelper.RunClientToServerTest(listener, connection, 4, 0, 0, SendOption.OrderedFragmentedReliable);
+                TestHelper.RunClientToServerTest(listener, connection, 4, 0, SendOption.OrderedFragmentedReliable);
             }
         }
     }
index 1c4214febbff720bc8d1ee2773071119e18db5c6..02cc11337a81d2230e29e7a20837734b90f6b7aa 100644 (file)
@@ -16,7 +16,7 @@ namespace Hazel.UnitTests
         /// </summary>
         /// <param name="listener">The listener to test.</param>
         /// <param name="connection">The connection to test.</param>
-        internal static void RunServerToClientTest(ConnectionListener listener, Connection connection, int headerSize, int handshakeSize, int totalHandshakeSize, SendOption sendOption)
+        internal static void RunServerToClientTest(ConnectionListener listener, Connection connection, int headerSize, int totalHandshakeSize, SendOption sendOption)
         {
             //Setup meta stuff 
             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -25,11 +25,13 @@ namespace Hazel.UnitTests
             //Setup listener
             listener.NewConnection += delegate(object sender, NewConnectionEventArgs args)
             {
+                Assert.AreEqual(0, args.Connection.Statistics.DataBytesReceived);
+                Assert.AreEqual(0, args.Connection.Statistics.TotalBytesReceived);
+                
                 args.Connection.WriteBytes(data, sendOption);
+                
                 Assert.AreEqual(data.Length, args.Connection.Statistics.DataBytesSent);
-                Assert.AreEqual(0, args.Connection.Statistics.DataBytesReceived);
                 Assert.AreEqual(data.Length + headerSize, args.Connection.Statistics.TotalBytesSent);
-                Assert.AreEqual(0, args.Connection.Statistics.TotalBytesReceived);
             };
 
             listener.Start();
@@ -54,7 +56,7 @@ namespace Hazel.UnitTests
             //Wait until data is received
             mutex.WaitOne();
 
-            Assert.AreEqual(handshakeSize, connection.Statistics.DataBytesSent);
+            Assert.AreEqual(0, connection.Statistics.DataBytesSent);
             Assert.AreEqual(data.Length, connection.Statistics.DataBytesReceived);
             Assert.AreEqual(totalHandshakeSize, connection.Statistics.TotalBytesSent);
             Assert.AreEqual(data.Length + headerSize, connection.Statistics.TotalBytesReceived);
@@ -65,7 +67,7 @@ namespace Hazel.UnitTests
         /// </summary>
         /// <param name="listener">The listener to test.</param>
         /// <param name="connection">The connection to test.</param>
-        internal static void RunClientToServerTest(ConnectionListener listener, Connection connection, int headerSize, int handshakeSize, int totalHandshakeSize, SendOption sendOption)
+        internal static void RunClientToServerTest(ConnectionListener listener, Connection connection, int headerSize, int totalHandshakeSize, SendOption sendOption)
         {
             //Setup meta stuff 
             byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -103,10 +105,10 @@ namespace Hazel.UnitTests
             //Wait until data is received
             mutex.WaitOne();
 
-            Assert.AreEqual(data.Length + handshakeSize, connection.Statistics.DataBytesSent);
+            Assert.AreEqual(data.Length, connection.Statistics.DataBytesSent);
             Assert.AreEqual(0, connection.Statistics.DataBytesReceived);
             Assert.AreEqual(totalHandshakeSize + data.Length + headerSize, connection.Statistics.TotalBytesSent);
-            Assert.AreEqual(sendOption == SendOption.Reliable ? 3 : 0, connection.Statistics.TotalBytesReceived);
+            Assert.AreEqual(0, connection.Statistics.TotalBytesReceived);
         }
     }
 }
index 0134cdc0a6ab0bddf00cc792a3030323ccc17a5c..e2abd18bd4de8e0da7a6bf03799bf98b7d1b4856 100644 (file)
@@ -1,6 +1,7 @@
 using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.Net;
+using System.Threading;
 
 namespace Hazel.UnitTests
 {
@@ -26,7 +27,7 @@ namespace Hazel.UnitTests
 
                 //UdpConnection fields
                 Assert.AreEqual(new IPEndPoint(IPAddress.Loopback, 4296), connection.RemoteEndPoint);
-                Assert.AreEqual(1, connection.Statistics.DataBytesSent);
+                Assert.AreEqual(0, connection.Statistics.DataBytesSent);
                 Assert.AreEqual(0, connection.Statistics.DataBytesReceived);
             }
         }
@@ -40,7 +41,7 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
             using (UdpConnection connection = new UdpClientConnection())
             {
-                TestHelper.RunServerToClientTest(listener, connection, 1, 1, 2, SendOption.None);
+                TestHelper.RunServerToClientTest(listener, connection, 1, 3, SendOption.None);
             }
         }
 
@@ -53,7 +54,7 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
             using (UdpConnection connection = new UdpClientConnection())
             {
-                TestHelper.RunServerToClientTest(listener, connection, 3, 1, 2, SendOption.Reliable);
+                TestHelper.RunServerToClientTest(listener, connection, 3, 3, SendOption.Reliable);
             }
         }
 
@@ -66,7 +67,7 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
             using (UdpConnection connection = new UdpClientConnection())
             {
-                TestHelper.RunClientToServerTest(listener, connection, 1, 1, 2, SendOption.None);
+                TestHelper.RunClientToServerTest(listener, connection, 1, 3, SendOption.None);
             }
         }
 
@@ -79,7 +80,56 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
             using (UdpConnection connection = new UdpClientConnection())
             {
-                TestHelper.RunClientToServerTest(listener, connection, 3, 1, 2, SendOption.Reliable);
+                TestHelper.RunClientToServerTest(listener, connection, 3, 3, SendOption.Reliable);
+            }
+        }
+
+        /// <summary>
+        ///     Tests the keepalive functionality from the client,
+        /// </summary>
+        [TestMethod]
+        public void KeepAliveClientTest()
+        {
+            using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
+            using (UdpConnection connection = new UdpClientConnection())
+            {
+                listener.Start();
+
+                connection.Connect(new NetworkEndPoint(IPAddress.Loopback, 4296));
+                connection.KeepAliveInterval = 100;
+
+                System.Threading.Thread.Sleep(1100);    //Enough time for 10 keep alive packets
+
+                Assert.AreEqual(33, connection.Statistics.TotalBytesSent);
+            }
+        }
+
+        /// <summary>
+        ///     Tests the keepalive functionality from the client,
+        /// </summary>
+        [TestMethod]
+        public void KeepAliveServerTest()
+        {
+            ManualResetEvent mutex = new ManualResetEvent(false);
+
+            using (UdpConnectionListener listener = new UdpConnectionListener(IPAddress.Any, 4296))
+            using (UdpConnection connection = new UdpClientConnection())
+            {
+                listener.NewConnection += delegate(object sender, NewConnectionEventArgs args)
+                {
+                    ((UdpConnection)args.Connection).KeepAliveInterval = 100;
+
+                    Thread.Sleep(1100);    //Enough time for 10 keep alive packets
+
+                    Assert.AreEqual(30, args.Connection.Statistics.TotalBytesSent);
+                    mutex.Set();
+                };
+
+                listener.Start();
+
+                connection.Connect(new NetworkEndPoint(IPAddress.Loopback, 4296));
+
+                mutex.WaitOne();
             }
         }
     }
index 7350be6c2967388223db5b5b816f4a95e7c53bde..d6c4c8327e6b4765eda28302ea08ecc498d5b0b4 100644 (file)
@@ -4,6 +4,7 @@ using System.Linq;
 using System.Text;
 using System.Net.Sockets;
 using System.Net;
+using System.Threading;
 
 
 /* 
@@ -43,9 +44,30 @@ namespace Hazel
         /// <summary>
         ///     The state of this connection.
         /// </summary>
-        public ConnectionState State { get { return state; } protected set { state = value; } }
+        public ConnectionState State
+        {
+            get
+            {
+                return state;
+            }
+            
+            protected set
+            {
+                state = value;
+
+                if (state == ConnectionState.Connected)
+                    connectWaitLock.Set();
+                else
+                    connectWaitLock.Reset();
+            }
+        }
         volatile ConnectionState state;
 
+        /// <summary>
+        ///     Reset event that is triggered when the connection is marked Connected.
+        /// </summary>
+        ManualResetEvent connectWaitLock = new ManualResetEvent(false);
+
         /// <summary>
         ///     Constructor that initializes the ConnecitonStatistics object.
         /// </summary>
@@ -97,6 +119,14 @@ namespace Hazel
                 handler(this, args);
         }
 
+        /// <summary>
+        ///     Blocks until the Connection is connected.
+        /// </summary>
+        protected void WaitOnConnect()
+        {
+            connectWaitLock.WaitOne();
+        }
+
         /// <summary>
         ///     Closes this connections safely.
         /// </summary>
index 38f4f3dc183fcb0edcd1c45bc53df56a03520e6f..efadf841ae9decf6ffde90ed399b955f7b4adb78 100644 (file)
@@ -65,6 +65,7 @@
     <Compile Include="UdpConnection.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="UdpConnection.KeepAlive.cs" />
     <Compile Include="UdpConnection.Reliable.cs" />
     <Compile Include="UdpConnectionListener.cs" />
     <Compile Include="UdpServerConnection.cs" />
index 335d58102d919c7af8ebb787d48ca0f42760f0d5..5e4f6210f89d7cbe9f675a83f61e77e3b78310c4 100644 (file)
@@ -11,6 +11,14 @@ namespace Hazel
     /// </summary>
     enum SendOptionInternal : byte
     {
+        /// <summary>
+        ///     Hello message for initiating communication.
+        /// </summary>
+        Hello = 254,
+
+        /// <summary>
+        ///     Message acknowledging the receipt of a message.
+        /// </summary>
         Acknowledgement = 255
     }
 }
index 4ad2db2da56ed405d4900903d132b5dbb4564602..f39514b1aa0ca5257b45c833f42255582ed2b848 100644 (file)
@@ -63,6 +63,22 @@ namespace Hazel
             Socket.NoDelay = true;
         }
 
+        /// <summary>
+        ///     Internal call to start listening once this socket has been constructed and is ready.
+        /// </summary>
+        internal void StartListening()
+        {
+            //Start receiving data
+            try
+            {
+                StartWaitingForHeader();
+            }
+            catch (SocketException e)
+            {
+                throw new HazelException("A Socket exception occured while initiating a receive operation.", e);
+            }
+        }
+
         /// <summary>
         ///     Connects this TCP connection to the endpoint.
         /// </summary>
index 1c01ad63b37fd90b147568e7768bff540510c0dc..09af39e7b0e7a592941724b8fdfa058d7cd7324b 100644 (file)
@@ -98,6 +98,8 @@ namespace Hazel
                 NewConnectionEventArgs args = new NewConnectionEventArgs(tcpConnection);
 
                 FireNewConnectionEvent(args);
+
+                tcpConnection.StartListening();
             }
         }
 
index fcdc917ceaf89a8803649c082bf6d8603abd7160..b5516c49fa589c34ef8a99706d3aff991fb80652 100644 (file)
@@ -25,6 +25,7 @@ namespace Hazel
         ///     Creates a new UdpClientConnection.
         /// </summary>
         public UdpClientConnection()
+            : base()
         {
             socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
         }
@@ -36,8 +37,11 @@ namespace Hazel
         /// <param name="sendOption">The option this data is requested to send with.</param>
         public override void WriteBytes(byte[] bytes, SendOption sendOption = SendOption.None)
         {
+            if (State != ConnectionState.Connected)
+                throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?");
+
             //Add header information and send
-            HandleSend(bytes, sendOption);
+            HandleSend(bytes, (byte)sendOption);
         }
 
         /// <summary>
@@ -53,8 +57,8 @@ namespace Hazel
 
             lock (socket)
             {
-                if (State != ConnectionState.Connected)
-                    throw new InvalidOperationException("Could not send data as this Connection is not connected. 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
                 {
@@ -82,7 +86,7 @@ namespace Hazel
             NetworkEndPoint nep = remoteEndPoint as NetworkEndPoint;
             if (nep == null)
             {
-                throw new ArgumentException("The remote end point of a TCP connection must be a NetworkEndPoint.");
+                throw new ArgumentException("The remote end point of a UDP connection must be a NetworkEndPoint.");
             }
 
             this.EndPoint = nep;
@@ -118,12 +122,14 @@ namespace Hazel
                 {
                     throw new HazelException("A Socket exception occured while initiating a receive operation.", e);
                 }
-
-                State = ConnectionState.Connected;
             }
 
-            //Write bytes to the server to tell it hi (and to punch a hole in our NAT, if present).
-            WriteBytes(new byte[] { 0 }, SendOption.None);  //TODO special hello message
+            //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(() => State = ConnectionState.Connected);
+
+            //Wait till hello packet is acknowledged and the state is set to Connected
+            WaitOnConnect();
         }
 
         /// <summary>
diff --git a/Hazel/UdpConnection.KeepAlive.cs b/Hazel/UdpConnection.KeepAlive.cs
new file mode 100644 (file)
index 0000000..1531874
--- /dev/null
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Hazel
+{
+    /// <summary>
+    ///     UdpConnection part which handles keepalive packets.
+    /// </summary>
+    partial class UdpConnection
+    {
+        /// <summary>
+        ///     The interval from data being received or transmitted to a keepalive packet being sent.
+        /// </summary>
+        /// <remarks>
+        ///     Set to System.Threading.Timeout.Infinite to disable keepalive packets.
+        /// </remarks>
+        public int KeepAliveInterval
+        {
+            get
+            {
+                return keepAliveInterval;
+            }
+
+            set
+            {
+                keepAliveInterval = value;
+                
+                //Update timer
+                ResetKeepAliveTimer();
+            }
+        }
+        int keepAliveInterval = 10000;
+
+        /// <summary>
+        ///     The timer creating keepalive pulses.
+        /// </summary>
+        Timer keepAliveTimer;
+
+        /// <summary>
+        ///     Lock for keep alive timer.
+        /// </summary>
+        Object keepAliveTimerLock = new Object();
+
+        /// <summary>
+        ///     Starts the keepalive timer.
+        /// </summary>
+        void InitializeKeepAliveTimer()
+        {
+            lock (keepAliveTimerLock)
+            {
+                keepAliveTimer = new Timer(
+                    (o) =>
+                    {
+                        Trace.WriteLine("Keepalive packet sent.");
+                        SendHello(null);
+                    },
+                    null,
+                    keepAliveInterval,
+                    keepAliveInterval
+                );
+            }
+        }
+
+        /// <summary>
+        ///     Resets the keepalive timer to zero.
+        /// </summary>
+        void ResetKeepAliveTimer()
+        {
+            lock (keepAliveTimerLock)
+                keepAliveTimer.Change(keepAliveInterval, keepAliveInterval);
+        }
+
+        /// <summary>
+        ///     Disposes of the keep alive timer.
+        /// </summary>
+        void DisposeKeepAliveTimer()
+        {
+            lock(keepAliveTimerLock)
+                keepAliveTimer.Dispose();
+        }
+    }
+}
index 36baf3c95293224d69fe0bda67feb5b6832e1403..fd53ab749741a958bd6f2da9b90f0768fa31ea90 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Text;
 using System.Threading;
@@ -56,8 +57,9 @@ namespace Hazel
             public byte[] Data;
             public Timer Timer;
             public int LastTimeout;
+            public Action AckCallback;
 
-            public Packet(byte[] data, Action<Packet> resendAction, int timeout)
+            public Packet(byte[] data, Action<Packet> resendAction, int timeout, Action ackCallback)
             {
                 Data = data;
                 
@@ -65,10 +67,11 @@ namespace Hazel
                     (object obj) => resendAction(this),
                     null, 
                     timeout,
-                    timeout
+                    Timeout.Infinite
                 );
 
                 LastTimeout = timeout;
+                AckCallback = ackCallback;
             }
         }
 
@@ -76,7 +79,7 @@ namespace Hazel
         ///     Writes the bytes neccessary for a reliable send and stores the send.
         /// </summary>
         /// <param name="bytes">The byte array to write to.</param>
-        void WriteReliableSendHeader(byte[] bytes)
+        void WriteReliableSendHeader(byte[] bytes, Action ackCallback)
         {
             lock (reliableDataPacketsSent)
             {
@@ -99,9 +102,13 @@ namespace Hazel
                         WriteBytesToConnection(p.Data);
 
                         //Double packet timeout
-                        p.Timer.Change(0, p.LastTimeout *= 2);
+                        lock (p.Timer)
+                            p.Timer.Change(p.LastTimeout *= 2, Timeout.Infinite);
+
+                        Trace.WriteLine("Resend.");
                     },
-                    resendTimeout
+                    resendTimeout,
+                    ackCallback
                 );
 
                 //Remember packet
@@ -119,15 +126,8 @@ namespace Hazel
             //Get the ID form the packet
             ushort id = (ushort)((bytes[1] << 8) + bytes[2]);
 
-            //Always reply with acknowledgement in order to stop the sender repeatedly sending it
-            WriteBytesToConnection(     //TODO group acks together
-                new byte[]
-                {
-                    (byte)SendOptionInternal.Acknowledgement,
-                    bytes[1],
-                    bytes[2]
-                }
-            );
+            //Send an acknowledgement
+            SendAck(bytes[1], bytes[2]);
 
             //Handle reliableness!
             lock (reliableDataPacketsMissing)
@@ -174,10 +174,30 @@ namespace Hazel
                 //Dispose of timer and remove from dictionary
                 if (reliableDataPacketsSent.ContainsKey(id))
                 {
-                    reliableDataPacketsSent[id].Timer.Dispose();
+                    Packet packet = reliableDataPacketsSent[id];
+                    
+                    lock (packet.Timer)
+                        packet.Timer.Dispose();
+                    
+                    if (packet.AckCallback != null)
+                        packet.AckCallback.Invoke();
+
                     reliableDataPacketsSent.Remove(id);
                 }
             }
         }
+
+        internal void SendAck(byte byte1, byte byte2)
+        {
+            //Always reply with acknowledgement in order to stop the sender repeatedly sending it
+            WriteBytesToConnection(     //TODO group acks together
+                new byte[]
+                {
+                    (byte)SendOptionInternal.Acknowledgement,
+                    byte1,
+                    byte2
+                }
+            );
+        }
     }
 }
index 09936fb327d547b5764a15b3ba289df9961ae699..557e7dc9955ac11ec202408f1252ac5a91df66ab 100644 (file)
@@ -31,20 +31,32 @@ namespace Hazel
         /// <param name="bytes">The bytes to write.</param>
         protected abstract void WriteBytesToConnection(byte[] bytes);
 
+        protected UdpConnection()
+        {
+            InitializeKeepAliveTimer();
+        }
+
         /// <summary>
         ///     Handles the reliable/fragmented/ordered sending from this connection.
         /// </summary>
         /// <param name="data">The data being sent.</param>
-        /// <param name="sendOption">The send option.</param>
+        /// <param name="sendOption">The send option as a byte.</param>
         /// <returns>The bytes that should actually be sent.</returns>
-        protected void HandleSend(byte[] data, SendOption sendOption)
+        protected void HandleSend(byte[] data, byte sendOption, Action ackCallback = null)
         {
             byte[] bytes;
             switch (sendOption)
             {
-                case SendOption.Reliable:
+                //Handle reliable header
+                case (byte)SendOption.Reliable:
                     bytes = new byte[data.Length + 3];
-                    WriteReliableSendHeader(bytes);
+                    WriteReliableSendHeader(bytes, ackCallback);
+                    break;
+
+                //Handle hellos (ignore data)
+                case (byte)SendOptionInternal.Hello:
+                    bytes = new byte[3];
+                    WriteReliableSendHeader(bytes, ackCallback);
                     break;
 
                 default:
@@ -53,14 +65,17 @@ namespace Hazel
             }
 
             //Add message type
-            bytes[0] = (byte)sendOption;
+            bytes[0] = sendOption;
 
             //Copy data into new array
             Buffer.BlockCopy(data, 0, bytes, bytes.Length - data.Length, data.Length);
 
+            //Inform keepalive not to send for a while
+            ResetKeepAliveTimer();      //TODO keepalive tests
+
             //Write to connection
             WriteBytesToConnection(bytes);
-
+            
             Statistics.LogSend(data.Length, bytes.Length);
         }
 
@@ -72,9 +87,13 @@ namespace Hazel
         /// <returns>The bytes of data received.</returns>
         protected byte[] HandleReceive(byte[] buffer, int bytesReceived)
         {
+            //Inform keepalive not to send for a while
+            ResetKeepAliveTimer();
+
             int headerSize = 1;
             switch (buffer[0])
             {
+                    //Handle reliable receives
                 case (byte)SendOption.Reliable:
                     headerSize = 3;
 
@@ -82,11 +101,17 @@ namespace Hazel
                         return null;
                     break;
 
+                    //Handle acknowledgments
                 case (byte)SendOptionInternal.Acknowledgement:
                     HandleAcknowledgement(buffer);
-                    
-                    Statistics.LogReceive(0, bytesReceived);
-                    
+
+                    return null;
+
+                //We need to acknowledge hello messages so just use the same reliable receive
+                //method
+                case (byte)SendOptionInternal.Hello:
+                    HandleReliableReceive(buffer);
+
                     return null;
             }
 
@@ -97,5 +122,28 @@ namespace Hazel
 
             return dataBytes;
         }
+
+        /// <summary>
+        ///     Sends a hello packet to the remote endpoint.
+        /// </summary>
+        /// <param name="acknowledgeCallback">The callback to invoke when the hello packet is acknowledged.</param>
+        protected void SendHello(Action acknowledgeCallback)
+        {
+            HandleSend(new byte[0], (byte)SendOptionInternal.Hello, acknowledgeCallback);
+        }
+
+        /// <summary>
+        ///     Called when things are being disposed of
+        /// </summary>
+        /// <param name="disposing"></param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                DisposeKeepAliveTimer();
+            }
+
+            base.Dispose(disposing);
+        }
     }
 }
index f820e761c592bca672e63b1700ee1981c96ca59f..cd362f7a92f6f8c286ab0ffd54a52198b615e121 100644 (file)
@@ -142,6 +142,9 @@ namespace Hazel
                 {
                     connection = new UdpServerConnection(this, remoteEndPoint);
                     connections.Add(remoteEndPoint, connection);
+                    
+                    //Then ping back an ack to make sure they're happy
+                    connection.SendAck(buffer[1], buffer[2]);
                 }
             }
 
index ee9f95f03ee92a886842773d42bec1de3fe57674..07735bf13ca9322d578ebc239f9b4167e5f69960 100644 (file)
@@ -31,6 +31,7 @@ namespace Hazel
         /// </summary>
         /// <param name="socket"></param>
         internal UdpServerConnection(UdpConnectionListener listener, EndPoint endPoint)
+            : base()
         {
             this.Listener = listener;
             this.RemoteEndPoint = endPoint;
@@ -46,7 +47,7 @@ namespace Hazel
         /// <param name="sendOption">The option this data is requested to send with.</param>
         public override void WriteBytes(byte[] bytes, SendOption sendOption = SendOption.None)
         {
-            HandleSend(bytes, sendOption);
+            HandleSend(bytes, (byte)sendOption);
         }
 
         /// <summary>