From 7ef44ae7a7db8c8508792468ba401bf9cecf8aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A4r=20Bj=C3=B6rklund?= Date: Fri, 4 Aug 2017 09:42:44 +0200 Subject: [PATCH] WIP --- .../ref/System.Net.Primitives.cs | 1 + .../ref/System.Net.Primitives.csproj | 2 +- .../src/System/Net/IPAddress.cs | 60 ++++++++++++++----- .../FunctionalTests/Configurations.props | 3 +- .../FunctionalTests/IPAddressSpanTest.cs | 46 ++++++++++++++ ...tem.Net.Primitives.Functional.Tests.csproj | 5 +- .../IPAddressPerformanceTests.cs | 47 +++++++++++++++ ...em.Net.Primitives.Performance.Tests.csproj | 5 +- 8 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs create mode 100644 src/System.Net.Primitives/tests/PerformanceTests/IPAddressPerformanceTests.cs diff --git a/src/System.Net.Primitives/ref/System.Net.Primitives.cs b/src/System.Net.Primitives/ref/System.Net.Primitives.cs index 16dfbef5ca28..a0c0e4ff6d93 100644 --- a/src/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -202,6 +202,7 @@ public IPAddress(long newAddress) { } public long ScopeId { get { throw null; } set { } } public override bool Equals(object comparand) { throw null; } public byte[] GetAddressBytes() { throw null; } + public bool TryWriteBytes(Span destination, out int bytesWritten) { throw null; } public override int GetHashCode() { throw null; } public static short HostToNetworkOrder(short host) { throw null; } public static int HostToNetworkOrder(int host) { throw null; } diff --git a/src/System.Net.Primitives/ref/System.Net.Primitives.csproj b/src/System.Net.Primitives/ref/System.Net.Primitives.csproj index 189b9b29b7c1..50c3e8c0cad0 100644 --- a/src/System.Net.Primitives/ref/System.Net.Primitives.csproj +++ b/src/System.Net.Primitives/ref/System.Net.Primitives.csproj @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/src/System.Net.Primitives/src/System/Net/IPAddress.cs b/src/System.Net.Primitives/src/System/Net/IPAddress.cs index fbe0e4fdcb63..7d4b776f4561 100644 --- a/src/System.Net.Primitives/src/System/Net/IPAddress.cs +++ b/src/System.Net.Primitives/src/System/Net/IPAddress.cs @@ -272,6 +272,49 @@ public static IPAddress Parse(string ipString) return IPAddressParser.Parse(ipString, false); } + public bool TryWriteBytes(Span destination, out int bytesWritten) + { + if (IsIPv6) + { + Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels); + + if (destination.Length < IPAddressParserStatics.IPv6AddressBytes) + { + bytesWritten = 0; + return false; + } + + int j = 0; + for (int i = 0; i < NumberOfLabels; i++) + { + destination[j++] = (byte)((_numbers[i] >> 8) & 0xFF); + destination[j++] = (byte)((_numbers[i]) & 0xFF); + } + + bytesWritten = IPAddressParserStatics.IPv6AddressBytes; + } + else + { + if (destination.Length < IPAddressParserStatics.IPv4AddressBytes) + { + bytesWritten = 0; + return false; + } + + uint address = PrivateAddress; + unchecked + { + destination[0] = (byte)(address); + destination[1] = (byte)(address >> 8); + destination[2] = (byte)(address >> 16); + destination[3] = (byte)(address >> 24); + } + + bytesWritten = IPAddressParserStatics.IPv4AddressBytes; + } + + return true; + } /// /// /// Provides a copy of the IPAddress internals as an array of bytes. @@ -285,26 +328,13 @@ public byte[] GetAddressBytes() Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels); bytes = new byte[IPAddressParserStatics.IPv6AddressBytes]; - int j = 0; - for (int i = 0; i < NumberOfLabels; i++) - { - bytes[j++] = (byte)((_numbers[i] >> 8) & 0xFF); - bytes[j++] = (byte)((_numbers[i]) & 0xFF); - } } else { - uint address = PrivateAddress; bytes = new byte[IPAddressParserStatics.IPv4AddressBytes]; - - unchecked - { - bytes[0] = (byte)(address); - bytes[1] = (byte)(address >> 8); - bytes[2] = (byte)(address >> 16); - bytes[3] = (byte)(address >> 24); - } } + + TryWriteBytes(new Span(bytes), out int bytesWritten); return bytes; } diff --git a/src/System.Net.Primitives/tests/FunctionalTests/Configurations.props b/src/System.Net.Primitives/tests/FunctionalTests/Configurations.props index cfc57211a43f..f26eea22b867 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/Configurations.props +++ b/src/System.Net.Primitives/tests/FunctionalTests/Configurations.props @@ -4,6 +4,7 @@ netstandard-Unix; netstandard-Windows_NT; + netcoreapp - \ No newline at end of file + diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs new file mode 100644 index 000000000000..d146d2f972c6 --- /dev/null +++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Net.Sockets; + +using Xunit; + +namespace System.Net.Primitives.Functional.Tests +{ + public static class IPAddressSpanTest + { + private const long MinAddress = 0; + private const long MaxAddress = 0xFFFFFFFF; + + private const long MinScopeId = 0; + private const long MaxScopeId = 0xFFFFFFFF; + + private static byte[] ipV6AddressBytes1 = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + private static byte[] ipV6AddressBytes2 = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + + private static IPAddress IPV6Address1() + { + return new IPAddress(ipV6AddressBytes1); + } + + private static IPAddress IPV6Address2() + { + return new IPAddress(ipV6AddressBytes2); + } + + [Theory] + [InlineData(new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 } })] + [InlineData(new object[] { new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } })] + public static void TryWriteBytes_RightSizeBuffer_Success(byte[] address) + { + var result = new byte[address.Length]; + int bytesWritten = -1; + IPAddress ip = new IPAddress(address); + Assert.Equal(true, ip.TryWriteBytes(new Span(result), out bytesWritten)); + Assert.Equal(address, result); + Assert.Equal(address.Length, bytesWritten); + } + } +} diff --git a/src/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj b/src/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj index 83b231ede57e..114ae36914aa 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj +++ b/src/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj @@ -8,6 +8,8 @@ + + @@ -19,6 +21,7 @@ + @@ -44,4 +47,4 @@ - \ No newline at end of file + diff --git a/src/System.Net.Primitives/tests/PerformanceTests/IPAddressPerformanceTests.cs b/src/System.Net.Primitives/tests/PerformanceTests/IPAddressPerformanceTests.cs new file mode 100644 index 000000000000..d50d005c2653 --- /dev/null +++ b/src/System.Net.Primitives/tests/PerformanceTests/IPAddressPerformanceTests.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Net.Primitives.Tests +{ + public static class IPAddressPerformanceTests + { + [Benchmark] + [MeasureGCCounts] + [InlineData(new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 } })] + [InlineData(new object[] { new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } })] + public static void TryWriteBytes(byte[] address) + { + var ip = new IPAddress(address); + var bytes = new byte[address.Length]; + var bytesSpan = new Span(bytes); + int bytesWritten = 0; + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { + ip.TryWriteBytes(bytesSpan, bytesWritten); + } + } + } + + [Benchmark] + [MeasureGCCounts] + [InlineData(new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 } })] + [InlineData(new object[] { new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } })] + public static void GetAddressBytes(byte[] address) + { + var ip = new IPAddress(address); + foreach (var iteration in Benchmark.Iterations) + { + using (iteration.StartMeasurement()) + { + var bytes = ip.GetAddressBytes(); + } + } + } + } +} diff --git a/src/System.Net.Primitives/tests/PerformanceTests/System.Net.Primitives.Performance.Tests.csproj b/src/System.Net.Primitives/tests/PerformanceTests/System.Net.Primitives.Performance.Tests.csproj index ab3d3f1b29bb..f84c36882df6 100644 --- a/src/System.Net.Primitives/tests/PerformanceTests/System.Net.Primitives.Performance.Tests.csproj +++ b/src/System.Net.Primitives/tests/PerformanceTests/System.Net.Primitives.Performance.Tests.csproj @@ -9,8 +9,11 @@ + + + @@ -19,4 +22,4 @@ - \ No newline at end of file +