Skip to content

Commit

Permalink
Add ToUInt and ToBigInteger conversion methods on ValueIpAddress.
Browse files Browse the repository at this point in the history
  • Loading branch information
enclave-alistair committed Nov 11, 2022
1 parent 6cf7e1b commit 29ce4b3
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public PacketFieldAttribute()
/// to indicate the exact length of the buffer slice returned.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate this size.
/// The start position of all fields following this one will be adjusted to accommodate this size.
/// </para>
/// <para>
/// If you set this on a primitive/numeric field with a return type smaller (in bytes) than the provided size,
Expand Down Expand Up @@ -66,7 +66,7 @@ public PacketFieldAttribute()
/// *before* this one.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by the function.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by the function.
/// </para>
/// </remarks>
public string? SizeFunction { get; set; }
Expand All @@ -79,7 +79,7 @@ public PacketFieldAttribute()
/// The field in question should be a numeric field prior to this field in the byte order.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by that field.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by that field.
/// </para>
/// </remarks>
public string? SizeField { get; set; }
Expand All @@ -92,7 +92,7 @@ public PacketFieldAttribute()
/// In most cases you should avoid using this property; position can usually be automatically determined from the other fields in the packet.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate this size.
/// The start position of all fields following this one will be adjusted to accommodate this size.
/// </para>
/// </remarks>
public int Position { get; set; }
Expand All @@ -111,7 +111,7 @@ public PacketFieldAttribute()
/// </code>
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by the function.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by the function.
/// </para>
/// </remarks>
public string? PositionFunction { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public PacketFieldAttribute()
/// to indicate the exact length of the buffer slice returned.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate this size.
/// The start position of all fields following this one will be adjusted to accommodate this size.
/// </para>
/// <para>
/// If you set this on a primitive/numeric field with a return type smaller (in bytes) than the provided size,
Expand Down Expand Up @@ -66,7 +66,7 @@ public PacketFieldAttribute()
/// *before* this one.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by the function.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by the function.
/// </para>
/// </remarks>
public string? SizeFunction { get; set; }
Expand All @@ -79,7 +79,7 @@ public PacketFieldAttribute()
/// The field in question should be a numeric field prior to this field in the byte order.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by that field.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by that field.
/// </para>
/// </remarks>
public string? SizeField { get; set; }
Expand All @@ -92,7 +92,7 @@ public PacketFieldAttribute()
/// In most cases you should avoid using this property; position can usually be automatically determined from the other fields in the packet.
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate this size.
/// The start position of all fields following this one will be adjusted to accommodate this size.
/// </para>
/// </remarks>
public int Position { get; set; }
Expand All @@ -111,7 +111,7 @@ public PacketFieldAttribute()
/// </code>
/// </para>
/// <para>
/// The start position of all fields following this one will be adjusted to accomodate the size returned by the function.
/// The start position of all fields following this one will be adjusted to accommodate the size returned by the function.
/// </para>
/// </remarks>
public string? PositionFunction { get; set; }
Expand Down
35 changes: 35 additions & 0 deletions src/Enclave.FastPacket/ValueIpAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Buffers.Binary;
using System.Net;
using System.Net.Sockets;
using System.Numerics;

namespace Enclave.FastPacket;

Expand Down Expand Up @@ -216,6 +217,40 @@ public override string ToString()
return ToIpAddress().ToString();
}

/// <summary>
/// Converts an IPv4 address to a unsigned 32-bit integer.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="AddressFamily"/> is <see cref="AddressFamily.InterNetworkV6"/>.</exception>
public uint ToUInt()
{
if (_addrFamily == AddressFamily.InterNetwork)
{
return unchecked((uint)_addr1);
}

throw new InvalidOperationException("Only IPv4 addresses can be converted to a UInt32");
}

/// <summary>
/// Convert this IP address to a big-integer representation.
/// </summary>
public BigInteger ToBigInteger()
{
if (_addrFamily == AddressFamily.InterNetworkV6)
{
Span<byte> destSpan = stackalloc byte[16];

BinaryPrimitives.WriteUInt64BigEndian(destSpan, _addr2);
BinaryPrimitives.WriteUInt64BigEndian(destSpan.Slice(sizeof(ulong)), _addr1);

return new BigInteger(destSpan, isUnsigned: true, isBigEndian: true);
}
else
{
return new BigInteger(_addr1);
}
}

/// <summary>
/// Equals operator.
/// </summary>
Expand Down
27 changes: 27 additions & 0 deletions tests/Enclave.FastPacket.Tests/ValueIpAddressTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using FluentAssertions;
using System;
using System.Net;
using System.Numerics;
using Xunit;

namespace Enclave.FastPacket.Tests;
Expand Down Expand Up @@ -62,6 +64,31 @@ public void EmptyIpv6AddressNotSameAsEmptyIpv4()
valueIpv6.Should().NotBe(valueIpv4);
}

[Theory]
[InlineData("81.152.41.187", 1368926651u)]
[InlineData("100.154.122.4", 1687845380u)]
[InlineData("4.122.154.100", 75143780u)]
public void CanConvertToUInt(string ip, uint expected)
{
Assert.Equal(expected, ValueIpAddress.Create(IPAddress.Parse(ip)).ToUInt());
}

[Fact]
public void CannotConvertIpv6ToUInt()
{
Assert.Throws<InvalidOperationException>(() => ValueIpAddress.Create(IPAddress.Parse("2001:db8:3333:4444:5555:6666:7777:8889")).ToUInt());
}

[Fact]
public void CanConvertToBigInt()
{
var ip = ValueIpAddress.Create(IPAddress.Parse("2001:db8:3333:4444:5555:6666:7777:8889"));

var expected = BigInteger.Parse("42540766427128305956041295149173016713");

Assert.Equal(expected, ip.ToBigInteger());
}

[Theory]
[InlineData("100.1.1.1", "101.1.1.1")]
[InlineData("1.255.255.255", "2.0.0.0")]
Expand Down

0 comments on commit 29ce4b3

Please sign in to comment.