using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Net; using System.Threading; namespace Hazel { /// /// Base class for all connections. /// /// /// /// Connection is the base class for all connections that Hazel can make. It provides common functionality and a /// standard interface to allow connections to be swapped easily. /// /// /// Any class inheriting from Connection should provide the 3 standard guarantees that Hazel provides: /// /// /// Thread Safe /// /// /// Connection Orientated /// /// /// Packet/Message Based /// /// /// /// /// public abstract class Connection : IDisposable { /// /// Called when a message has been received. /// /// /// /// DataReceived is invoked everytime a message is received from the end point of this connection, the message /// that was received can be found in the alongside other information from the /// event. /// /// /// /// /// /// public event Action DataReceived; public int TestLagMs = -1; public int TestDropRate = 0; protected int testDropCount = 0; /// /// Called when the end point disconnects or an error occurs. /// /// /// /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote /// end point disconnected. If it was invoked due to an exception occuring then the exception is available /// in the passed with the event. /// /// /// /// /// /// public event EventHandler Disconnected; /// /// The remote end point of this Connection. /// /// /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract /// which can then be cast to an appropriate end point depending on the /// connection type. /// public IPEndPoint EndPoint { get; protected set; } public IPMode IPMode { get; protected set; } /// /// The traffic statistics about this Connection. /// /// /// Contains statistics about the number of messages and bytes sent and received by this connection. /// public ConnectionStatistics Statistics { get; protected set; } /// /// The state of this connection. /// /// /// All implementers should be aware that when this is set to ConnectionState.Connected it will /// release all threads that are blocked on . /// public ConnectionState State { get { return this._state; } protected set { this._state = value; this.SetState(value); } } protected ConnectionState _state; protected virtual void SetState(ConnectionState state) { } /// /// Constructor that initializes the ConnecitonStatistics object. /// /// /// This constructor initialises with empty statistics and sets to /// . /// protected Connection() { this.Statistics = new ConnectionStatistics(); this.State = ConnectionState.NotConnected; } /// /// Sends a number of bytes to the end point of the connection using the specified . /// /// The message to send. public abstract SendErrors Send(MessageWriter msg); /// /// Connects the connection to a server and begins listening. /// This method blocks and may thrown if there is a problem connecting. /// /// The bytes of data to send in the handshake. /// The number of milliseconds to wait before giving up on the connect attempt. public abstract void Connect(byte[] bytes = null, int timeout = 5000); /// /// Connects the connection to a server and begins listening. /// This method does not block. /// /// The bytes of data to send in the handshake. public abstract void ConnectAsync(byte[] bytes = null); /// /// Invokes the DataReceived event. /// /// The bytes received. /// The the message was received with. /// /// Invokes the event on this connection to alert subscribers a new message has been /// received. The bytes and the send option that the message was sent with should be passed in to give to the /// subscribers. /// protected void InvokeDataReceived(MessageReader msg, SendOption sendOption) { // Make a copy to avoid race condition between null check and invocation Action handler = DataReceived; if (handler != null) { try { handler(new DataReceivedEventArgs(this, msg, sendOption)); } catch { } } else { msg.Recycle(); } } /// /// Invokes the Disconnected event. /// /// The exception, if any, that occurred to cause this. /// Extra disconnect data /// /// Invokes the event to alert subscribres this connection has been disconnected either /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to /// pass to the subscribers, otherwise null can be passed in. /// protected void InvokeDisconnected(string e, MessageReader reader) { // Make a copy to avoid race condition between null check and invocation EventHandler handler = Disconnected; if (handler != null) { DisconnectedEventArgs args = new DisconnectedEventArgs(e, reader); try { handler(this, args); } catch { } } } /// /// 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. /// public abstract void Disconnect(string reason, MessageWriter writer = null); /// /// Disposes of this NetworkConnection. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Disposes of this NetworkConnection. /// /// Are we currently disposing? protected virtual void Dispose(bool disposing) { if (disposing) { this.DataReceived = null; this.Disconnected = null; } } } }