]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Added fragmented messages
authorJamJar00 <jamster.30@btinternet.com>
Sat, 31 Dec 2016 16:28:47 +0000 (16:28 +0000)
committerJamJar00 <jamster.30@btinternet.com>
Sat, 31 Dec 2016 16:28:47 +0000 (16:28 +0000)
12 files changed:
Hazel.UnitTests/TcpConnectionTests.cs
Hazel.UnitTests/TestHelper.cs
Hazel.UnitTests/UdpConnectionTests.cs
Hazel/Hazel.csproj
Hazel/SendOption.cs
Hazel/SendOptionInternal.cs [deleted file]
Hazel/Udp/SendOptionInternal.cs [new file with mode: 0644]
Hazel/Udp/UdpClientConnection.cs
Hazel/Udp/UdpConnection.Fragmented.cs [new file with mode: 0644]
Hazel/Udp/UdpConnection.Reliable.cs
Hazel/Udp/UdpConnection.cs
Hazel/Udp/UdpConnectionListener.cs

index fc61c9ffe8ed322d20674f08e8afefc0c731d8c4..95b48d5b22935dae9b1f97f635e2b5dde4f5a66f 100644 (file)
@@ -94,7 +94,7 @@ namespace Hazel.UnitTests
             using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
             using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunServerToClientTest(listener, connection, 4, 5, SendOption.FragmentedReliable);
+                TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.FragmentedReliable);
             }
         }
 
@@ -107,7 +107,7 @@ namespace Hazel.UnitTests
             using (TcpConnectionListener listener = new TcpConnectionListener(IPAddress.Any, 4296))
             using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunClientToServerTest(listener, connection, 4, 5, SendOption.FragmentedReliable);
+                TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.FragmentedReliable);
             }
         }
 
index a66dc6f461e04e28335ddfeaf62aa797a99b249c..0bb16931f3b93ed06aad88dc33696eb5ed1d2f36 100644 (file)
@@ -16,10 +16,10 @@ 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 totalHandshakeSize, SendOption sendOption)
+        internal static void RunServerToClientTest(ConnectionListener listener, Connection connection, int dataSize, SendOption sendOption)
         {
             //Setup meta stuff 
-            byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+            byte[] data = BuildData(dataSize);
             ManualResetEvent mutex = new ManualResetEvent(false);
 
             //Setup listener
@@ -56,10 +56,10 @@ 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 totalHandshakeSize, SendOption sendOption)
+        internal static void RunClientToServerTest(ConnectionListener listener, Connection connection, int dataSize, SendOption sendOption)
         {
             //Setup meta stuff 
-            byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+            byte[] data = BuildData(dataSize);
             ManualResetEvent mutex = new ManualResetEvent(false);
             ManualResetEvent mutex2 = new ManualResetEvent(false);
 
@@ -152,5 +152,18 @@ namespace Hazel.UnitTests
 
             mutex2.WaitOne();
         }
+
+        /// <summary>
+        ///     Builds new data of increaseing value bytes.
+        /// </summary>
+        /// <param name="dataSize">The number of bytes to generate.</param>
+        /// <returns>The data.</returns>
+        static byte[] BuildData(int dataSize)
+        {
+            byte[] data = new byte[dataSize];
+            for (int i = 0; i < dataSize; i++)
+                data[i] = (byte)i;
+            return data;
+        }
     }
 }
index 7d7b0a1110c70474014946cecc9a3448e1fc1826..878fa5c60adbdfbb47dbc1ec8d9ac295450793f7 100644 (file)
@@ -94,7 +94,7 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
             using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunServerToClientTest(listener, connection, 1, 4, SendOption.None);
+                TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.None);
             }
         }
 
@@ -107,7 +107,20 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
             using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunServerToClientTest(listener, connection, 3, 4, SendOption.Reliable);
+                TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.Reliable);
+            }
+        }
+
+        /// <summary>
+        ///     Tests server to client reliable communication on the UdpConnection.
+        /// </summary>
+        [TestMethod]
+        public void UdpFragmentedServerToClientTest()
+        {
+            using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
+            using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
+            {
+                TestHelper.RunServerToClientTest(listener, connection, (int)(connection.FragmentSize * 9.5), SendOption.FragmentedReliable);
             }
         }
 
@@ -120,7 +133,7 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
             using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunClientToServerTest(listener, connection, 1, 4, SendOption.None);
+                TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.None);
             }
         }
 
@@ -133,7 +146,20 @@ namespace Hazel.UnitTests
             using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
             using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
             {
-                TestHelper.RunClientToServerTest(listener, connection, 3, 4, SendOption.Reliable);
+                TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.Reliable);
+            }
+        }
+
+        /// <summary>
+        ///     Tests server to client reliable communication on the UdpConnection.
+        /// </summary>
+        [TestMethod]
+        public void UdpFragmentedClientToServerTest()
+        {
+            using (UdpConnectionListener listener = new UdpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
+            using (UdpConnection connection = new UdpClientConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
+            {
+                TestHelper.RunClientToServerTest(listener, connection, (int)(connection.FragmentSize * 9.5), SendOption.FragmentedReliable);
             }
         }
 
index 151a0aa1dde381f28c55ee267060e4d7fbdafcfc..f382241c811275cfd58a3b332e01b511f2970fc0 100644 (file)
@@ -69,7 +69,7 @@
     <Compile Include="ObjectPool.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SendOption.cs" />
-    <Compile Include="SendOptionInternal.cs" />
+    <Compile Include="Udp\SendOptionInternal.cs" />
     <Compile Include="Tcp\StateObject.cs" />
     <Compile Include="ConnectionStatistics.cs" />
     <Compile Include="Tcp\TcpConnection.cs" />
@@ -78,6 +78,7 @@
     <Compile Include="Udp\UdpConnection.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Udp\UdpConnection.Fragmented.cs" />
     <Compile Include="Udp\UdpConnection.KeepAlive.cs" />
     <Compile Include="Udp\UdpConnection.Reliable.cs" />
     <Compile Include="Udp\UdpConnectionListener.cs" />
index a81fded3d2b93380c9fcf17faea5e522f47b99a1..e7ebec2aaf62adb1c1b1c7bd2b1a112c5960bd8f 100644 (file)
@@ -31,18 +31,7 @@ namespace Hazel
         ///     a larger number of protocol bytes and can be slower than unreliable delivery.
         /// </remarks>
         Reliable = 1,
-
-        /// <summary>
-        ///     Requests data be sent so that large messages are fragmented into smaller chunks of
-        ///     data and reassembled when received.
-        /// </summary>
-        /// <remarks>
-        ///     Fragmented messages allow large amounts of data to be transmitted in smaller chunks when using connections 
-        ///     that do not support the transmission of large messages. Without specifying reliable delivery there is no 
-        ///     guarentee that the message will arrive but any incomplete messages will be simply be discarded.
-        /// </remarks>
-        Fragmented = 2,
-
+        
         /// <summary>
         ///     Requests data be sent so that large messages are fragmented into smaller chunks of
         ///     data and reassembled when received.
@@ -53,6 +42,6 @@ namespace Hazel
         ///     guaranteed to arrive and to arrive only once but the sending process may require more memory, processing,
         ///     a larger number protocol bytes and may be slower than sending unreliably.
         /// </remarks>
-        FragmentedReliable = 3
+        FragmentedReliable = 2
     }
 }
diff --git a/Hazel/SendOptionInternal.cs b/Hazel/SendOptionInternal.cs
deleted file mode 100644 (file)
index 2a7a707..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-
-namespace Hazel
-{
-    /// <summary>
-    ///     Extra internal states for SendOption enumeration when using UDP.
-    /// </summary>
-    enum SendOptionInternal : byte
-    {
-        /// <summary>
-        ///     Hello message for initiating communication.
-        /// </summary>
-        Hello = 8,
-
-        /// <summary>
-        ///     Message for discontinuing communication.
-        /// </summary>
-        Disconnect = 9,
-
-        /// <summary>
-        ///     Message acknowledging the receipt of a message.
-        /// </summary>
-        Acknowledgement = 10
-    }
-}
diff --git a/Hazel/Udp/SendOptionInternal.cs b/Hazel/Udp/SendOptionInternal.cs
new file mode 100644 (file)
index 0000000..164ab83
--- /dev/null
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+
+namespace Hazel.Udp
+{
+    /// <summary>
+    ///     Extra internal states for SendOption enumeration when using UDP.
+    /// </summary>
+    enum UdpSendOption : byte
+    {
+        /// <summary>
+        ///     Hello message for initiating communication.
+        /// </summary>
+        Hello = 8,
+
+        /// <summary>
+        ///     Message for discontinuing communication.
+        /// </summary>
+        Disconnect = 9,
+
+        /// <summary>
+        ///     Message acknowledging the receipt of a message.
+        /// </summary>
+        Acknowledgement = 10,
+
+        /// <summary>
+        ///     Message that is part of a larger, fragmented message.
+        /// </summary>
+        Fragment = 11
+    }
+}
index 26eece7a4e3c44244eefbf83569098f068e7edd2..4ffe4242d5d6f5c563a9c6648e6de58cad77e33d 100644 (file)
@@ -79,6 +79,10 @@ namespace Hazel.Udp
                                 lock (socket)
                                     socket.EndSendTo(result);
                             }
+                            catch (ObjectDisposedException e)
+                            {
+                                HandleDisconnect(new HazelException("Could not send as the socket was disposed of.", e));
+                            }
                             catch (SocketException e)
                             {
                                 HandleDisconnect(new HazelException("Could not send data as a SocketException occured.", e));
diff --git a/Hazel/Udp/UdpConnection.Fragmented.cs b/Hazel/Udp/UdpConnection.Fragmented.cs
new file mode 100644 (file)
index 0000000..09248bd
--- /dev/null
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Hazel.Udp
+{
+    partial class UdpConnection
+    {
+        /// <summary>
+        ///     The amount of data that can be put into a fragment.
+        /// </summary>
+        public int FragmentSize { get; } = 65507 - 1 - 2 - 2 - 2;
+
+        /// <summary>
+        ///     The last fragmented message ID that was written.
+        /// </summary>
+        volatile ushort lastFragmentIDAllocated;
+
+        Dictionary<ushort, FragmentedMessage> fragmentedMessagesReceived = new Dictionary<ushort, FragmentedMessage>();
+
+        /// <summary>
+        ///     Sends a message fragmenting it as needed to pass over the network.
+        /// </summary>
+        /// <param name="sendOption">The send option the message was sent with.</param>
+        /// <param name="data">The data of the message to send.</param>
+        void FragmentedSend(byte[] data)
+        {
+            //Get an ID not used yet.
+            ushort id = ++lastFragmentIDAllocated;      //TODO manage loop around
+
+            for (ushort i = 0; i < Math.Ceiling(data.Length / (double)FragmentSize); i++)
+            {
+                byte[] buffer = new byte[Math.Min(data.Length - (FragmentSize * i), FragmentSize) + 7];
+
+                //Add send option
+                buffer[0] = i == 0 ? (byte)SendOption.FragmentedReliable : (byte)UdpSendOption.Fragment;
+
+                //Add fragment message ID
+                buffer[1] = (byte)((id >> 8) & 0xFF);
+                buffer[2] = (byte)id;
+
+                //Add length or fragment id
+                if (i == 0)
+                {
+                    ushort fragments = (ushort)Math.Ceiling(data.Length / (double)FragmentSize);
+                    buffer[3] = (byte)((fragments >> 8) & 0xFF);
+                    buffer[4] = (byte)fragments;
+                }
+                else
+                {
+                    buffer[3] = (byte)((i >> 8) & 0xFF);
+                    buffer[4] = (byte)i;
+                }
+
+                //Pass fragment to reliable send code to ensure it will arrive
+                AttachReliableID(buffer, 5);
+
+                //Copy data into fragment
+                Buffer.BlockCopy(data, FragmentSize * i, buffer, 7, buffer.Length - 7);
+
+                //Send
+                WriteBytesToConnection(buffer);
+            }
+        }
+
+        /// <summary>
+        ///     Gets a message from those we've begun receiving or adds a new one.
+        /// </summary>
+        /// <param name="messageId">The Id of the message to find.</param>
+        /// <returns></returns>
+        FragmentedMessage GetFragmentedMessage(ushort messageId)
+        {
+            lock (fragmentedMessagesReceived)
+            {
+                FragmentedMessage message;
+                if (fragmentedMessagesReceived.ContainsKey(messageId))
+                {
+                    message = fragmentedMessagesReceived[messageId];
+                }
+                else
+                {
+                    message = new FragmentedMessage();
+
+                    fragmentedMessagesReceived.Add(messageId, message);
+                }
+
+                return message;
+            }
+        }
+
+        /// <summary>
+        ///     Handles a the start message of a fragmented message.
+        /// </summary>
+        /// <param name="buffer">The buffer received.</param>
+        void FragmentedStartMessageReceive(byte[] buffer)
+        {
+            //Send to reliable code to send the acknowledgement
+            if (!ProcessReliableReceive(buffer, 5))
+                return;
+
+            ushort id = (ushort)((buffer[1] << 8) + buffer[2]);
+
+            ushort length = (ushort)((buffer[3] << 8) + buffer[4]);
+
+            FragmentedMessage message;
+            bool messageComplete;
+            lock (fragmentedMessagesReceived)
+            {
+                message = GetFragmentedMessage(id);
+                message.received.Add(new FragmentedMessage.Fragment(0, buffer, 7));
+                message.noFragments = length;
+
+                messageComplete = message.noFragments == message.received.Count;
+            }
+
+            if (messageComplete)
+                FinalizeFragmentedMessage(message);
+        }
+
+        /// <summary>
+        ///     Handles a fragment message of a fragmented message.
+        /// </summary>
+        /// <param name="buffer">The buffer received.</param>
+        void FragmentedMessageReceive(byte[] buffer)
+        {
+            //Send to reliable code to send the acknowledgement
+            if (!ProcessReliableReceive(buffer, 5))
+                return;
+
+            ushort id = (ushort)((buffer[1] << 8) + buffer[2]);
+
+            ushort fragmentID = (ushort)((buffer[3] << 8) + buffer[4]);
+
+            FragmentedMessage message;
+            bool messageComplete;
+            lock (fragmentedMessagesReceived)
+            {
+                message = GetFragmentedMessage(id);
+                message.received.Add(new FragmentedMessage.Fragment(fragmentID, buffer, 7));
+
+                messageComplete = message.noFragments == message.received.Count;
+            }
+
+            if (messageComplete)
+                FinalizeFragmentedMessage(message);
+        }
+
+        /// <summary>
+        ///     Finalizes a completed fragmented message and invokes message received events.
+        /// </summary>
+        /// <param name="message">The message received.</param>
+        void FinalizeFragmentedMessage(FragmentedMessage message)
+        {
+            IEnumerable<FragmentedMessage.Fragment> orderedFragments = message.received.OrderBy((x) => x.fragmentID);
+
+            byte[] completeData = new byte[(orderedFragments.Count() - 1) * FragmentSize + orderedFragments.Last().data.Length];
+            int ptr = 0;
+            foreach (FragmentedMessage.Fragment fragment in orderedFragments)
+            {
+                Buffer.BlockCopy(fragment.data, fragment.offset, completeData, ptr, fragment.data.Length - fragment.offset);
+                ptr += fragment.data.Length - fragment.offset;
+            }
+
+            InvokeDataReceived(completeData, SendOption.FragmentedReliable);
+        }
+
+        /// <summary>
+        ///     Holding class for the parts of a fragmented message so far received.
+        /// </summary>
+        private class FragmentedMessage
+        {
+            /// <summary>
+            ///     The total number of fragments expected.
+            /// </summary>
+            public int noFragments = -1;
+
+            /// <summary>
+            ///     The fragments received so far.
+            /// </summary>
+            public List<Fragment> received = new List<Fragment>();
+
+            public struct Fragment
+            {
+                public int fragmentID;
+                public byte[] data;
+                public int offset;
+
+                public Fragment(int fragmentID, byte[] data, int offset)
+                {
+                    this.fragmentID = fragmentID;
+                    this.data = data;
+                    this.offset = offset;
+                }
+            }
+        }
+    }
+}
index 2b5868353082301dac914a6941781609c304c497..f87233b0d7a66177230640b238b222ae56dc9c0f 100644 (file)
@@ -177,17 +177,13 @@ namespace Hazel.Udp
         }
 
         /// <summary>
-        ///     Sends the bytes reliably and stores the send.
+        ///     Adds a 2 byte ID to the packet at offset and stores the packet reference for retransmission.
         /// </summary>
-        /// <param name="bytes">The byte array to write to.</param>
+        /// <param name="buffer">The buffer to attach to.</param>
+        /// <param name="offset">The offset to attach at.</param>
         /// <param name="ackCallback">The callback to make once the packet has been acknowledged.</param>
-        void ReliableSend(byte sendOption, byte[] data, Action ackCallback)
+        void AttachReliableID(byte[] buffer, int offset, Action ackCallback = null)
         {
-            byte[] bytes = new byte[data.Length + 3];
-
-            //Add message type
-            bytes[0] = sendOption;
-
             //Find and reliable ID
             lock (reliableDataPacketsSent)
             {
@@ -199,13 +195,13 @@ namespace Hazel.Udp
                 while (reliableDataPacketsSent.ContainsKey(id));
 
                 //Write ID
-                bytes[1] = (byte)((id >> 8) & 0xFF);
-                bytes[2] = (byte)id;
+                buffer[offset] = (byte)((id >> 8) & 0xFF);
+                buffer[offset + 1] = (byte)id;
 
                 //Create packet object
                 Packet packet = Packet.GetObject();
                 packet.Set(
-                    bytes,
+                    buffer,
                     (Packet p) =>
                     {
                         //Double packet timeout
@@ -217,7 +213,7 @@ namespace Hazel.Udp
                                 if (++p.Retransmissions > ResendsBeforeDisconnect)
                                 {
                                     HandleDisconnect();
-                                    
+
                                     //Set acknowledged so we dont change the timer again
                                     p.Acknowledged = true;
 
@@ -246,6 +242,22 @@ namespace Hazel.Udp
                 //Remember packet
                 reliableDataPacketsSent.Add(id, packet);
             }
+        }
+
+        /// <summary>
+        ///     Sends the bytes reliably and stores the send.
+        /// </summary>
+        /// <param name="bytes">The byte array to write to.</param>
+        /// <param name="ackCallback">The callback to make once the packet has been acknowledged.</param>
+        void ReliableSend(byte sendOption, byte[] data, Action ackCallback = null)
+        {
+            byte[] bytes = new byte[data.Length + 3];
+
+            //Add message type
+            bytes[0] = sendOption;
+
+            //Add reliable ID
+            AttachReliableID(bytes, 1, ackCallback);
             
             //Copy data into new array
             Buffer.BlockCopy(data, 0, bytes, bytes.Length - data.Length, data.Length);
@@ -260,9 +272,9 @@ namespace Hazel.Udp
         ///     Handles a reliable message being received and invokes the data event.
         /// </summary>
         /// <param name="buffer">The buffer received.</param>
-        void ReliableReceive(byte[] buffer)
+        void ReliableMessageReceive(byte[] buffer)
         {
-            if (ProcessReliableReceive(buffer))
+            if (ProcessReliableReceive(buffer, 1))
                 InvokeDataReceived(SendOption.Reliable, buffer, 3);
 
             Statistics.LogReliableReceive(buffer.Length - 3, buffer.Length);
@@ -272,14 +284,15 @@ namespace Hazel.Udp
         ///     Handles receives from reliable packets.
         /// </summary>
         /// <param name="bytes">The buffer containing the data.</param>
+        /// <param name="offset">The offset of the reliable header.</param>
         /// <returns>Whether the packet was a new packet or not.</returns>
-        bool ProcessReliableReceive(byte[] bytes)
+        bool ProcessReliableReceive(byte[] bytes, int offset)
         {
             //Get the ID form the packet
-            ushort id = (ushort)((bytes[1] << 8) + bytes[2]);
+            ushort id = (ushort)((bytes[offset] << 8) + bytes[offset + 1]);
 
             //Send an acknowledgement
-            SendAck(bytes[1], bytes[2]);
+            SendAck(bytes[offset], bytes[offset + 1]);
 
             /*
              * It gets a little complicated here (note the fact I'm actually using a multiline comment for once...)
@@ -348,7 +361,7 @@ namespace Hazel.Udp
         ///     Handles acknowledgement packets to us.
         /// </summary>
         /// <param name="bytes">The buffer containing the data.</param>
-        void AcknowledgementReceive(byte[] bytes)
+        void AcknowledgementMessageReceive(byte[] bytes)
         {
             //Get ID
             ushort id = (ushort)((bytes[1] << 8) + bytes[2]);
@@ -390,7 +403,7 @@ namespace Hazel.Udp
             WriteBytesToConnection(     //TODO group acks together
                 new byte[]
                 {
-                    (byte)SendOptionInternal.Acknowledgement,
+                    (byte)UdpSendOption.Acknowledgement,
                     byte1,
                     byte2
                 }
index 7e7e745dbb572e3ff1f7e38671108139ec2f0b9b..d724be9b60348a62241b6fdb255ce27f67fcec37 100644 (file)
@@ -63,13 +63,17 @@ namespace Hazel.Udp
             {
                 //Handle reliable header and hellos
                 case (byte)SendOption.Reliable:
-                case (byte)SendOptionInternal.Hello:
+                case (byte)UdpSendOption.Hello:
                     ReliableSend(sendOption, data, ackCallback);
                     break;
+
+                case (byte)SendOption.FragmentedReliable:
+                    FragmentedSend(data);
+                    break;
                 
                 //Treat all else as unreliable
                 default:
-                    UnreliableSend(sendOption, data);
+                    UnreliableSend(data, sendOption);
                     break;
             }
         }
@@ -87,24 +91,33 @@ namespace Hazel.Udp
             {
                 //Handle reliable receives
                 case (byte)SendOption.Reliable:
-                    ReliableReceive(buffer);
+                    ReliableMessageReceive(buffer);
                     break;
 
                 //Handle acknowledgments
-                case (byte)SendOptionInternal.Acknowledgement:
-                    AcknowledgementReceive(buffer);
+                case (byte)UdpSendOption.Acknowledgement:
+                    AcknowledgementMessageReceive(buffer);
                     break;
 
                 //We need to acknowledge hello messages but dont want to invoke any events!
-                case (byte)SendOptionInternal.Hello:
-                    ProcessReliableReceive(buffer);
+                case (byte)UdpSendOption.Hello:
+                    ProcessReliableReceive(buffer, 1);
                     Statistics.LogHelloReceive(buffer.Length);
                     break;
 
-                case (byte)SendOptionInternal.Disconnect:
+                case (byte)UdpSendOption.Disconnect:
                     HandleDisconnect();                    
                     break;
 
+                //Handle fragmented messages
+                case (byte)SendOption.FragmentedReliable:
+                    FragmentedStartMessageReceive(buffer);
+                    break;
+
+                case (byte)UdpSendOption.Fragment:
+                    FragmentedMessageReceive(buffer);
+                    break;
+
                 //Treat everything else as unreliable
                 default:
                     InvokeDataReceived(SendOption.None, buffer, 1);
@@ -113,7 +126,12 @@ namespace Hazel.Udp
             }
         }
 
-        void UnreliableSend(byte sendOption, byte[] data)
+        /// <summary>
+        ///     Sends bytes using the unreliable UDP protocol.
+        /// </summary>
+        /// <param name="data">The data.</param>
+        /// <param name="sendOption">The SendOption to attach.</param>
+        void UnreliableSend(byte[] data, byte sendOption)
         {
             byte[] bytes = new byte[data.Length + 1];
 
@@ -161,7 +179,7 @@ namespace Hazel.Udp
                 Buffer.BlockCopy(bytes, 0, actualBytes, 1, bytes.Length);
             }
 
-            HandleSend(actualBytes, (byte)SendOptionInternal.Hello, acknowledgeCallback);
+            HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback);
         }
 
         /// <summary>
@@ -175,7 +193,7 @@ namespace Hazel.Udp
         /// </summary>
         protected void SendDisconnect()
         {
-            HandleSend(new byte[0], (byte)SendOptionInternal.Disconnect);       //TODO Should disconnect wait for an ack?
+            HandleSend(new byte[0], (byte)UdpSendOption.Disconnect);       //TODO Should disconnect wait for an ack?
         }
 
         /// <inheritdoc/>
index 22c3c37bc5a1b0837ed8baaa93860b2171d963bf..5c3c44ce203718069192de2aaf5d2b34be07957f 100644 (file)
@@ -150,7 +150,7 @@ namespace Hazel.Udp
                 else
                 {
                     //Check for malformed connection attempts
-                    if (buffer[0] != (byte)SendOptionInternal.Hello)
+                    if (buffer[0] != (byte)UdpSendOption.Hello)
                         return;
 
                     connection = new UdpServerConnection(this, remoteEndPoint, IPMode);