#nullable enable using System; using System.Linq; using System.Net; using System.Net.Sockets; namespace Barotrauma.Networking { sealed class LidgrenAddress : Address { public readonly IPAddress NetAddress; public override string StringRepresentation => NetAddress.ToString(); public override bool IsLocalHost => IPAddress.IsLoopback(NetAddress); public LidgrenAddress(IPAddress netAddress) { if (IPAddress.IsLoopback(netAddress)) { netAddress = IPAddress.Loopback; } if (netAddress.IsIPv4MappedToIPv6) { netAddress = netAddress.MapToIPv4(); } NetAddress = netAddress; } public new static Option Parse(string endpointStr) { if (endpointStr.Equals("localhost", StringComparison.OrdinalIgnoreCase)) { return Option.Some(new LidgrenAddress(IPAddress.Loopback)); } else if (IPAddress.TryParse(endpointStr, out IPAddress? netEndpoint)) { return Option.Some(new LidgrenAddress(netEndpoint!)); } return Option.None(); } public static Option ParseHostName(string endpointStr) { try { var resolvedAddresses = Dns.GetHostAddresses(endpointStr); return resolvedAddresses.Any() ? Option.Some(new LidgrenAddress(resolvedAddresses.First())) : Option.None(); } catch (SocketException) { return Option.None(); } catch (ArgumentOutOfRangeException) { return Option.None(); } } public override bool Equals(object? obj) => obj switch { LidgrenAddress otherAddress => this == otherAddress, _ => false }; public override int GetHashCode() => NetAddress.GetHashCode(); public static bool operator ==(LidgrenAddress a, LidgrenAddress b) { var addressA = a.NetAddress.MapToIPv6(); var addressB = b.NetAddress.MapToIPv6(); if (IPAddress.IsLoopback(addressA) && IPAddress.IsLoopback(addressB)) { return true; } return addressA.Equals(addressB); } public static bool operator !=(LidgrenAddress a, LidgrenAddress b) => !(a == b); } }