Refactor address classes
This commit is contained in:
parent
d7ccd3069f
commit
912945a142
11 changed files with 199 additions and 92 deletions
35
src/IPMeow.Lib/Address/IPv4Address.cs
Normal file
35
src/IPMeow.Lib/Address/IPv4Address.cs
Normal file
|
@ -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);
|
||||
}
|
30
src/IPMeow.Lib/Address/IPv6Address.cs
Normal file
30
src/IPMeow.Lib/Address/IPv6Address.cs
Normal file
|
@ -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);
|
||||
}
|
104
src/IPMeow.Lib/Address/MacAddress.cs
Normal file
104
src/IPMeow.Lib/Address/MacAddress.cs
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
10
src/IPMeow.Lib/Address/Network.cs
Normal file
10
src/IPMeow.Lib/Address/Network.cs
Normal file
|
@ -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);
|
||||
};
|
|
@ -1,8 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib;
|
||||
|
||||
public class BitEnumerator
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
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; }
|
10
src/IPMeow.Lib/Host/HostEntry.cs
Normal file
10
src/IPMeow.Lib/Host/HostEntry.cs
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
{
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue