connection.Connect();
connection.Dispose();
- Thread.Sleep(50);
+ Thread.Sleep(100);
Assert.IsTrue(serverConnected);
Assert.IsTrue(serverDisconnected);
/// </remarks>
public abstract void ConnectAsync(byte[] bytes = null, int timeout = 5000);
- /// <summary>
- /// Sends a disconnect message to the end point.
- /// </summary>
- protected abstract void SendDisconnect();
-
/// <summary>
/// Invokes the DataReceived event.
/// </summary>
/// Invokes the Disconnected event.
/// </summary>
/// <param name="e">The exception, if any, that occured to cause this.</param>
+ /// <param name="reader">Extra disconnect data</param>
/// <remarks>
/// Invokes the <see cref="Disconnected"/> event to alert subscribres this connection has been disconnected either
/// by the end point or because an error occured. If an error occured the error should be passed in in order to
/// pass to the subscribers, otherwise null can be passed in.
/// </remarks>
- protected void InvokeDisconnected(string e)
+ protected void InvokeDisconnected(string e, MessageReader reader)
{
//Make a copy to avoid race condition between null check and invocation
EventHandler<DisconnectedEventArgs> handler = Disconnected;
if (handler != null)
{
- DisconnectedEventArgs args = DisconnectedEventArgs.GetObject();
- args.Set(e);
+ DisconnectedEventArgs args = new DisconnectedEventArgs(e, reader);
handler.Invoke(this, args);
}
}
/// 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>
- public abstract void Disconnect(string reason);
+ public abstract void Disconnect(string reason, MessageWriter writer = null, bool fireEvent = true);
/// <summary>
/// Disposes of this NetworkConnection.
/// The Connection is connected and data can be transfered.
/// </summary>
Connected,
-
- /// <summary>
- /// The Connection is currently disconnecting.
- /// </summary>
- Disconnecting
}
}
/// <threadsafety static="true" instance="true"/>
public class DisconnectedEventArgs : EventArgs
{
- /// <summary>
- /// Returns an instance of this object from the pool.
- /// </summary>
- /// <returns>A new or recycled DisconnectedEventArgs object.</returns>
- internal static DisconnectedEventArgs GetObject()
- {
- return new DisconnectedEventArgs();
- }
-
/// <summary>
/// The exception, if any, that caused the disconnect.
/// </summary>
/// that caused it or a <see cref="HazelException"/> with the details of the exception, if the disconnection
/// wasn't caused by an error then this will contain null.
/// </remarks>
- public string Reason { get; private set; }
+ public readonly string Reason;
- /// <summary>
- /// Private constructor for object pool.
- /// </summary>
- DisconnectedEventArgs()
- {
-
- }
+ public readonly MessageReader Message;
- /// <summary>
- /// Sets the given exception for the arguments.
- /// </summary>
- /// <param name="e">The exception if the cause.</param>
- internal void Set(string reason)
+ public DisconnectedEventArgs(string reason, MessageReader reader)
{
- this.Reason = reason;
+
}
}
}
{
switch (this.SendOption)
{
- case Hazel.SendOption.Reliable:
+ case SendOption.Reliable:
{
byte[] output = new byte[this.Length - 3];
System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3);
return output;
}
- case Hazel.SendOption.None:
+ case SendOption.None:
{
byte[] output = new byte[this.Length - 1];
System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1);
}
}
+ /// <summary>
+ /// Sends a disconnect message to the end point.
+ /// </summary>
+ protected abstract bool SendDisconnect(MessageWriter writer);
+
+
/// <summary>
/// Called when the socket has been disconnected at the remote host.
/// </summary>
/// <param name="e">The exception if one was the cause.</param>
- public override void Disconnect(string reason)
+ public override void Disconnect(string reason, MessageWriter writer = null, bool fireEvent = true)
{
- bool invoke = false;
- lock (this)
- {
- if (this._state == ConnectionState.Connected)
- {
- this._state = ConnectionState.Disconnecting;
- invoke = true;
- }
- }
-
- if (invoke)
+ if (this.SendDisconnect(writer) && fireEvent)
{
try
{
- InvokeDisconnected(reason);
+ InvokeDisconnected(reason, null);
}
catch { }
}
/// <summary>
/// Sends a disconnect message to the end point.
+ /// You may include optional disconnect data. The SendOption must be unreliable.
/// </summary>
- protected override void SendDisconnect()
+ protected override bool SendDisconnect(MessageWriter data = null)
{
+ lock (this)
+ {
+ if (this._state != ConnectionState.Connected) return false;
+ this._state = ConnectionState.NotConnected;
+ }
+
+ var bytes = EmptyDisconnectBytes;
+ if (data != null && data.Length > 0)
+ {
+ if (data.SendOption != SendOption.None) throw new ArgumentException("Disconnect messages can only be unreliable.");
+
+ bytes = data.ToByteArray(true);
+ bytes[0] = (byte)UdpSendOption.Disconnect;
+ }
+
try
{
socket.SendTo(
- DisconnectBytes,
+ bytes,
0,
- 1,
+ bytes.Length,
SocketFlags.None,
RemoteEndPoint);
}
catch { }
+
+ return true;
}
/// <inheritdoc />
{
if (disposing)
{
- if (this._state == ConnectionState.Connected
- || this._state == ConnectionState.Disconnecting)
- {
- this._state = ConnectionState.NotConnected;
- SendDisconnect();
- }
+ SendDisconnect();
}
if (this.socket != null)
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
namespace Hazel.Udp
{
/// <inheritdoc />
public abstract partial class UdpConnection : NetworkConnection
{
- protected static readonly byte[] DisconnectBytes = new byte[] { (byte)UdpSendOption.Disconnect };
+ protected static readonly byte[] EmptyDisconnectBytes = new byte[] { (byte)UdpSendOption.Disconnect };
/// <summary>
/// Creates a new UdpConnection and initializes the keep alive timer.
throw new InvalidOperationException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?");
}
-
/// <summary>
/// Sends a disconnect message to the end point.
/// </summary>
- protected override void SendDisconnect()
+ protected override bool SendDisconnect(MessageWriter data = null)
{
+ lock (this)
+ {
+ if (this._state != ConnectionState.Connected) return false;
+ this._state = ConnectionState.NotConnected;
+ }
+
+ var bytes = EmptyDisconnectBytes;
+ if (data != null && data.Length > 0)
+ {
+ if (data.SendOption != SendOption.None) throw new ArgumentException("Disconnect messages can only be unreliable.");
+
+ bytes = data.ToByteArray(true);
+ bytes[0] = (byte)UdpSendOption.Disconnect;
+ }
+
try
{
- Listener.SendDataSync(DisconnectBytes, 1, RemoteEndPoint);
+ Listener.SendDataSync(bytes, bytes.Length, RemoteEndPoint);
}
catch { }
+
+ return true;
}
protected override void Dispose(bool disposing)
if (disposing)
{
- if (this._state == ConnectionState.Connected
- || this._state == ConnectionState.Disconnecting)
- {
- this._state = ConnectionState.NotConnected;
- SendDisconnect();
- }
+ SendDisconnect();
}