]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Big fixes and threadstatic docs
authorJamJar00 <jamster.30@btinternet.com>
Tue, 31 May 2016 15:47:46 +0000 (16:47 +0100)
committerJamJar00 <jamster.30@btinternet.com>
Tue, 31 May 2016 15:47:46 +0000 (16:47 +0100)
15 files changed:
Hazel/ConnectionListener.cs
Hazel/DataEventArgs.cs
Hazel/DisconnectedEventArgs.cs
Hazel/IRecyclable.cs
Hazel/NetworkConnection.cs
Hazel/NetworkConnectionListener.cs
Hazel/NetworkEndPoint.cs
Hazel/NewConnectionEventArgs.cs
Hazel/ObjectPool.cs
Hazel/TcpConnection.cs
Hazel/UdpClientConnection.cs
Hazel/UdpConnection.Reliable.cs
Hazel/UdpConnection.cs
Hazel/UdpConnectionListener.cs
Hazel/UdpServerConnection.cs

index e738f1bfb81722714e265e0427a56caf5d2d9c5f..8c4e165cd194356e3fab359d8f3f90286e2fd836 100644 (file)
@@ -47,7 +47,7 @@ namespace Hazel
         ///     <code language="C#" source="DocInclude/TcpListenerExample.cs"/>
         /// </example>
         public event EventHandler<NewConnectionEventArgs> NewConnection;
-        //TODO add threadsafe markers on all xmldocs
+
         /// <summary>
         ///     Makes this connection listener begin listening for connections.
         /// </summary>
index 72522a39457f0fd43c2157258783fdd11fe14f3b..1dd3c26e9067f2c955db49e7c62ed91a5ef872a5 100644 (file)
@@ -15,6 +15,7 @@ namespace Hazel
     ///     </para>
     ///     <include file="DocInclude/common.xml" path="docs/item[@name='Recyclable']/*" />
     /// </remarks>
+    /// <threadsafety static="true" instance="true"/>
     public class DataEventArgs : EventArgs, IRecyclable
     {
         /// <summary>
index 86d26c5b43b7b443ecea06054fc4027af2c75db0..19422449ceeb0520c424cf2a1a3396c8a3147f80 100644 (file)
@@ -15,6 +15,7 @@ namespace Hazel
     ///     </para>
     ///     <include file="DocInclude/common.xml" path="docs/item[@name='Recyclable']/*" />
     /// </remarks>
+    /// <threadsafety static="true" instance="true"/>
     public class DisconnectedEventArgs : IRecyclable
     {
         /// <summary>
index 3dd1d4c352cad76c92acdb2fe6722cc76b17daca..8310f25a1b58ea3430b872065668f1d08dd69f24 100644 (file)
@@ -8,6 +8,7 @@ namespace Hazel
     /// <summary>
     ///     Interface for all items that can be returned to an object pool.
     /// </summary>
+    /// <threadsafety static="true" instance="true"/>
     interface IRecyclable
     {
         /// <summary>
index 2363a015ce24fa303b7a810cd7c5d0e8d006bab0..18a660e4e060c64fce2a6d9a8b9cac6878e383fc 100644 (file)
@@ -10,6 +10,7 @@ namespace Hazel
     /// <summary>
     ///     Abstract base class for a <see cref="Connection"/> to a remote end point via a network protocol like TCP or UDP.
     /// </summary>
+    /// <threadsafety static="true" instance="true"/>
     public abstract class NetworkConnection : Connection
     {
         /// <summary>
index 4cb46a4bd7abd4bd7be49cac4f5da93601801dd4..30be50540297803e9da0bb363f3f0df3750fa189 100644 (file)
@@ -10,6 +10,7 @@ namespace Hazel
     /// <summary>
     ///     Abstract base class for a <see cref="ConnectionListener"/> for network based connections.
     /// </summary>
+    /// <threadsafety static="true" instance="true"/>
     public abstract class NetworkConnectionListener : ConnectionListener
     {
         /// <summary>
index f8b10d3890b94d992a2f9767da3282ed5f115fb9..aa114a3c390ba3e67ca751ff892e75e6d0b74d66 100644 (file)
@@ -14,6 +14,7 @@ namespace Hazel
     /// <remarks>
     ///     This wraps a <see cref="System.Net.EndPoint"/> for connecting across a network using protocols like TCP or UDP.
     /// </remarks>
+    /// <threadsafety static="true" instance="true"/>
     public sealed class NetworkEndPoint : ConnectionEndPoint
     {
         /// <summary>
index 2a01dcd08148980aad11325a2fb2f506013f3187..30ef5bedfbf383c59213fedba900323c74d1c35e 100644 (file)
@@ -15,6 +15,7 @@ namespace Hazel
     ///     </para>
     ///     <include file="DocInclude/common.xml" path="docs/item[@name='Recyclable']/*" />
     /// </remarks>
+    /// <threadsafety static="true" instance="true"/>
     public class NewConnectionEventArgs : EventArgs, IRecyclable
     {
         /// <summary>
index a840486c2aa1beba09308fd50477ba7a58a3ebd1..7a410e41f8a41960c1c5e9dfefd6d5d38a6c9c85 100644 (file)
@@ -11,6 +11,7 @@ namespace Hazel
     ///     A fairly simple object pool for items that will be created a lot.
     /// </summary>
     /// <typeparam name="T">The type that is pooled.</typeparam>
+    /// <threadsafety static="true" instance="true"/>
     sealed class ObjectPool<T> where T : IRecyclable
     {
         /// <summary>
index 39905d516e75140a4152c5be45a6bc6e159cca71..db122f405a0b057a6abbcdafb34f03225872b8b8 100644 (file)
@@ -248,6 +248,11 @@ namespace Hazel
                 //If the socket's been disposed then we can just end there.
                 return;
             }
+            catch (SocketException e)
+            {
+                HandleDisconnect(new HazelException("A Socket exception occured while initiating a receive operation.", e));
+                return;
+            }
 
             StateObject state = (StateObject)result.AsyncState;
 
index 5c151d315c85b2861de29f089b458a0661be6adf..7052b73deeb2fb57dcf149083803a21f06c16bcb 100644 (file)
@@ -226,9 +226,13 @@ namespace Hazel
         /// <inheritdoc />
         protected override void Dispose(bool disposing)
         {
-            //Dispose of the socket
             if (disposing)
             {
+                //Send disconnect message if we're not already disconnecting
+                if (State == ConnectionState.Connected)
+                    SendDisconnect();
+
+                //Dispose of the socket
                 lock (socketLock)
                 {
                     State = ConnectionState.NotConnected;
index 146919396064bfccb86ee1ae351c4ad4b0b2d344..3c3cf64607936c55498ca8add5b101919c00f971 100644 (file)
@@ -194,7 +194,7 @@ namespace Hazel
         ///     Handles receives from reliable packets.
         /// </summary>
         /// <param name="bytes">The buffer containing the data.</param>
-        /// <returns>Whether the bytes were valid or not.</returns>
+        /// <returns>Whether the packet was a new packet or not.</returns>
         bool HandleReliableReceive(byte[] bytes)
         {
             //Get the ID form the packet
@@ -203,26 +203,45 @@ namespace Hazel
             //Send an acknowledgement
             SendAck(bytes[1], bytes[2]);
 
-            //Handle reliableness!
+            /*
+             * It gets a little complicated here (note the fact I'm actually using a multiline comment for once...)
+             * 
+             * In a simple world if our data is greater than the last reliable packet received (reliableReceiveLast)
+             * then it is guaranteed to be a new packet, if it's not we can see if we are missing that packet (lookup 
+             * in reliableDataPacketsMissing).
+             * 
+             * --------rrl#############             (1)
+             * 
+             * (where --- are packets received already and #### are packets that will be counted as new)
+             * 
+             * Unfortunately if id becomes greater than 65535 it will loop back to zero so we will add a pointer that
+             * specifies any packets with an id behind it are also new (overwritePointer).
+             * 
+             * ####op----------rrl#####             (2)
+             * 
+             * ------rll#########op----             (3)
+             * 
+             * Anything behind than the reliableReceiveLast pointer (but greater than the overwritePointer is either a 
+             * missing packet or something we've already received so when we change the pointers we need to make sure 
+             * we keep note of what hasn't been received yet (reliableDataPacketsMissing).
+             * 
+             * So...
+             */
+            
             lock (reliableDataPacketsMissing)
             {
-                //TODO Looping of IDs
-                //      Currently when ID loops all packets will be discarded as ID will be less than reliableReceiveLast
-                //      And wont be in reliableDataPacketsMissing.
+                //Calculate overwritePointer
+                ushort overwritePointer = (ushort)(reliableReceiveLast - 32768);
 
-                //If the ID <= reliableReceiveLast it might be something we're missing
-                //HasReceivedSomething handles the edge case of reliableReceiveLast = 0 & ID = 0
-                if (id <= reliableReceiveLast && hasReceivedSomething)
-                {
-                    //See if we're missing it, else this packet is a duplicate
-                    if (reliableDataPacketsMissing.Contains(id))
-                        reliableDataPacketsMissing.Remove(id);
-                    else
-                        return false;
-                }
-                
-                //If ID > reliableReceiveLast then it's something new
+                //Calculate if it is a new packet by examining if it is within the range
+                bool isNew;
+                if (overwritePointer < reliableReceiveLast)
+                    isNew = id > reliableReceiveLast || id <= overwritePointer;     //Figure (2)
                 else
+                    isNew = id > reliableReceiveLast && id <= overwritePointer;     //Figure (3)
+                
+                //If it's new or we've not received anything yet
+                if (isNew || !hasReceivedSomething)
                 {
                     //Mark items between the most recent receive and the id received as missing
                     for (ushort i = (ushort)(reliableReceiveLast + 1); i < id; i++)
@@ -232,6 +251,16 @@ namespace Hazel
                     reliableReceiveLast = id;
                     hasReceivedSomething = true;
                 }
+                
+                //Else it could be a missing packet
+                else
+                {
+                    //See if we're missing it, else this packet is a duplicate as so we return false
+                    if (reliableDataPacketsMissing.Contains(id))
+                        reliableDataPacketsMissing.Remove(id);
+                    else
+                        return false;
+                }
             }
 
             return true;
index 3d5b6c22bcd20005e47b0800a766651d5e1448c9..8890c92a9a4b1a9d24cbc89cb9d66f74faa7a7d7 100644 (file)
@@ -149,20 +149,20 @@ namespace Hazel
             HandleSend(new byte[0], (byte)SendOptionInternal.Hello, acknowledgeCallback);
         }
 
-        /// <inheritdoc/>
-        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>
+        ///     Sends a disconnect message to the end point.
+        /// </summary>
+        protected void SendDisconnect()
+        {
+            HandleSend(new byte[0], (byte)SendOptionInternal.Disconnect);       //TODO Should disconnect wait for an ack?
+        }
+
         /// <inheritdoc/>
         protected override void Dispose(bool disposing)
         {
index 284a5fc4a9735fccd2dc2a7d8e4976afd0d67c93..0572b616cc6e2b4236c1b1d8254ef11a37989196 100644 (file)
@@ -19,6 +19,11 @@ namespace Hazel
         /// </summary>
         Socket listener;
 
+        /// <summary>
+        ///     Buffer to store incoming data in.
+        /// </summary>
+        byte[] dataBuffer = new byte[ushort.MaxValue];
+
         /// <summary>
         ///     The connections we currently hold
         /// </summary>
@@ -66,8 +71,7 @@ namespace Hazel
         void StartListeningForData()
         {
             EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
-            byte[] dataBuffer = new byte[ushort.MaxValue];
-
+            
             try
             {
                 lock (listener)
@@ -91,7 +95,7 @@ namespace Hazel
             //End the receive operation
             try
             {
-                lock (listener) //TODO how does this stop when the client disconnects?
+                lock (listener)
                     bytesReceived = listener.EndReceiveFrom(result, ref remoteEndPoint);
             }
             catch (ObjectDisposedException)
@@ -99,10 +103,11 @@ namespace Hazel
                 //If the socket's been disposed then we can just end there.
                 return;
             }
-            catch (SocketException)
+            catch (SocketException e)
             {
-                //TODO Errr...;
-                return;
+                //Errrr... shit...
+                //Not exactly much we can do if we've got here
+                throw e;
             }
 
             //Exit if no bytes read, we've closed.
index 4bbf922a0dac65a53ec4e5e05ae81e75a1acf2da..79409136e4a40f5cd0e86d8f663b4834e135fc00 100644 (file)
@@ -105,6 +105,10 @@ namespace Hazel
             //Here we just need to inform the listener we no longer need data.
             if (disposing)
             {
+                //Send disconnect message if we're not already disconnecting
+                if (State == ConnectionState.Connected)
+                    SendDisconnect();
+
                 lock (stateLock)
                 {
                     Listener.RemoveConnectionTo(RemoteEndPoint);