diff options
Diffstat (limited to 'Impostor-dev/src/Impostor.Hazel/NetworkConnection.cs')
-rw-r--r-- | Impostor-dev/src/Impostor.Hazel/NetworkConnection.cs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Impostor-dev/src/Impostor.Hazel/NetworkConnection.cs b/Impostor-dev/src/Impostor.Hazel/NetworkConnection.cs new file mode 100644 index 0000000..282fe10 --- /dev/null +++ b/Impostor-dev/src/Impostor.Hazel/NetworkConnection.cs @@ -0,0 +1,121 @@ +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 + } + + /// <summary> + /// Abstract base class for a <see cref="Connection"/> to a remote end point via a network protocol like TCP or UDP. + /// </summary> + /// <threadsafety static="true" instance="true"/> + public abstract class NetworkConnection : Connection + { + /// <summary> + /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect happens. + /// </summary> + public Func<HazelInternalErrors, MessageWriter> OnInternalDisconnect; + + /// <summary> + /// The remote end point of this connection. + /// </summary> + /// <remarks> + /// This is the end point of the other device given as an <see cref="System.Net.EndPoint"/> rather than a generic + /// <see cref="ConnectionEndPoint"/> as the base <see cref="Connection"/> does. + /// </remarks> + 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); + } + } + + /// <summary> + /// Sends a disconnect message to the end point. + /// </summary> + protected abstract ValueTask<bool> SendDisconnect(MessageWriter writer); + + /// <summary> + /// Called when the socket has been disconnected at the remote host. + /// </summary> + protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) + { + if (await SendDisconnect(null)) + { + try + { + await InvokeDisconnected(reason, reader); + } + catch { } + } + + this.Dispose(); + } + + /// <summary> + /// Called when socket is disconnected internally + /// </summary> + 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); + } + } + + /// <summary> + /// Called when the socket has been disconnected locally. + /// </summary> + public override async ValueTask Disconnect(string reason, MessageWriter writer = null) + { + if (await SendDisconnect(writer)) + { + try + { + await InvokeDisconnected(reason, null); + } + catch { } + } + + this.Dispose(); + } + } +} |