From: JamJar00 Date: Tue, 31 May 2016 15:47:46 +0000 (+0100) Subject: Big fixes and threadstatic docs X-Git-Tag: 1.0.0~149 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=a9b835d9919d24cb82e361041bc8c473d6760aa7;p=rhonda%2Fimpostor.hazel.git Big fixes and threadstatic docs --- diff --git a/Hazel/ConnectionListener.cs b/Hazel/ConnectionListener.cs index e738f1b..8c4e165 100644 --- a/Hazel/ConnectionListener.cs +++ b/Hazel/ConnectionListener.cs @@ -47,7 +47,7 @@ namespace Hazel /// /// public event EventHandler NewConnection; - //TODO add threadsafe markers on all xmldocs + /// /// Makes this connection listener begin listening for connections. /// diff --git a/Hazel/DataEventArgs.cs b/Hazel/DataEventArgs.cs index 72522a3..1dd3c26 100644 --- a/Hazel/DataEventArgs.cs +++ b/Hazel/DataEventArgs.cs @@ -15,6 +15,7 @@ namespace Hazel /// /// /// + /// public class DataEventArgs : EventArgs, IRecyclable { /// diff --git a/Hazel/DisconnectedEventArgs.cs b/Hazel/DisconnectedEventArgs.cs index 86d26c5..1942244 100644 --- a/Hazel/DisconnectedEventArgs.cs +++ b/Hazel/DisconnectedEventArgs.cs @@ -15,6 +15,7 @@ namespace Hazel /// /// /// + /// public class DisconnectedEventArgs : IRecyclable { /// diff --git a/Hazel/IRecyclable.cs b/Hazel/IRecyclable.cs index 3dd1d4c..8310f25 100644 --- a/Hazel/IRecyclable.cs +++ b/Hazel/IRecyclable.cs @@ -8,6 +8,7 @@ namespace Hazel /// /// Interface for all items that can be returned to an object pool. /// + /// interface IRecyclable { /// diff --git a/Hazel/NetworkConnection.cs b/Hazel/NetworkConnection.cs index 2363a01..18a660e 100644 --- a/Hazel/NetworkConnection.cs +++ b/Hazel/NetworkConnection.cs @@ -10,6 +10,7 @@ namespace Hazel /// /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. /// + /// public abstract class NetworkConnection : Connection { /// diff --git a/Hazel/NetworkConnectionListener.cs b/Hazel/NetworkConnectionListener.cs index 4cb46a4..30be505 100644 --- a/Hazel/NetworkConnectionListener.cs +++ b/Hazel/NetworkConnectionListener.cs @@ -10,6 +10,7 @@ namespace Hazel /// /// Abstract base class for a for network based connections. /// + /// public abstract class NetworkConnectionListener : ConnectionListener { /// diff --git a/Hazel/NetworkEndPoint.cs b/Hazel/NetworkEndPoint.cs index f8b10d3..aa114a3 100644 --- a/Hazel/NetworkEndPoint.cs +++ b/Hazel/NetworkEndPoint.cs @@ -14,6 +14,7 @@ namespace Hazel /// /// This wraps a for connecting across a network using protocols like TCP or UDP. /// + /// public sealed class NetworkEndPoint : ConnectionEndPoint { /// diff --git a/Hazel/NewConnectionEventArgs.cs b/Hazel/NewConnectionEventArgs.cs index 2a01dcd..30ef5be 100644 --- a/Hazel/NewConnectionEventArgs.cs +++ b/Hazel/NewConnectionEventArgs.cs @@ -15,6 +15,7 @@ namespace Hazel /// /// /// + /// public class NewConnectionEventArgs : EventArgs, IRecyclable { /// diff --git a/Hazel/ObjectPool.cs b/Hazel/ObjectPool.cs index a840486..7a410e4 100644 --- a/Hazel/ObjectPool.cs +++ b/Hazel/ObjectPool.cs @@ -11,6 +11,7 @@ namespace Hazel /// A fairly simple object pool for items that will be created a lot. /// /// The type that is pooled. + /// sealed class ObjectPool where T : IRecyclable { /// diff --git a/Hazel/TcpConnection.cs b/Hazel/TcpConnection.cs index 39905d5..db122f4 100644 --- a/Hazel/TcpConnection.cs +++ b/Hazel/TcpConnection.cs @@ -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; diff --git a/Hazel/UdpClientConnection.cs b/Hazel/UdpClientConnection.cs index 5c151d3..7052b73 100644 --- a/Hazel/UdpClientConnection.cs +++ b/Hazel/UdpClientConnection.cs @@ -226,9 +226,13 @@ namespace Hazel /// 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; diff --git a/Hazel/UdpConnection.Reliable.cs b/Hazel/UdpConnection.Reliable.cs index 1469193..3c3cf64 100644 --- a/Hazel/UdpConnection.Reliable.cs +++ b/Hazel/UdpConnection.Reliable.cs @@ -194,7 +194,7 @@ namespace Hazel /// Handles receives from reliable packets. /// /// The buffer containing the data. - /// Whether the bytes were valid or not. + /// Whether the packet was a new packet or not. 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; diff --git a/Hazel/UdpConnection.cs b/Hazel/UdpConnection.cs index 3d5b6c2..8890c92 100644 --- a/Hazel/UdpConnection.cs +++ b/Hazel/UdpConnection.cs @@ -149,20 +149,20 @@ namespace Hazel HandleSend(new byte[0], (byte)SendOptionInternal.Hello, acknowledgeCallback); } - /// - public override void Close() - { - HandleSend(new byte[0], (byte)SendOptionInternal.Disconnect); //TODO Should disconnect wait for an ack? - - base.Close(); - } - /// /// Called when the socket has been disconnected at the remote host. /// /// The exception if one was the cause. protected abstract void HandleDisconnect(HazelException e = null); + /// + /// Sends a disconnect message to the end point. + /// + protected void SendDisconnect() + { + HandleSend(new byte[0], (byte)SendOptionInternal.Disconnect); //TODO Should disconnect wait for an ack? + } + /// protected override void Dispose(bool disposing) { diff --git a/Hazel/UdpConnectionListener.cs b/Hazel/UdpConnectionListener.cs index 284a5fc..0572b61 100644 --- a/Hazel/UdpConnectionListener.cs +++ b/Hazel/UdpConnectionListener.cs @@ -19,6 +19,11 @@ namespace Hazel /// Socket listener; + /// + /// Buffer to store incoming data in. + /// + byte[] dataBuffer = new byte[ushort.MaxValue]; + /// /// The connections we currently hold /// @@ -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. diff --git a/Hazel/UdpServerConnection.cs b/Hazel/UdpServerConnection.cs index 4bbf922..7940913 100644 --- a/Hazel/UdpServerConnection.cs +++ b/Hazel/UdpServerConnection.cs @@ -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);