From 912945a142adca344abcae4db154ef59b7f41624 Mon Sep 17 00:00:00 2001 From: femsci Date: Wed, 3 May 2023 13:11:27 +0200 Subject: [PATCH] Refactor address classes --- src/IPMeow.Lib/Address/IPv4Address.cs | 35 +++++++++ src/IPMeow.Lib/Address/IPv6Address.cs | 30 +++++++ src/IPMeow.Lib/Address/MacAddress.cs | 104 +++++++++++++++++++++++++ src/IPMeow.Lib/Address/Network.cs | 10 +++ src/IPMeow.Lib/BitEnumerator.cs | 5 -- src/IPMeow.Lib/{ => Host}/Host.cs | 12 ++- src/IPMeow.Lib/Host/HostEntry.cs | 10 +++ src/IPMeow.Lib/{ => Host}/IBindable.cs | 7 +- src/IPMeow.Lib/HostEntry.cs | 14 ---- src/IPMeow.Lib/MacAddress.cs | 58 -------------- test/IPMeow.Test/StructTests.cs | 6 +- 11 files changed, 199 insertions(+), 92 deletions(-) create mode 100644 src/IPMeow.Lib/Address/IPv4Address.cs create mode 100644 src/IPMeow.Lib/Address/IPv6Address.cs create mode 100644 src/IPMeow.Lib/Address/MacAddress.cs create mode 100644 src/IPMeow.Lib/Address/Network.cs rename src/IPMeow.Lib/{ => Host}/Host.cs (57%) create mode 100644 src/IPMeow.Lib/Host/HostEntry.cs rename src/IPMeow.Lib/{ => Host}/IBindable.cs (58%) delete mode 100644 src/IPMeow.Lib/HostEntry.cs delete mode 100644 src/IPMeow.Lib/MacAddress.cs diff --git a/src/IPMeow.Lib/Address/IPv4Address.cs b/src/IPMeow.Lib/Address/IPv4Address.cs new file mode 100644 index 0000000..8cecac6 --- /dev/null +++ b/src/IPMeow.Lib/Address/IPv4Address.cs @@ -0,0 +1,35 @@ +using System.Net; +using System.Net.Sockets; + +namespace IPMeow.Lib.Address; + +public class IPv4Address +{ + public IPv4Address(byte[] bytes) + { + if (bytes.Length != 4) + { + throw new ArgumentException("Invalid byte length."); + } + + _addr = BitConverter.ToUInt32(bytes); + } + + public IPv4Address(long address) + { + _addr = (uint)address; + } + + public IPv4Address(IPAddress address) + { + if (address.AddressFamily != AddressFamily.InterNetwork) + { + throw new ArgumentException($"Invalid address type: {address.AddressFamily}. Expected IPv4."); + } + + _addr = BitConverter.ToUInt32(address.GetAddressBytes()); + } + + private readonly uint _addr; + public static implicit operator IPAddress(IPv4Address addr) => new(addr._addr); +} diff --git a/src/IPMeow.Lib/Address/IPv6Address.cs b/src/IPMeow.Lib/Address/IPv6Address.cs new file mode 100644 index 0000000..837d605 --- /dev/null +++ b/src/IPMeow.Lib/Address/IPv6Address.cs @@ -0,0 +1,30 @@ +using System.Net; +using System.Net.Sockets; + +namespace IPMeow.Lib.Address; + +public class IPv6Address +{ + public IPv6Address(byte[] address) + { + if (address.Length != 16) + { + throw new ArgumentException("Invalid address. Expected 16 bytes."); + } + + _addr = address; + } + + public IPv6Address(IPAddress address) + { + if (address.AddressFamily != AddressFamily.InterNetworkV6) + { + throw new ArgumentException($"Invalid address type: {address.AddressFamily}. Expected IPv6."); + } + + _addr = address.GetAddressBytes(); + } + + private readonly byte[] _addr; + public static implicit operator IPAddress(IPv6Address addr) => new(addr._addr); +} diff --git a/src/IPMeow.Lib/Address/MacAddress.cs b/src/IPMeow.Lib/Address/MacAddress.cs new file mode 100644 index 0000000..d01e2f4 --- /dev/null +++ b/src/IPMeow.Lib/Address/MacAddress.cs @@ -0,0 +1,104 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace IPMeow.Lib.Address; + +public readonly struct MacAddress +{ + public MacAddress(byte[] addr) + { + if (addr.Length != 6) + { + throw new ArgumentException("Invalid address bytes."); + } + + addrBytes = addr; + } + + public static MacAddress Parse(byte[] addr) + { + if (TryParse(addr, out MacAddress? mac)) + { + return mac.Value; + } + + throw new ArgumentException("Invalid address byte length. Expected 6 octets."); + } + + public static MacAddress Parse(string addr) + { + if (TryParse(addr, out MacAddress? mac)) + { + return mac.Value; + } + + throw new FormatException("Invalid address format."); + } + + public static bool TryParse(byte[] addr, [NotNullWhen(true)] out MacAddress? mac) + { + mac = null; + + if (addr.Length != 6) + { + return false; + } + + mac = new(addr); + + return true; + } + + public static bool TryParse(string addr, [NotNullWhen(true)] out MacAddress? mac) + { + mac = null; + + string[] bytes = addr.Split(":"); + + if (bytes.Length != 6) + { + throw new ArgumentException("Invalid address length. Expected 6 octets."); + } + + var addrBytes = bytes.Select(byteStr => + { + if (byte.TryParse(byteStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byte b)) + { + return b; + } + + throw new ArgumentException($"{byteStr} is not a valid hex byte."); + }).ToArray(); + + mac = new(addrBytes); + + return true; + } + + private readonly byte[] addrBytes; + + public override readonly bool Equals([NotNullWhen(true)] object? obj) + { + return obj is MacAddress addr && this.addrBytes.SequenceEqual(addr.addrBytes); + } + + public static bool operator ==(MacAddress a, MacAddress b) + { + return a.addrBytes.SequenceEqual(b.addrBytes); + } + + public static bool operator !=(MacAddress a, MacAddress b) + { + return !(a == b); + } + + public override readonly string ToString() + { + return string.Join(':', addrBytes.Select(b => b.ToString("x2"))); + } + + public override int GetHashCode() + { + return addrBytes.GetHashCode(); + } +} diff --git a/src/IPMeow.Lib/Address/Network.cs b/src/IPMeow.Lib/Address/Network.cs new file mode 100644 index 0000000..59f8613 --- /dev/null +++ b/src/IPMeow.Lib/Address/Network.cs @@ -0,0 +1,10 @@ +using System.Net; + +namespace IPMeow.Lib.Address; + +public abstract class Network +{ + public abstract bool IsInNetwork(IPAddress addr); + + public abstract bool IsSubnetOf(Network n); +}; diff --git a/src/IPMeow.Lib/BitEnumerator.cs b/src/IPMeow.Lib/BitEnumerator.cs index 5a56dfc..0fe95d4 100644 --- a/src/IPMeow.Lib/BitEnumerator.cs +++ b/src/IPMeow.Lib/BitEnumerator.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace IPMeow.Lib; public class BitEnumerator diff --git a/src/IPMeow.Lib/Host.cs b/src/IPMeow.Lib/Host/Host.cs similarity index 57% rename from src/IPMeow.Lib/Host.cs rename to src/IPMeow.Lib/Host/Host.cs index d5f2312..f450c47 100644 --- a/src/IPMeow.Lib/Host.cs +++ b/src/IPMeow.Lib/Host/Host.cs @@ -1,16 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.ComponentModel.DataAnnotations; using System.Net.NetworkInformation; -using System.Threading.Tasks; +using IPMeow.Lib.Address; -namespace IPMeow.Lib; +namespace IPMeow.Lib.Host; public class Host : IBindable { + [Key] public required string Id { get; set; } - public DateTime? LastPing { get; set; } public required IPAddressCollection Addresses { get; set; } -public required MacAddress Mac { get; set; } + public required MacAddress Mac { get; set; } } diff --git a/src/IPMeow.Lib/Host/HostEntry.cs b/src/IPMeow.Lib/Host/HostEntry.cs new file mode 100644 index 0000000..97e07a0 --- /dev/null +++ b/src/IPMeow.Lib/Host/HostEntry.cs @@ -0,0 +1,10 @@ +using System.Net; + +namespace IPMeow.Lib.Host; + +public class HostEntry +{ + public string? Name { get; set; } + public required IPAddress Address { get; set; } + public int Priority { get; set; } = 0; +} diff --git a/src/IPMeow.Lib/IBindable.cs b/src/IPMeow.Lib/Host/IBindable.cs similarity index 58% rename from src/IPMeow.Lib/IBindable.cs rename to src/IPMeow.Lib/Host/IBindable.cs index 7003e2b..12dc1e5 100644 --- a/src/IPMeow.Lib/IBindable.cs +++ b/src/IPMeow.Lib/Host/IBindable.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Net.NetworkInformation; -using System.Threading.Tasks; +using IPMeow.Lib.Address; -namespace IPMeow.Lib; +namespace IPMeow.Lib.Host; public interface IBindable { diff --git a/src/IPMeow.Lib/HostEntry.cs b/src/IPMeow.Lib/HostEntry.cs deleted file mode 100644 index e6754cf..0000000 --- a/src/IPMeow.Lib/HostEntry.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; - -namespace IPMeow.Lib; - -public class HostEntry -{ - public string? Name { get; set; } - public required IPAddress Address { get; set; } -public int Priority { get; set; } = 0; -} diff --git a/src/IPMeow.Lib/MacAddress.cs b/src/IPMeow.Lib/MacAddress.cs deleted file mode 100644 index f890eb5..0000000 --- a/src/IPMeow.Lib/MacAddress.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; - -namespace IPMeow.Lib; - -public readonly struct MacAddress -{ - public MacAddress(byte[] addr) - { - if (addr.Length != 6) - { - throw new ArgumentException("Invalid address bytes."); - } - - addrBytes = addr; - } - - public MacAddress(string addr) - { - string[] bytes = addr.Split(":"); - - if (bytes.Length != 6) - { - throw new ArgumentException("Invalid format."); - } - - addrBytes = bytes.Select(byteStr => - { - if (byte.TryParse(byteStr, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out byte b)) - { - return b; - } - - throw new ArgumentException($"{byteStr} is not a valid hex byte."); - }).ToArray(); - } - - private readonly byte[] addrBytes; - - public override readonly bool Equals([NotNullWhen(true)] object? obj) - { - return obj is MacAddress addr && this.addrBytes.SequenceEqual(addr.addrBytes); - } - - public override readonly string ToString() - { - return string.Join(':', addrBytes.Select(b => b.ToString("x2"))); - } - - public override int GetHashCode() - { - return addrBytes.GetHashCode(); - } -} diff --git a/test/IPMeow.Test/StructTests.cs b/test/IPMeow.Test/StructTests.cs index c551957..b4579ed 100644 --- a/test/IPMeow.Test/StructTests.cs +++ b/test/IPMeow.Test/StructTests.cs @@ -1,5 +1,5 @@ using IPMeow.Lib; -using Xunit; +using IPMeow.Lib.Address; namespace IPMeow.Test; @@ -8,8 +8,8 @@ public class StructTests [Fact] public void MacAddressSerializationTest() { - var addrFromString = new MacAddress("fe:ed:de:ad:be:ef"); - var addrFromBytes = new MacAddress(new byte[] { 0xfe, 0xed, 0xde, 0xad, 0xbe, 0xef }); + var addrFromString = MacAddress.Parse("fe:ed:de:ad:be:ef"); + var addrFromBytes = MacAddress.Parse(new byte[] { 0xfe, 0xed, 0xde, 0xad, 0xbe, 0xef }); Assert.Equal(addrFromString, addrFromBytes);