using System; using System.Net; using System.Threading.Tasks; using Impostor.Api.Net.Messages; namespace Impostor.Hazel { public enum HazelInternalErrors { SocketExceptionSend, SocketExceptionReceive, ReceivedZeroBytes, PingsWithoutResponse, ReliablePacketWithoutResponse, ConnectionDisconnected } /// /// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. /// /// public abstract class NetworkConnection : Connection { /// /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. /// public Func OnInternalDisconnect; /// /// The remote end point of this connection. /// /// /// This is the end point of the other device given as an rather than a generic /// as the base does. /// public IPEndPoint RemoteEndPoint { get; protected set; } public long GetIP4Address() { if (IPMode == IPMode.IPv4) { return ((IPEndPoint)this.RemoteEndPoint).Address.Address; } else { var bytes = ((IPEndPoint)this.RemoteEndPoint).Address.GetAddressBytes(); return BitConverter.ToInt64(bytes, bytes.Length - 8); } } /// /// Sends a disconnect message to the end point. /// protected abstract ValueTask SendDisconnect(MessageWriter writer); /// /// Called when the socket has been disconnected at the remote host. /// protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) { if (await SendDisconnect(null)) { try { await InvokeDisconnected(reason, reader); } catch { } } this.Dispose(); } /// /// Called when socket is disconnected internally /// internal async ValueTask DisconnectInternal(HazelInternalErrors error, string reason) { var handler = this.OnInternalDisconnect; if (handler != null) { MessageWriter messageToRemote = handler(error); if (messageToRemote != null) { try { await Disconnect(reason, messageToRemote); } finally { messageToRemote.Recycle(); } } else { await Disconnect(reason); } } else { await Disconnect(reason); } } /// /// Called when the socket has been disconnected locally. /// public override async ValueTask Disconnect(string reason, MessageWriter writer = null) { if (await SendDisconnect(writer)) { try { await InvokeDisconnected(reason, null); } catch { } } this.Dispose(); } } }