public Action<DataReceivedEventArgs> DataReceived;
public int TestLagMs = -1;
-
+
public event Action<byte[], int> DataSentRaw;
protected void InvokeDataSentRaw(byte[] data, int length)
{
/// Connections go round 4 states in their lifetime: they start as <see cref="ConnectionState.NotConnected"/> to
/// indicate they have no endpoint, calling <see cref="Connect"/> takes them into
/// <see cref="ConnectionState.Connecting"/>, once they have received confirmation they are connected they enter
- /// <see cref="ConnectionState.Connected"/> and finally calling <see cref="Close"/> sets them to
+ /// <see cref="ConnectionState.Connected"/> and finally calling <see cref="Dispose"/> sets them to
/// <see cref="ConnectionState.Disconnecting"/> and then the sequence repeats back to
/// <see cref="ConnectionState.NotConnected"/> once disconnection is complete.
/// </para>
protected set
{
- state = value;
- if (state == ConnectionState.Connected)
+ this.state = value;
+ if (this.state == ConnectionState.Connected)
connectWaitLock.Set();
else
connectWaitLock.Reset();
/// </remarks>
protected Connection()
{
- Statistics = new ConnectionStatistics();
-
- State = ConnectionState.NotConnected;
+ this.Statistics = new ConnectionStatistics();
+ this.State = ConnectionState.NotConnected;
}
/// <summary>
/// <summary>
/// Sends a disconnect message to the end point.
/// </summary>
- public abstract void SendDisconnect();
+ protected abstract void SendDisconnect();
/// <summary>
/// Invokes the DataReceived event.
}
/// <summary>
- /// Closes this connection safely.
+ /// For times when you want to force the disconnect handler to fire as well as close it.
+ /// If you only want to close it, just use Dispose.
/// </summary>
- /// <remarks>
- /// <para>
- /// Informs the end point of the connection that we are disconnecting from them and disposes of this
- /// connection.
- /// </para>
- /// <para>
- /// This calls <see cref="Dispose()"/> and therefore sets <see cref="State"/> straight to
- /// <see cref="ConnectionState.NotConnected"/>. Once you call Close you will not be able to send any more
- /// data using this connection and no more data will be received.
- /// </para>
- /// </remarks>
- public virtual void Close()
- {
- Dispose();
- }
-
+ public abstract void Disconnect(string reason);
+
/// <summary>
/// Disposes of this NetworkConnection.
/// </summary>
}
catch (ObjectDisposedException)
{
- HandleDisconnect("Could not send as the socket was disposed of.");
+ Disconnect("Could not send as the socket was disposed of.");
}
catch (SocketException)
{
- HandleDisconnect("Could not send data as a SocketException occured.");
+ Disconnect("Could not send data as a SocketException occured.");
}
},
null
}
catch (SocketException)
{
- HandleDisconnect("Could not send data as a SocketException occured.");
+ Disconnect("Could not send data as a SocketException occured.");
+ throw;
+ }
+ }
+
+ protected override void WriteBytesToConnectionSync(byte[] bytes, int length)
+ {
+ InvokeDataSentRaw(bytes, length);
+
+ 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
+ {
+ socket.SendTo(
+ bytes,
+ 0,
+ length,
+ SocketFlags.None,
+ RemoteEndPoint);
+ }
+ catch (ObjectDisposedException)
+ {
+ //User probably called Disconnect in between this method starting and here so report the issue
+ throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?");
+ }
+ catch (SocketException)
+ {
+ Disconnect("Could not send data as a SocketException occured.");
throw;
}
}
}
catch (SocketException e)
{
- HandleDisconnect("A socket exception occured while reading data.");
+ Disconnect("Socket exception while reading data: " + e.Message);
return;
}
//Exit if no bytes read, we've failed.
if (bytesReceived == 0)
{
- HandleDisconnect("Recieved 0 bytes");
+ Disconnect("Received 0 bytes");
return;
}
}
catch (SocketException e)
{
- HandleDisconnect("A Socket exception occured while initiating a receive operation.");
+ Disconnect("Socket exception during receive: " + e.Message);
}
catch (ObjectDisposedException)
{
HandleReceive(msg, bytesReceived);
}
- /// <inheritdoc />
- protected override void HandleDisconnect(string e)
- {
- if (State == ConnectionState.Connected)
- {
- State = ConnectionState.Disconnecting;
-
- try
- {
- InvokeDisconnected(e);
- }
- catch { }
- }
-
- Dispose();
- }
-
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (disposing)
{
- //Send disconnect message if we're not already disconnecting
- if (State == ConnectionState.Connected)
+ if (this.state == ConnectionState.Connected
+ || this.state == ConnectionState.Disconnecting)
{
- State = ConnectionState.NotConnected;
- try
- {
- SendDisconnect();
- }
- catch { }
+ SendDisconnect();
+ this.state = ConnectionState.NotConnected;
}
}
- if (socket != null)
+ if (this.socket != null)
{
- socket.Close();
- socket.Dispose();
- socket = null;
+ this.socket.Close();
+ this.socket.Dispose();
+ this.socket = null;
}
this.reliablePacketTimer.Dispose();
/// </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) =>
+ keepAliveTimer = new Timer(
+ (o) =>
+ {
+ try
{
- try
- {
- ReliableSend((byte)UdpSendOption.Ping);
- Interlocked.Increment(ref KeepAlivesSent);
- }
- catch
- {
- Trace.WriteLine("Keepalive packet failed to send.");
- DisposeKeepAliveTimer();
- }
- },
- null,
- keepAliveInterval,
- keepAliveInterval
- );
- }
+ ReliableSend((byte)UdpSendOption.Ping);
+ Interlocked.Increment(ref KeepAlivesSent);
+ }
+ catch
+ {
+ Trace.WriteLine("Keepalive packet failed to send.");
+ DisposeKeepAliveTimer();
+ }
+ },
+ null,
+ keepAliveInterval,
+ keepAliveInterval
+ );
}
/// <summary>
/// </summary>
void ResetKeepAliveTimer()
{
- lock (keepAliveTimerLock)
+ try
{
keepAliveTimer.Change(keepAliveInterval, keepAliveInterval);
}
+ catch { }
}
/// <summary>
/// </summary>
void DisposeKeepAliveTimer()
{
- lock (keepAliveTimerLock)
+ var timer = this.keepAliveTimer;
+ if (timer != null)
{
- if (keepAliveTimer != null)
- {
- keepAliveTimer.Dispose();
- keepAliveTimer = null;
- }
+ this.keepAliveTimer = null;
+ timer.Dispose();
}
}
}
public int ResendTimeout { get { return resendTimeout; } set { resendTimeout = value; } }
private volatile int resendTimeout = 0;
+ public volatile int ResendLimit = 0;
+
+ public volatile float ResendPingMultiplier = 3;
+
/// <summary>
/// Holds the last ID allocated.
/// </summary>
/// connection will be marked as disconnected and the <see cref="Connection.Disconnected">Disconnected</see> event
/// will be invoked.
/// </remarks>
- public int DisconnectTimeout { get { return disconnectTimeout; } set { disconnectTimeout = value; } }
- private volatile int disconnectTimeout = 2500;
+ public volatile int DisconnectTimeout = 2500;
/// <summary>
/// Class to hold packet data
}
public ushort Id;
- public byte[] Data;
+ private byte[] Data;
+ private UdpConnection Connection;
+ private int Length;
- public DateTime LastSend;
- public int LastTimeout;
+ public volatile int NextTimeout;
public volatile bool Acknowledged;
- private Func<Packet, int> ResendAction;
public Action AckCallback;
public volatile int Retransmissions;
{
}
- internal void Set(ushort id, byte[] data, Func<Packet, int> resendAction, int timeout, Action ackCallback)
+ internal void Set(ushort id, UdpConnection connection, byte[] data, int length, int timeout, Action ackCallback)
{
this.Id = id;
this.Data = data;
+ this.Connection = connection;
+ this.Length = length;
this.Acknowledged = false;
- this.LastSend = DateTime.Now;
- this.LastTimeout = timeout;
- this.ResendAction = resendAction;
- AckCallback = ackCallback;
- Retransmissions = 0;
+ this.NextTimeout = timeout;
+ this.AckCallback = ackCallback;
+ this.Retransmissions = 0;
- Stopwatch.Restart();
+ this.Stopwatch.Restart();
}
// Packets resent
public int Resend()
{
- var evt = this.ResendAction;
- if (!this.Acknowledged)
+ var connection = this.Connection;
+ if (!this.Acknowledged && connection != null)
{
- if (evt != null)
+ long lifetime = this.Stopwatch.ElapsedMilliseconds;
+ if (lifetime >= connection.DisconnectTimeout)
{
- return evt(this);
+ if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self))
+ {
+ connection.Disconnect($"Reliable packet {self.Id} was not ack'd after {lifetime}ms");
+
+ self.Recycle();
+ }
+
+ return 0;
+ }
+
+ if (lifetime >= this.NextTimeout)
+ {
+ if (++this.Retransmissions > connection.ResendLimit)
+ {
+ if (connection.reliableDataPacketsSent.TryRemove(this.Id, out Packet self))
+ {
+ connection.Disconnect($"Reliable packet {self.Id} was not ack'd after {self.Retransmissions} resends");
+
+ self.Recycle();
+ }
+
+ return 0;
+ }
+
+ this.NextTimeout = (int)Math.Min(this.NextTimeout * 3f, connection.DisconnectTimeout);
+ try
+ {
+ connection.WriteBytesToConnection(this.Data, this.Length);
+ return 1;
+ }
+ catch (InvalidOperationException)
+ {
+ //No longer connected
+ connection.Disconnect("Could not resend data as connection is no longer connected");
+ }
}
}
public void Recycle()
{
this.Acknowledged = true;
+ this.Connection = null;
PacketPool.PutObject(this);
}
foreach (var kvp in this.reliableDataPacketsSent)
{
Packet pkt = kvp.Value;
- double timeSinceLast = (DateTime.Now - pkt.LastSend).TotalMilliseconds;
- if (timeSinceLast >= pkt.LastTimeout)
- {
+
try
{
output += pkt.Resend();
}
catch { }
- }
- minTimeout = Math.Min(pkt.LastTimeout, minTimeout);
+ minTimeout = Math.Min(pkt.NextTimeout, minTimeout);
}
}
id = (ushort)Interlocked.Increment(ref lastIDAllocated);
- if (!reliableDataPacketsSent.TryAdd(id, packet))
- {
- throw new Exception("That shouldn't be possible");
- }
-
- int timeout = resendTimeout > 0 ? resendTimeout : (int)Math.Max(50, Math.Min(AveragePingMs * 2, 1000));
-
- //Write ID
buffer[offset] = (byte)((id >> 8) & 0xFF);
buffer[offset + 1] = (byte)id;
packet.Set(
id,
+ this,
buffer,
- (Packet p) =>
- {
- // Callback for a previous packet
- if (p.Acknowledged) return 0;
-
- p.LastSend = DateTime.Now;
- p.LastTimeout = (int)Math.Min(p.LastTimeout * 1.5f, 3000);
-
- Packet self;
- if (p.Stopwatch.ElapsedMilliseconds > this.disconnectTimeout)
- {
- if (reliableDataPacketsSent.TryRemove(p.Id, out self))
- {
- HandleDisconnect($"Reliable packet {self.Id} was not ack'd after {self.Retransmissions} resends");
-
- self.Recycle();
- }
-
- return 0;
- }
-
-
- try
- {
- WriteBytesToConnection(p.Data, sendLength);
- p.Retransmissions++;
- return 1;
- }
- catch (InvalidOperationException)
- {
- //No longer connected
- HandleDisconnect("Could not resend data as connection is no longer connected");
- }
-
- return 0;
- },
- timeout,
+ sendLength,
+ resendTimeout > 0 ? resendTimeout : (int)Math.Max(300, Math.Min(AveragePingMs * this.ResendPingMultiplier, 2000)),
ackCallback
);
+
+ if (!reliableDataPacketsSent.TryAdd(id, packet))
+ {
+ throw new Exception("That shouldn't be possible");
+ }
}
/// <summary>
/// </summary>
/// <param name="bytes">The bytes to write.</param>
protected abstract void WriteBytesToConnection(byte[] bytes, int length);
-
+
+ /// <summary>
+ /// Writes the given bytes to the connection synchronously.
+ /// </summary>
+ /// <param name="bytes">The bytes to write.</param>
+ protected abstract void WriteBytesToConnectionSync(byte[] bytes, int length);
+
/// <inheritdoc/>
public override void Send(MessageWriter msg)
{
break;
case (byte)UdpSendOption.Disconnect:
- HandleDisconnect("The remote sent a disconnect request");
+ Disconnect("The remote sent a disconnect request");
message.Recycle();
break;
/// 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(string reason);
+ public override void Disconnect(string reason)
+ {
+ bool invoke = false;
+ lock (this)
+ {
+ if (this.state == ConnectionState.Connected)
+ {
+ this.state = ConnectionState.Disconnecting;
+ invoke = true;
+ }
+ }
+
+ if (invoke)
+ {
+ try
+ {
+ InvokeDisconnected(reason);
+ }
+ catch { }
+ }
+
+ this.Dispose();
+ }
/// <summary>
/// Sends a disconnect message to the end point.
/// </summary>
- public override void SendDisconnect()
+ protected override void SendDisconnect()
{
- WriteBytesToConnection(new byte[] { (byte)UdpSendOption.Disconnect }, 1);
+ try
+ {
+ WriteBytesToConnectionSync(new byte[] { (byte)UdpSendOption.Disconnect }, 1);
+ }
+ catch { }
}
/// <inheritdoc/>
/// <summary>
/// The socket listening for connections.
/// </summary>
- Socket listener;
-
+ Socket socket;
+
+ private Action<string> Logger;
+
Timer reliablePacketTimer;
/// <summary>
/// Creates a new UdpConnectionListener for the given <see cref="IPAddress"/>, port and <see cref="IPMode"/>.
/// </summary>
/// <param name="endPoint">The endpoint to listen on.</param>
- public UdpConnectionListener(NetworkEndPoint endPoint)
+ public UdpConnectionListener(NetworkEndPoint endPoint, Action<string> logger = null)
{
+ this.Logger = logger;
this.EndPoint = endPoint.EndPoint;
this.IPMode = endPoint.IPMode;
if (endPoint.IPMode == IPMode.IPv4)
- this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
else
{
if (!Socket.OSSupportsIPv6)
throw new HazelException("IPV6 not supported!");
- this.listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
- this.listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
+ this.socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
+ this.socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
}
reliablePacketTimer = new Timer(ManageReliablePackets, null, 100, Timeout.Infinite);
foreach (var kvp in this.allConnections)
{
var sock = kvp.Value;
- PacketsResent += sock.ManageReliablePackets(state);
+ Interlocked.Add(ref PacketsResent, sock.ManageReliablePackets(state));
KeepAlives += Interlocked.Exchange(ref sock.KeepAlivesSent, 0);
DuplicateRecieves += Interlocked.Exchange(ref sock.DuplicateRecieves, 0);
}
{
try
{
- listener.Bind(EndPoint);
+ socket.Bind(EndPoint);
}
catch (SocketException e)
{
{
message = MessageReader.GetSized(BufferSize);
- listener.BeginReceiveFrom(message.Buffer, 0, message.Buffer.Length, SocketFlags.None, ref remoteEP, ReadCallback, message);
+ socket.BeginReceiveFrom(message.Buffer, 0, message.Buffer.Length, SocketFlags.None, ref remoteEP, ReadCallback, message);
Interlocked.Increment(ref ActiveListeners);
}
catch (ObjectDisposedException)
public int ActiveListeners;
public int ActiveCallbacks;
+
void ReadCallback(IAsyncResult result)
{
- var message = (MessageReader)result.AsyncState;
Interlocked.Increment(ref ActiveCallbacks);
+ Interlocked.Decrement(ref ActiveListeners);
- int bytesReceived;
- EndPoint remoteEndPoint = new IPEndPoint(IPMode == IPMode.IPv4 ? IPAddress.Any : IPAddress.IPv6Any, 0);
-
- //End the receive operation
try
{
- Interlocked.Decrement(ref ActiveListeners);
- bytesReceived = listener.EndReceiveFrom(result, ref remoteEndPoint);
- Interlocked.Add(ref BytesReceived, bytesReceived);
-
- message.Offset = 0;
- message.Length = bytesReceived;
- }
- catch (NullReferenceException)
- {
- return;
- }
- catch (ObjectDisposedException)
- {
- //If the socket's been disposed then we can just end there.
- return;
- }
- catch (SocketException)
- {
- // Client no longer reachable, pretend it didn't happen
- // TODO should this not inform the connection this client is lost???
+ var message = (MessageReader)result.AsyncState;
+ int bytesReceived;
+ EndPoint remoteEndPoint = new IPEndPoint(IPMode == IPMode.IPv4 ? IPAddress.Any : IPAddress.IPv6Any, 0);
- // This thread suggests the IP is not passed out from WinSoc so maybe not possible
- // http://stackoverflow.com/questions/2576926/python-socket-error-on-udp-data-receive-10054
- message.Recycle();
+ //End the receive operation
+ try
+ {
+ bytesReceived = socket.EndReceiveFrom(result, ref remoteEndPoint);
+ Interlocked.Add(ref BytesReceived, bytesReceived);
- UdpServerConnection dead;
- if (this.allConnections.TryRemove(remoteEndPoint, out dead))
+ message.Offset = 0;
+ message.Length = bytesReceived;
+ }
+ catch (NullReferenceException)
+ {
+ return;
+ }
+ catch (ObjectDisposedException)
{
- dead.Dispose();
+ //If the socket's been disposed then we can just end there.
+ return;
}
+ catch (SocketException)
+ {
+ // Client no longer reachable, pretend it didn't happen
+ // TODO should this not inform the connection this client is lost???
- StartListeningForData();
- return;
- }
+ // This thread suggests the IP is not passed out from WinSoc so maybe not possible
+ // http://stackoverflow.com/questions/2576926/python-socket-error-on-udp-data-receive-10054
+ message.Recycle();
- // Exit if no bytes read, we've closed.
- if (bytesReceived == 0)
- {
- message.Recycle();
- return;
- }
+ UdpServerConnection dead;
+ if (this.allConnections.TryRemove(remoteEndPoint, out dead))
+ {
+ dead.Dispose();
+ }
- //Begin receiving again
- StartListeningForData();
+ StartListeningForData();
+ return;
+ }
- bool aware = true;
- bool hasHelloByte = message.Buffer[0] == (byte)UdpSendOption.Hello;
- bool isHello = hasHelloByte && message.Length >= MinConnectionLength;
+ // Exit if no bytes read, we've closed.
+ if (bytesReceived == 0)
+ {
+ message.Recycle();
+ return;
+ }
- //If we're aware of this connection use the one already
- //If this is a new client then connect with them!
- UdpServerConnection connection;
- if (!this.allConnections.TryGetValue(remoteEndPoint, out connection))
- {
- lock (this.allConnections)
+ //Begin receiving again
+ StartListeningForData();
+
+ bool aware = true;
+ bool hasHelloByte = message.Buffer[0] == (byte)UdpSendOption.Hello;
+ bool isHello = hasHelloByte && message.Length >= MinConnectionLength;
+
+ //If we're aware of this connection use the one already
+ //If this is a new client then connect with them!
+ UdpServerConnection connection;
+ if (!this.allConnections.TryGetValue(remoteEndPoint, out connection))
{
- aware = this.allConnections.TryGetValue(remoteEndPoint, out connection);
- if (!aware)
+ //Check for malformed connection attempts
+ if (!isHello)
{
- //Check for malformed connection attempts
- if (!isHello)
- {
- Interlocked.Decrement(ref ActiveCallbacks);
- message.Recycle();
- return;
- }
+ message.Recycle();
+ return;
+ }
- connection = new UdpServerConnection(this, remoteEndPoint, this.IPMode);
- if (!this.allConnections.TryAdd(remoteEndPoint, connection))
+ lock (this.allConnections)
+ {
+ aware = this.allConnections.TryGetValue(remoteEndPoint, out connection);
+ if (!aware)
{
- throw new Exception();
+ connection = new UdpServerConnection(this, remoteEndPoint, this.IPMode);
+ if (!this.allConnections.TryAdd(remoteEndPoint, connection))
+ {
+ throw new Exception();
+ }
}
}
}
- }
- //Inform the connection of the buffer (new connections need to send an ack back to client)
- connection.HandleReceive(message, bytesReceived);
+ var stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ try
+ {
+ //Inform the connection of the buffer (new connections need to send an ack back to client)
+ connection.HandleReceive(message, bytesReceived);
+ }
+ finally
+ {
+ var el = stopwatch.ElapsedMilliseconds;
+ if (el > 5)
+ {
+ this.Logger?.Invoke($"Long Packet {el}ms = {string.Join(" ", message.Buffer.Take(bytesReceived))}");
+ }
+ }
- //If it's a new connection invoke the NewConnection event.
- if (!aware)
- {
- // Skip header and hello byte;
- message.Offset = 4;
- message.Length = bytesReceived - 4;
- message.Position = 0;
- InvokeNewConnection(message, connection);
+ //If it's a new connection invoke the NewConnection event.
+ if (!aware)
+ {
+ // Skip header and hello byte;
+ message.Offset = 4;
+ message.Length = bytesReceived - 4;
+ message.Position = 0;
+ InvokeNewConnection(message, connection);
+ }
+ else if (isHello || (!isHello && hasHelloByte))
+ {
+ message.Recycle();
+ }
}
- else if (isHello || (!isHello && hasHelloByte))
+ finally
{
- message.Recycle();
+ Interlocked.Decrement(ref ActiveCallbacks);
}
-
- Interlocked.Decrement(ref ActiveCallbacks);
}
+ public int TestDropRate = -1;
+ private int dropCounter = 0;
+
/// <summary>
/// Sends data from the listener socket.
/// </summary>
if (length > bytes.Length) return;
Interlocked.Add(ref BytesSent, length);
+ if (TestDropRate > 0)
+ {
+ if (Interlocked.Increment(ref dropCounter) % TestDropRate == 0)
+ {
+ return;
+ }
+ }
+
try
{
- listener.BeginSendTo(
+ socket.BeginSendTo(
bytes,
0,
length,
{
try
{
- listener.EndSendTo(result);
+ socket.EndSendTo(result);
}
catch { }
},
{
try
{
- listener.SendTo(
+ socket.SendTo(
bytes,
0,
length,
kvp.Value.Dispose();
}
- if (listener != null)
+ if (this.socket != null)
{
- listener.Close();
- this.listener.Dispose();
- this.listener = null;
+ this.socket.Close();
+ this.socket.Dispose();
+ this.socket = null;
}
this.reliablePacketTimer.Dispose();
/// <summary>
/// Lock object for the writing to the state of the connection.
/// </summary>
- Object stateLock = new Object();
+ private ReaderWriterLockSlim stateLock = new ReaderWriterLockSlim();
/// <summary>
/// Creates a UdpConnection for the virtual connection to the endpoint.
{
InvokeDataSentRaw(bytes, length);
- lock (stateLock)
- {
- if (State != ConnectionState.Connected)
- throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?");
- }
+ if (State != ConnectionState.Connected)
+ throw new InvalidOperationException("Could not send data: Not connected.");
Listener.SendData(bytes, length, RemoteEndPoint);
}
+ /// <inheritdoc />
+ protected override void WriteBytesToConnectionSync(byte[] bytes, int length)
+ {
+ InvokeDataSentRaw(bytes, length);
+
+ // No throw: As an internal interface, I want to try sending bytes whenever the I feel like it.
+
+ Listener.SendDataSync(bytes, length, RemoteEndPoint);
+ }
+
/// <inheritdoc />
/// <remarks>
/// This will always throw a HazelException.
{
throw new HazelException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?");
}
-
- /// <inheritdoc />
- protected override void HandleDisconnect(string reason)
- {
- 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)
- {
- try
- {
- InvokeDisconnected(reason);
- }
- catch { }
-
- Dispose();
- }
- }
-
- /// <inheritdoc />
+
protected override void Dispose(bool disposing)
{
- //Here we just need to inform the listener we no longer need data.
+ Listener.RemoveConnectionTo(RemoteEndPoint);
+
if (disposing)
{
- // Send disconnect message if we're not already disconnecting
- if (this.state == ConnectionState.Connected)
+ if (this.state == ConnectionState.Connected
+ || this.state == ConnectionState.Disconnecting)
{
- try
- {
- SendDisconnect();
- }
- catch { }
- this.state = ConnectionState.Disconnecting;
+ SendDisconnect();
+ this.state = ConnectionState.NotConnected;
}
-
- Listener.RemoveConnectionTo(RemoteEndPoint);
-
}
base.Dispose(disposing);