From c180082fb42a170c58597f23195332b830931bf0 Mon Sep 17 00:00:00 2001 From: Cory Charlton Date: Wed, 15 Nov 2023 09:58:35 -0800 Subject: [PATCH 01/13] Added `==` and `!=` operator overloads --- nanoFramework.System.Net/IPAddress.cs | 96 +++++++++++++++---- .../Properties/AssemblyInfo.cs | 2 +- 2 files changed, 78 insertions(+), 20 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index ff3b20f..5fb7410 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -4,6 +4,7 @@ // See LICENSE file in the project root for full license information. // +using System.Collections; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.CompilerServices; @@ -19,12 +20,38 @@ public class IPAddress /// /// Provides an IP address that indicates that the server must listen for client activity on all network interfaces. This field is read-only. /// - public static readonly IPAddress Any = new(0x0000000000000000); + /// + /// The method uses the field to indicate that a instance must listen for client activity on all network interfaces. + /// + /// The field is equivalent to 0.0.0.0 in dotted-quad notation. + /// + public static readonly IPAddress Any = new(new byte[] { 0, 0, 0, 0 }); /// /// Provides the IP loopback address. This field is read-only. /// - public static readonly IPAddress Loopback = new(0x000000000100007F); + /// + /// The field is equivalent to 127.0.0.1 in dotted-quad notation. + /// + public static readonly IPAddress Loopback = new(new byte[] { 127, 0, 0, 1 }); + + /// + /// Provides the IP broadcast address. This field is read-only. + /// + /// + /// The field is equivalent to 255.255.255.255 in dotted-quad notation. + /// + public static readonly IPAddress Broadcast = new(new byte[] { 255, 255, 255, 255 }); + + /// + /// Provides an IP address that indicates that no network interface should be used. This field is read-only. + /// + /// + /// The uses the field to indicate that a must not listen for client activity. + /// + /// The field is equivalent to 255.255.255.255 in dotted-quad notation. + /// + public static readonly IPAddress None = Broadcast; internal readonly long Address; @@ -39,6 +66,11 @@ public class IPAddress internal const int NumberOfLabels = IPv6AddressBytes / 2; + /// + /// A lazily initialized cache of the value. + /// + private int _hashCode; + /// /// Gets the address family of the IP address. /// @@ -122,6 +154,16 @@ public IPAddress(byte[] address) } } + /// + /// Tests whether two objects are the same. + /// + public static bool operator ==(IPAddress left, IPAddress right) => left is not null && left.Equals(right); + + /// + /// Tests whether two objects differ in location or size. + /// + public static bool operator !=(IPAddress left, IPAddress right) => !(left == right); + /// /// Compares two IP addresses. /// @@ -129,11 +171,28 @@ public IPAddress(byte[] address) /// public override bool Equals(object obj) { - IPAddress addr = obj as IPAddress; + return obj is IPAddress other && Equals(other); + } - if (obj == null) return false; + /// + /// Compares two IP addresses. + /// + /// An instance to compare to the current instance. + /// + public bool Equals(IPAddress other) + { + if (other is null) + { + return false; + } - return this.Address == addr.Address; + // Compare families before address representations + if (AddressFamily != other.AddressFamily) + { + return false; + } + + return Address == other.Address; } /// @@ -142,7 +201,7 @@ public override bool Equals(object obj) /// A Byte array. public byte[] GetAddressBytes() { - return new byte[] + return new[] { (byte)(Address), (byte)(Address >> 8), @@ -207,18 +266,21 @@ public static IPAddress GetDefaultLocalAddress() /// public override int GetHashCode() { - // For IPv6 addresses, we cannot simply return the integer - // representation as the hashcode. Instead, we calculate - // the hashcode from the string representation of the address. - if (_family == AddressFamily.InterNetworkV6) - { - return ToString().GetHashCode(); - } - else + if (_hashCode == 0) { + // For IPv6 addresses, we cannot simply return the integer + // representation as the hashcode. Instead, we calculate + // the hashcode from the string representation of the address. + if (_family == AddressFamily.InterNetworkV6) + { + _hashCode = ToString().GetHashCode(); + } + // For IPv4 addresses, we can simply use the integer representation. - return unchecked((int)Address); + _hashCode = unchecked((int)Address); } + + return _hashCode; } // For security, we need to be able to take an IPAddress and make a copy that's immutable and not derived. @@ -236,11 +298,7 @@ internal IPAddress Snapshot() throw new NotSupportedException(); } - #region native methods - [MethodImpl(MethodImplOptions.InternalCall)] internal static extern string IPv4ToString(uint ipv4Address); - - #endregion } } diff --git a/nanoFramework.System.Net/Properties/AssemblyInfo.cs b/nanoFramework.System.Net/Properties/AssemblyInfo.cs index 3642cc8..2202180 100644 --- a/nanoFramework.System.Net/Properties/AssemblyInfo.cs +++ b/nanoFramework.System.Net/Properties/AssemblyInfo.cs @@ -11,7 +11,7 @@ //////////////////////////////////////////////////////////////// // update this whenever the native assembly signature changes // -[assembly: AssemblyNativeVersion("100.1.5.0")] +[assembly: AssemblyNativeVersion("100.1.5.1")] //////////////////////////////////////////////////////////////// // Setting ComVisible to false makes the types in this assembly not visible From cf8078aff6abec5ab7e073f95ca73bb0d40c07c4 Mon Sep 17 00:00:00 2001 From: Cory Charlton Date: Wed, 15 Nov 2023 14:28:28 -0800 Subject: [PATCH 02/13] Unit tests --- Tests/IPAddressTests/IPAddressTests.cs | 21 ++++++++++++++++++++- Tests/IPAddressTests/nano.runsettings | 8 +++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Tests/IPAddressTests/IPAddressTests.cs b/Tests/IPAddressTests/IPAddressTests.cs index f89b18e..dc8a7db 100644 --- a/Tests/IPAddressTests/IPAddressTests.cs +++ b/Tests/IPAddressTests/IPAddressTests.cs @@ -16,7 +16,7 @@ namespace NFUnitTestIPAddress public class IPAddressTests { [Setup] - public void SetupConnectToEthernetTests() + public void Setup() { // Comment next line to run the tests on a real hardware Assert.SkipTest("Skipping tests using nanoCLR Win32 in a pipeline"); @@ -301,5 +301,24 @@ public void NetTest6_SocketAddressBasic() + " as " + socketAddress2.ToString() + " " + socketAddress2.GetHashCode()); } } + + [TestMethod] + public void Equality_Tests() + { + var privateAddress = new IPAddress(new byte[] { 192, 168, 0, 1 }); + var publicAddress = new IPAddress(new byte[] { 1, 1, 1, 1 }); + + // Equal + Assert.IsTrue(privateAddress.Equals(new IPAddress(new byte[]{192, 168, 0 , 1})), "192.168.0.1 equals 192.168.0.1"); + Assert.IsTrue(publicAddress.Equals(new IPAddress(new byte[] { 1, 1, 1, 1 })), "1.1.1.1 equals 1.1.1.1"); + Assert.IsTrue(privateAddress == new IPAddress(new byte[] { 192, 168, 0, 1 }), "192.168.0.1 == 192.168.0.1"); + Assert.IsTrue(publicAddress == new IPAddress(new byte[] { 1, 1, 1, 1 }), "1.1.1.1 == 1.1.1.1"); + + // Not Equal + Assert.IsFalse(privateAddress.Equals(new IPAddress(new byte[] { 192, 168, 0, 2 })), "192.168.0.1 not equals 192.168.0.2"); + Assert.IsFalse(publicAddress.Equals(new IPAddress(new byte[] { 1, 1, 1, 2 })), "1.1.1.1 not equals 1.1.1.2"); + Assert.IsTrue(privateAddress != new IPAddress(new byte[] { 192, 168, 0, 2 }), "192.168.0.1 == 192.168.0.2"); + Assert.IsTrue(publicAddress != new IPAddress(new byte[] { 1, 1, 1, 2 }), "1.1.1.1 == 1.1.1.2"); + } } } diff --git a/Tests/IPAddressTests/nano.runsettings b/Tests/IPAddressTests/nano.runsettings index e82b99e..93ce85e 100644 --- a/Tests/IPAddressTests/nano.runsettings +++ b/Tests/IPAddressTests/nano.runsettings @@ -2,14 +2,16 @@ - 1 .\TestResults 120000 net48 x64 - None - False + None + False + COM3 + + \ No newline at end of file From 445f784de249e118d0b362b1712a30925b295f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:02:01 +0000 Subject: [PATCH 03/13] Renaming param to match .NET --- nanoFramework.System.Net/IPAddress.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index 5fb7410..b1d39b2 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -167,11 +167,10 @@ public IPAddress(byte[] address) /// /// Compares two IP addresses. /// - /// An instance to compare to the current instance. - /// - public override bool Equals(object obj) + /// An instance to compare to the current instance. + public override bool Equals(object comparand) { - return obj is IPAddress other && Equals(other); + return comparand is IPAddress other && Equals(other); } /// From f6b42bd445639e44c08a783009687fdf6c915448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:02:41 +0000 Subject: [PATCH 04/13] Add missing comment for return value --- nanoFramework.System.Net/IPAddress.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index b1d39b2..343407a 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -168,6 +168,7 @@ public IPAddress(byte[] address) /// Compares two IP addresses. /// /// An instance to compare to the current instance. + /// if the two addresses are equal; otherwise, . public override bool Equals(object comparand) { return comparand is IPAddress other && Equals(other); From 228811d448af808c5e3edfb6c9301f96838495a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:05:55 +0000 Subject: [PATCH 05/13] Renaming param to match .NET doc --- nanoFramework.System.Net/IPAddress.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index 343407a..14d4d33 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -177,22 +177,22 @@ public override bool Equals(object comparand) /// /// Compares two IP addresses. /// - /// An instance to compare to the current instance. - /// - public bool Equals(IPAddress other) + /// An instance to compare to the current instance. + /// if the two addresses are equal; otherwise, . + public bool Equals(IPAddress comparand) { - if (other is null) + if (comparand is null) { return false; } // Compare families before address representations - if (AddressFamily != other.AddressFamily) + if (AddressFamily != comparand.AddressFamily) { return false; } - return Address == other.Address; + return Address == comparand.Address; } /// From 512ac45c28fc1ce0bca3780835b3901f23ab66ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:06:26 +0000 Subject: [PATCH 06/13] Fix Intelisense comment --- nanoFramework.System.Net/IPAddress.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index 14d4d33..8f8a4f7 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -196,9 +196,9 @@ public bool Equals(IPAddress comparand) } /// - /// Provides a copy of the as an array of bytes. + /// Provides a copy of the as an array of bytes in network order. /// - /// A Byte array. + /// A array. public byte[] GetAddressBytes() { return new[] From 72b644a213adba43d72af8b66b11c043c27b8e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:13:59 +0000 Subject: [PATCH 07/13] Update test project file --- Tests/IPAddressTests/IPAddressTests.nfproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/IPAddressTests/IPAddressTests.nfproj b/Tests/IPAddressTests/IPAddressTests.nfproj index aa2f4ef..fea9537 100644 --- a/Tests/IPAddressTests/IPAddressTests.nfproj +++ b/Tests/IPAddressTests/IPAddressTests.nfproj @@ -61,6 +61,9 @@ + + + From 1168157b4ce3178f5b8349188c1c6d88c5b97a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 00:16:30 +0000 Subject: [PATCH 08/13] Remove unused using --- nanoFramework.System.Net/IPAddress.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index 8f8a4f7..d7bc1d2 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -4,7 +4,6 @@ // See LICENSE file in the project root for full license information. // -using System.Collections; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.CompilerServices; @@ -158,7 +157,7 @@ public IPAddress(byte[] address) /// Tests whether two objects are the same. /// public static bool operator ==(IPAddress left, IPAddress right) => left is not null && left.Equals(right); - + /// /// Tests whether two objects differ in location or size. /// From b329880ed1ea5833ef35ed91c95d3da0560c9760 Mon Sep 17 00:00:00 2001 From: Cory Charlton Date: Wed, 15 Nov 2023 16:56:40 -0800 Subject: [PATCH 09/13] Updating tests --- Tests/IPAddressTests/IPAddressTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/IPAddressTests/IPAddressTests.cs b/Tests/IPAddressTests/IPAddressTests.cs index dc8a7db..dcbec9e 100644 --- a/Tests/IPAddressTests/IPAddressTests.cs +++ b/Tests/IPAddressTests/IPAddressTests.cs @@ -305,18 +305,18 @@ public void NetTest6_SocketAddressBasic() [TestMethod] public void Equality_Tests() { - var privateAddress = new IPAddress(new byte[] { 192, 168, 0, 1 }); - var publicAddress = new IPAddress(new byte[] { 1, 1, 1, 1 }); + var privateAddress = IPAddress.Parse("192.168.0.1"); + var publicAddress = IPAddress.Parse("1.1.1.1"); // Equal - Assert.IsTrue(privateAddress.Equals(new IPAddress(new byte[]{192, 168, 0 , 1})), "192.168.0.1 equals 192.168.0.1"); - Assert.IsTrue(publicAddress.Equals(new IPAddress(new byte[] { 1, 1, 1, 1 })), "1.1.1.1 equals 1.1.1.1"); + Assert.AreEqual(privateAddress, IPAddress.Parse("192.168.0.1")); + Assert.AreEqual(publicAddress, IPAddress.Parse("1.1.1.1")); Assert.IsTrue(privateAddress == new IPAddress(new byte[] { 192, 168, 0, 1 }), "192.168.0.1 == 192.168.0.1"); Assert.IsTrue(publicAddress == new IPAddress(new byte[] { 1, 1, 1, 1 }), "1.1.1.1 == 1.1.1.1"); // Not Equal - Assert.IsFalse(privateAddress.Equals(new IPAddress(new byte[] { 192, 168, 0, 2 })), "192.168.0.1 not equals 192.168.0.2"); - Assert.IsFalse(publicAddress.Equals(new IPAddress(new byte[] { 1, 1, 1, 2 })), "1.1.1.1 not equals 1.1.1.2"); + Assert.AreNotEqual(privateAddress, IPAddress.Parse("1.1.1.1")); + Assert.AreNotEqual(publicAddress, IPAddress.Parse("192.168.0.1")); Assert.IsTrue(privateAddress != new IPAddress(new byte[] { 192, 168, 0, 2 }), "192.168.0.1 == 192.168.0.2"); Assert.IsTrue(publicAddress != new IPAddress(new byte[] { 1, 1, 1, 2 }), "1.1.1.1 == 1.1.1.2"); } From b98a5434158e3a9ea81041f796a6987f8bc34fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 16 Nov 2023 01:02:07 +0000 Subject: [PATCH 10/13] Improve Intelisense comments to equality operators - Also rename params to match .NET implementation. --- nanoFramework.System.Net/IPAddress.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index d7bc1d2..7bf71e5 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -154,14 +154,20 @@ public IPAddress(byte[] address) } /// - /// Tests whether two objects are the same. + /// Indicates whether two objects are equal. /// - public static bool operator ==(IPAddress left, IPAddress right) => left is not null && left.Equals(right); + /// The to compare with . + /// The to compare with . + /// if is equal to ; otherwise, . + public static bool operator ==(IPAddress a, IPAddress b) => a is not null && a.Equals(b); /// - /// Tests whether two objects differ in location or size. + /// Indicates whether two objects are not equal. /// - public static bool operator !=(IPAddress left, IPAddress right) => !(left == right); + /// The to compare with . + /// The to compare with . + /// if is not equal to ; otherwise, . + public static bool operator !=(IPAddress a, IPAddress b) => !(a == b); /// /// Compares two IP addresses. From d8f175c1d07f65b9ef343b5a94b79533782f1711 Mon Sep 17 00:00:00 2001 From: Cory Charlton Date: Wed, 15 Nov 2023 19:07:34 -0800 Subject: [PATCH 11/13] Removing hash code caching --- nanoFramework.System.Net/IPAddress.cs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/nanoFramework.System.Net/IPAddress.cs b/nanoFramework.System.Net/IPAddress.cs index 7bf71e5..57806f2 100644 --- a/nanoFramework.System.Net/IPAddress.cs +++ b/nanoFramework.System.Net/IPAddress.cs @@ -65,11 +65,6 @@ public class IPAddress internal const int NumberOfLabels = IPv6AddressBytes / 2; - /// - /// A lazily initialized cache of the value. - /// - private int _hashCode; - /// /// Gets the address family of the IP address. /// @@ -271,21 +266,16 @@ public static IPAddress GetDefaultLocalAddress() /// public override int GetHashCode() { - if (_hashCode == 0) + // For IPv6 addresses, we cannot simply return the integer + // representation as the hashcode. Instead, we calculate + // the hashcode from the string representation of the address. + if (_family == AddressFamily.InterNetworkV6) { - // For IPv6 addresses, we cannot simply return the integer - // representation as the hashcode. Instead, we calculate - // the hashcode from the string representation of the address. - if (_family == AddressFamily.InterNetworkV6) - { - _hashCode = ToString().GetHashCode(); - } - - // For IPv4 addresses, we can simply use the integer representation. - _hashCode = unchecked((int)Address); + return ToString().GetHashCode(); } - return _hashCode; + // For IPv4 addresses, we can simply use the integer representation. + return unchecked((int)Address); } // For security, we need to be able to take an IPAddress and make a copy that's immutable and not derived. From c53291c7abf89463f98c482b1af070b1419fbc91 Mon Sep 17 00:00:00 2001 From: Cory Charlton Date: Wed, 24 Jan 2024 18:52:08 -0800 Subject: [PATCH 12/13] Reverting unintended changes --- .../NetworkInformation/NetworkInterface.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs b/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs index 555530f..3c5e72f 100644 --- a/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs +++ b/nanoFramework.System.Net/NetworkInformation/NetworkInterface.cs @@ -470,10 +470,10 @@ public NetworkInterfaceType NetworkInterfaceType #region native methods [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int GetNetworkInterfaceCount(); + private extern static int GetNetworkInterfaceCount(); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern NetworkInterface GetNetworkInterface(uint interfaceIndex); + private extern static NetworkInterface GetNetworkInterface(uint interfaceIndex); [MethodImpl(MethodImplOptions.InternalCall)] private extern void InitializeNetworkInterfaceSettings(); From b1bc488a8178d41d4024d3e1d133bc81491c4e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 26 Jan 2024 10:27:21 +0000 Subject: [PATCH 13/13] Bump native assembly version --- nanoFramework.System.Net/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nanoFramework.System.Net/Properties/AssemblyInfo.cs b/nanoFramework.System.Net/Properties/AssemblyInfo.cs index 6f37577..7638b29 100644 --- a/nanoFramework.System.Net/Properties/AssemblyInfo.cs +++ b/nanoFramework.System.Net/Properties/AssemblyInfo.cs @@ -11,7 +11,7 @@ //////////////////////////////////////////////////////////////// // update this whenever the native assembly signature changes // -[assembly: AssemblyNativeVersion("100.2.0.0")] +[assembly: AssemblyNativeVersion("100.2.0.1")] //////////////////////////////////////////////////////////////// // Setting ComVisible to false makes the types in this assembly not visible