Imported Upstream version 5.10.0.47

Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-24 17:04:36 +00:00
parent 88ff76fe28
commit e46a49ecf1
5927 changed files with 226314 additions and 129848 deletions

View File

@@ -41,18 +41,18 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
{E671BC9F-A64C-4504-8B00-7A3215B99AF9}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{7860A11A-1841-4416-8A30-28EEEB42C6BB}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{7860A11A-1841-4416-8A30-28EEEB42C6BB}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{7860A11A-1841-4416-8A30-28EEEB42C6BB}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
{7860A11A-1841-4416-8A30-28EEEB42C6BB}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
{86256B36-4C78-4A71-A80A-CCA35C4AE758}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{FCFF9C63-CE7A-476E-8241-7B7236FFDBFB}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{FCFF9C63-CE7A-476E-8241-7B7236FFDBFB}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{FCFF9C63-CE7A-476E-8241-7B7236FFDBFB}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU

View File

@@ -191,7 +191,9 @@ namespace System.Net
public static readonly System.Net.IPAddress Loopback;
public static readonly System.Net.IPAddress None;
public IPAddress(byte[] address) { }
public IPAddress(ReadOnlySpan<byte> address) { }
public IPAddress(byte[] address, long scopeid) { }
public IPAddress(ReadOnlySpan<byte> address, long scopeid) { }
public IPAddress(long newAddress) { }
public System.Net.Sockets.AddressFamily AddressFamily { get { throw null; } }
public bool IsIPv4MappedToIPv6 { get { throw null; } }
@@ -202,6 +204,7 @@ namespace System.Net
public long ScopeId { get { throw null; } set { } }
public override bool Equals(object comparand) { throw null; }
public byte[] GetAddressBytes() { throw null; }
public bool TryWriteBytes(Span<byte> 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; }
@@ -213,8 +216,11 @@ namespace System.Net
public static int NetworkToHostOrder(int network) { throw null; }
public static long NetworkToHostOrder(long network) { throw null; }
public static System.Net.IPAddress Parse(string ipString) { throw null; }
public static System.Net.IPAddress Parse(ReadOnlySpan<char> ipString) { throw null; }
public override string ToString() { throw null; }
public bool TryFormat(Span<char> destination, out int charsWritten) { throw null; }
public static bool TryParse(string ipString, out System.Net.IPAddress address) { throw null; }
public static bool TryParse(ReadOnlySpan<char> ipString, out System.Net.IPAddress address) { throw null; }
[Obsolete("This property has been deprecated. It is address family dependent. Please use IPAddress.Equals method to perform comparisons. http://go.microsoft.com/fwlink/?linkid=14202")]
public long Address { get { throw null; } set { } }
}

View File

@@ -13,9 +13,10 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Microsoft.Win32.Primitives\ref\Microsoft.Win32.Primitives.csproj" />
<ProjectReference Include="..\..\System.Memory\ref\System.Memory.csproj" />
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
<ProjectReference Include="..\..\System.Runtime.Handles\ref\System.Runtime.Handles.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -89,6 +89,9 @@
<Compile Include="$(CommonPath)\System\Net\NetworkInformation\HostInformation.cs">
<Link>Common\System\Net\NetworkInformation\HostInformation.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Marvin.cs">
<Link>Common\System\Marvin.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs">
<Link>Common\System\IO\StringBuilderCache.cs</Link>
</Compile>
@@ -194,13 +197,16 @@
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
<Reference Include="System.Diagnostics.Contracts" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tracing" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Memory" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Security.Cryptography.Algorithms" />
<Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />

View File

@@ -225,7 +225,9 @@ namespace System.Net
if (cookie.Domain.Length == 0)
{
throw new ArgumentException(SR.net_emptystringcall, "cookie.Domain");
throw new ArgumentException(
SR.Format(SR.net_emptystringcall, nameof(cookie) + "." + nameof(cookie.Domain)),
nameof(cookie) + "." + nameof(cookie.Domain));
}
Uri uri;
@@ -736,7 +738,7 @@ namespace System.Net
return null;
}
bool isSecure = (uri.Scheme == UriScheme.Https);
bool isSecure = (uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss);
int port = uri.Port;
CookieCollection cookies = null;

View File

@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
namespace System.Net
{
@@ -41,11 +42,10 @@ namespace System.Net
/// <summary>
/// A lazily initialized cache of the result of calling <see cref="ToString"/>.
/// </summary>
[NonSerialized]
private string _toString;
/// <summary>
/// This field is only used for IPv6 addresses. A lazily initialized cache of the <see cref="GetHashCode"/> value.
/// A lazily initialized cache of the <see cref="GetHashCode"/> value.
/// </summary>
private int _hashCode;
@@ -84,6 +84,8 @@ namespace System.Net
set
{
Debug.Assert(IsIPv4);
_toString = null;
_hashCode = 0;
_addressOrScopeId = value;
}
}
@@ -98,6 +100,8 @@ namespace System.Net
set
{
Debug.Assert(IsIPv6);
_toString = null;
_hashCode = 0;
_addressOrScopeId = value;
}
}
@@ -123,13 +127,13 @@ namespace System.Net
/// Constructor for an IPv6 Address with a specified Scope.
/// </para>
/// </devdoc>
public IPAddress(byte[] address, long scopeid)
public IPAddress(byte[] address, long scopeid) :
this(new ReadOnlySpan<byte>(address ?? ThrowAddressNullException()), scopeid)
{
if (address == null)
{
throw new ArgumentNullException(nameof(address));
}
}
public IPAddress(ReadOnlySpan<byte> address, long scopeid)
{
if (address.Length != IPAddressParserStatics.IPv6AddressBytes)
{
throw new ArgumentException(SR.dns_bad_ip_address, nameof(address));
@@ -152,27 +156,6 @@ namespace System.Net
PrivateScopeId = (uint)scopeid;
}
internal unsafe IPAddress(byte* address, int addressLength, long scopeid)
{
Debug.Assert(address != null);
Debug.Assert(addressLength == IPAddressParserStatics.IPv6AddressBytes);
// Consider: Since scope is only valid for link-local and site-local
// addresses we could implement some more robust checking here
if (scopeid < 0 || scopeid > 0x00000000FFFFFFFF)
{
throw new ArgumentOutOfRangeException(nameof(scopeid));
}
_numbers = new ushort[NumberOfLabels];
for (int i = 0; i < NumberOfLabels; i++)
{
_numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
}
PrivateScopeId = (uint)scopeid;
}
internal unsafe IPAddress(ushort* numbers, int numbersLength, uint scopeid)
{
Debug.Assert(numbers != null);
@@ -202,22 +185,18 @@ namespace System.Net
/// Constructor for IPv4 and IPv6 Address.
/// </para>
/// </devdoc>
public IPAddress(byte[] address)
public IPAddress(byte[] address) :
this(new ReadOnlySpan<byte>(address ?? ThrowAddressNullException()))
{
if (address == null)
{
throw new ArgumentNullException(nameof(address));
}
if (address.Length != IPAddressParserStatics.IPv4AddressBytes && address.Length != IPAddressParserStatics.IPv6AddressBytes)
{
throw new ArgumentException(SR.dns_bad_ip_address, nameof(address));
}
}
public IPAddress(ReadOnlySpan<byte> address)
{
if (address.Length == IPAddressParserStatics.IPv4AddressBytes)
{
PrivateAddress = (uint)((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
}
else
else if (address.Length == IPAddressParserStatics.IPv6AddressBytes)
{
_numbers = new ushort[NumberOfLabels];
@@ -226,27 +205,9 @@ namespace System.Net
_numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
}
}
}
internal unsafe IPAddress(byte* address, int addressLength)
{
Debug.Assert(address != null);
Debug.Assert(addressLength > 0);
Debug.Assert(
addressLength == IPAddressParserStatics.IPv4AddressBytes ||
addressLength == IPAddressParserStatics.IPv6AddressBytes);
if (addressLength == IPAddressParserStatics.IPv4AddressBytes)
{
PrivateAddress = (uint)((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
}
else
{
_numbers = new ushort[NumberOfLabels];
for (int i = 0; i < NumberOfLabels; i++)
{
_numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
}
throw new ArgumentException(SR.dns_bad_ip_address, nameof(address));
}
}
@@ -264,13 +225,85 @@ namespace System.Net
/// </devdoc>
public static bool TryParse(string ipString, out IPAddress address)
{
address = IPAddressParser.Parse(ipString, true);
if (ipString == null)
{
address = null;
return false;
}
address = IPAddressParser.Parse(ipString.AsReadOnlySpan(), tryParse: true);
return (address != null);
}
public static bool TryParse(ReadOnlySpan<char> ipSpan, out IPAddress address)
{
address = IPAddressParser.Parse(ipSpan, tryParse: true);
return (address != null);
}
public static IPAddress Parse(string ipString)
{
return IPAddressParser.Parse(ipString, false);
if (ipString == null)
{
throw new ArgumentNullException(nameof(ipString));
}
return IPAddressParser.Parse(ipString.AsReadOnlySpan(), tryParse: false);
}
public static IPAddress Parse(ReadOnlySpan<char> ipSpan)
{
return IPAddressParser.Parse(ipSpan, tryParse: false);
}
public bool TryWriteBytes(Span<byte> destination, out int bytesWritten)
{
if (IsIPv6)
{
if (destination.Length < IPAddressParserStatics.IPv6AddressBytes)
{
bytesWritten = 0;
return false;
}
WriteIPv6Bytes(destination);
bytesWritten = IPAddressParserStatics.IPv6AddressBytes;
}
else
{
if (destination.Length < IPAddressParserStatics.IPv4AddressBytes)
{
bytesWritten = 0;
return false;
}
WriteIPv4Bytes(destination);
bytesWritten = IPAddressParserStatics.IPv4AddressBytes;
}
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteIPv6Bytes(Span<byte> destination)
{
Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels);
int j = 0;
for (int i = 0; i < NumberOfLabels; i++)
{
destination[j++] = (byte)((_numbers[i] >> 8) & 0xFF);
destination[j++] = (byte)((_numbers[i]) & 0xFF);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteIPv4Bytes(Span<byte> destination)
{
uint address = PrivateAddress;
destination[0] = (byte)(address);
destination[1] = (byte)(address >> 8);
destination[2] = (byte)(address >> 16);
destination[3] = (byte)(address >> 24);
}
/// <devdoc>
@@ -280,33 +313,19 @@ namespace System.Net
/// </devdoc>
public byte[] GetAddressBytes()
{
byte[] bytes;
if (IsIPv6)
{
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);
}
byte[] bytes = new byte[IPAddressParserStatics.IPv6AddressBytes];
WriteIPv6Bytes(bytes);
return bytes;
}
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);
}
byte[] bytes = new byte[IPAddressParserStatics.IPv4AddressBytes];
WriteIPv4Bytes(bytes);
return bytes;
}
return bytes;
}
public AddressFamily AddressFamily
@@ -371,13 +390,23 @@ namespace System.Net
return _toString;
}
public bool TryFormat(Span<char> destination, out int charsWritten)
{
return IsIPv4 ?
IPAddressParser.IPv4AddressToString(PrivateAddress, destination, out charsWritten) :
IPAddressParser.IPv6AddressToString(_numbers, PrivateScopeId, destination, out charsWritten);
}
public static long HostToNetworkOrder(long host)
{
#if BIGENDIAN
return host;
#else
return (((long)HostToNetworkOrder(unchecked((int)host)) & 0xFFFFFFFF) << 32)
| ((long)HostToNetworkOrder(unchecked((int)(host >> 32))) & 0xFFFFFFFF);
ulong value = (ulong)host;
value = (value << 32) | (value >> 32);
value = (value & 0x0000FFFF0000FFFF) << 16 | (value & 0xFFFF0000FFFF0000) >> 16;
value = (value & 0x00FF00FF00FF00FF) << 8 | (value & 0xFF00FF00FF00FF00) >> 8;
return (long)value;
#endif
}
@@ -386,8 +415,10 @@ namespace System.Net
#if BIGENDIAN
return host;
#else
return (((int)HostToNetworkOrder(unchecked((short)host)) & 0xFFFF) << 16)
| ((int)HostToNetworkOrder(unchecked((short)(host >> 16))) & 0xFFFF);
uint value = (uint)host;
value = (value << 16) | (value >> 16);
value = (value & 0x00FF00FF) << 8 | (value & 0xFF00FF00) >> 8;
return (int)value;
#endif
}
@@ -419,7 +450,7 @@ namespace System.Net
{
if (address == null)
{
throw new ArgumentNullException(nameof(address));
ThrowAddressNullException();
}
if (address.IsIPv6)
@@ -532,7 +563,6 @@ namespace System.Net
{
if (PrivateAddress != value)
{
_toString = null;
PrivateAddress = unchecked((uint)value);
}
}
@@ -586,23 +616,40 @@ namespace System.Net
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 (_hashCode != 0)
{
return _hashCode;
}
// For IPv6 addresses, we calculate the hashcode by using Marvin
// on a stack-allocated array containing the Address bytes and ScopeId.
int hashCode;
if (IsIPv6)
{
if (_hashCode == 0)
{
_hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(ToString());
}
const int addressAndScopeIdLength = IPAddressParserStatics.IPv6AddressBytes + sizeof(uint);
Span<byte> addressAndScopeIdSpan = stackalloc byte[addressAndScopeIdLength];
return _hashCode;
new ReadOnlySpan<ushort>(_numbers).AsBytes().CopyTo(addressAndScopeIdSpan);
Span<byte> scopeIdSpan = addressAndScopeIdSpan.Slice(IPAddressParserStatics.IPv6AddressBytes);
bool scopeWritten = BitConverter.TryWriteBytes(scopeIdSpan, _addressOrScopeId);
Debug.Assert(scopeWritten);
hashCode = Marvin.ComputeHash32(
ref addressAndScopeIdSpan[0],
addressAndScopeIdLength,
Marvin.DefaultSeed);
}
else
{
// For IPv4 addresses, we can simply use the integer representation.
return unchecked((int)PrivateAddress);
// For IPv4 addresses, we use Marvin on the integer representation of the Address.
hashCode = Marvin.ComputeHash32(
ref Unsafe.As<uint, byte>(ref _addressOrScopeId),
sizeof(uint),
Marvin.DefaultSeed);
}
_hashCode = hashCode;
return _hashCode;
}
// For security, we need to be able to take an IPAddress and make a copy that's immutable and not derived.
@@ -647,5 +694,8 @@ namespace System.Net
return new IPAddress(address);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static byte[] ThrowAddressNullException() => throw new ArgumentNullException("address");
}
}

View File

@@ -11,35 +11,23 @@ namespace System.Net
{
internal class IPAddressParser
{
internal static unsafe IPAddress Parse(string ipString, bool tryParse)
{
if (ipString == null)
{
if (tryParse)
{
return null;
}
throw new ArgumentNullException(nameof(ipString));
}
private const int MaxIPv4StringLength = 15; // 4 numbers separated by 3 periods, with up to 3 digits per number
if (ipString.IndexOf(':') != -1)
internal static unsafe IPAddress Parse(ReadOnlySpan<char> ipSpan, bool tryParse)
{
if (ipSpan.IndexOf(':') >= 0)
{
// If the address string contains the colon character then it can only be an IPv6 address.
// This is valid because we don't support/parse a port specification at the end of an IPv4 address.
uint scope;
// The address is parsed as IPv6 if and only if it contains a colon. This is valid because
// we don't support/parse a port specification at the end of an IPv4 address.
ushort* numbers = stackalloc ushort[IPAddressParserStatics.IPv6AddressShorts];
if (Ipv6StringToAddress(ipString, numbers, IPAddressParserStatics.IPv6AddressShorts, out scope))
if (Ipv6StringToAddress(ipSpan, numbers, IPAddressParserStatics.IPv6AddressShorts, out uint scope))
{
return new IPAddress(numbers, IPAddressParserStatics.IPv6AddressShorts, scope);
}
}
else
else if (Ipv4StringToAddress(ipSpan, out long address))
{
long address;
if (Ipv4StringToAddress(ipString, out address))
{
return new IPAddress(address);
}
return new IPAddress(address);
}
if (tryParse)
@@ -52,19 +40,40 @@ namespace System.Net
internal static unsafe string IPv4AddressToString(uint address)
{
const int MaxLength = 15;
char* addressString = stackalloc char[MaxLength];
int offset = MaxLength;
char* addressString = stackalloc char[MaxIPv4StringLength];
int charsWritten = IPv4AddressToStringHelper(address, addressString);
return new string(addressString, 0, charsWritten);
}
internal static unsafe bool IPv4AddressToString(uint address, Span<char> formatted, out int charsWritten)
{
if (formatted.Length < MaxIPv4StringLength)
{
charsWritten = 0;
return false;
}
fixed (char* formattedPtr = &formatted.DangerousGetPinnableReference())
{
charsWritten = IPv4AddressToStringHelper(address, formattedPtr);
}
return true;
}
private static unsafe int IPv4AddressToStringHelper(uint address, char* addressString)
{
int offset = 0;
FormatIPv4AddressNumber((int)((address >> 24) & 0xFF), addressString, ref offset);
addressString[--offset] = '.';
FormatIPv4AddressNumber((int)((address >> 16) & 0xFF), addressString, ref offset);
addressString[--offset] = '.';
FormatIPv4AddressNumber((int)((address >> 8) & 0xFF), addressString, ref offset);
addressString[--offset] = '.';
FormatIPv4AddressNumber((int)(address & 0xFF), addressString, ref offset);
addressString[offset++] = '.';
FormatIPv4AddressNumber((int)((address >> 8) & 0xFF), addressString, ref offset);
addressString[offset++] = '.';
FormatIPv4AddressNumber((int)((address >> 16) & 0xFF), addressString, ref offset);
addressString[offset++] = '.';
FormatIPv4AddressNumber((int)((address >> 24) & 0xFF), addressString, ref offset);
return new string(addressString, offset, MaxLength - offset);
return offset;
}
internal static string IPv6AddressToString(ushort[] address, uint scopeId)
@@ -72,6 +81,35 @@ namespace System.Net
Debug.Assert(address != null);
Debug.Assert(address.Length == IPAddressParserStatics.IPv6AddressShorts);
StringBuilder buffer = IPv6AddressToStringHelper(address, scopeId);
return StringBuilderCache.GetStringAndRelease(buffer);
}
internal static bool IPv6AddressToString(ushort[] address, uint scopeId, Span<char> destination, out int charsWritten)
{
Debug.Assert(address != null);
Debug.Assert(address.Length == IPAddressParserStatics.IPv6AddressShorts);
StringBuilder buffer = IPv6AddressToStringHelper(address, scopeId);
if (destination.Length < buffer.Length)
{
StringBuilderCache.Release(buffer);
charsWritten = 0;
return false;
}
buffer.CopyTo(0, destination, buffer.Length);
charsWritten = buffer.Length;
StringBuilderCache.Release(buffer);
return true;
}
internal static StringBuilder IPv6AddressToStringHelper(ushort[] address, uint scopeId)
{
const int INET6_ADDRSTRLEN = 65;
StringBuilder buffer = StringBuilderCache.Acquire(INET6_ADDRSTRLEN);
@@ -99,33 +137,35 @@ namespace System.Net
buffer.Append('%').Append(scopeId);
}
return StringBuilderCache.GetStringAndRelease(buffer);
return buffer;
}
private static unsafe void FormatIPv4AddressNumber(int number, char* addressString, ref int offset)
{
// Math.DivRem has no overload for byte, assert here for safety
Debug.Assert(number < 256);
offset += number > 99 ? 3 : number > 9 ? 2 : 1;
int i = offset;
do
{
int rem;
number = Math.DivRem(number, 10, out rem);
number = Math.DivRem(number, 10, out int rem);
addressString[--i] = (char)('0' + rem);
} while (number != 0);
offset = i;
}
public static unsafe bool Ipv4StringToAddress(string ipString, out long address)
public static unsafe bool Ipv4StringToAddress(ReadOnlySpan<char> ipSpan, out long address)
{
Debug.Assert(ipString != null);
int end = ipSpan.Length;
long tmpAddr;
int end = ipString.Length;
fixed (char* ipStringPtr = ipString)
fixed (char* ipStringPtr = &ipSpan.DangerousGetPinnableReference())
{
tmpAddr = IPv4AddressHelper.ParseNonCanonical(ipStringPtr, 0, ref end, notImplicitFile: true);
}
if (tmpAddr != IPv4AddressHelper.Invalid && end == ipString.Length)
if (tmpAddr != IPv4AddressHelper.Invalid && end == ipSpan.Length)
{
// IPv4AddressHelper.ParseNonCanonical returns the bytes in the inverse order.
// Reverse them and return success.
@@ -144,49 +184,51 @@ namespace System.Net
}
}
public static unsafe bool Ipv6StringToAddress(string ipString, ushort* numbers, int numbersLength, out uint scope)
public static unsafe bool Ipv6StringToAddress(ReadOnlySpan<char> ipSpan, ushort* numbers, int numbersLength, out uint scope)
{
Debug.Assert(ipString != null);
Debug.Assert(numbers != null);
Debug.Assert(numbersLength >= IPAddressParserStatics.IPv6AddressShorts);
int end = ipString.Length;
fixed (char* name = ipString)
{
if (IPv6AddressHelper.IsValidStrict(name, 0, ref end) || (end != ipString.Length))
{
string scopeId = null;
IPv6AddressHelper.Parse(ipString, numbers, 0, ref scopeId);
int end = ipSpan.Length;
long result = 0;
if (!string.IsNullOrEmpty(scopeId))
bool isValid = false;
fixed (char* ipStringPtr = &ipSpan.DangerousGetPinnableReference())
{
isValid = IPv6AddressHelper.IsValidStrict(ipStringPtr, 0, ref end);
}
if (isValid || (end != ipSpan.Length))
{
string scopeId = null;
IPv6AddressHelper.Parse(ipSpan, numbers, 0, ref scopeId);
long result = 0;
if (!string.IsNullOrEmpty(scopeId))
{
if (scopeId.Length < 2)
{
if (scopeId.Length < 2)
scope = 0;
return false;
}
for (int i = 1; i < scopeId.Length; i++)
{
char c = scopeId[i];
if (c < '0' || c > '9')
{
scope = 0;
return false;
}
for (int i = 1; i < scopeId.Length; i++)
result = (result * 10) + (c - '0');
if (result > uint.MaxValue)
{
char c = scopeId[i];
if (c < '0' || c > '9')
{
scope = 0;
return false;
}
result = (result * 10) + (c - '0');
if (result > uint.MaxValue)
{
scope = 0;
return false;
}
scope = 0;
return false;
}
}
scope = (uint)result;
return true;
}
scope = (uint)result;
return true;
}
scope = 0;

View File

@@ -15,7 +15,7 @@ namespace System
private const int NumberOfLabels = 4;
// Only called from the IPv6Helper, only parse the canonical format
internal static unsafe int ParseHostNumber(string str, int start, int end)
internal static unsafe int ParseHostNumber(ReadOnlySpan<char> str, int start, int end)
{
byte* numbers = stackalloc byte[NumberOfLabels];
ParseCanonical(str, numbers, start, end);
@@ -309,7 +309,7 @@ namespace System
// of 8-bit numbers and the characters '.'
// Address may terminate with ':' or with the end of the string
//
private static unsafe bool ParseCanonical(string name, byte* numbers, int start, int end)
private static unsafe bool ParseCanonical(ReadOnlySpan<char> name, byte* numbers, int start, int end)
{
for (int i = 0; i < NumberOfLabels; ++i)
{

View File

@@ -242,9 +242,12 @@ namespace System
if (sequenceLength != 0)
{
if (sequenceLength > 4)
{
return false;
}
++sequenceCount;
lastSequence = i - sequenceLength;
sequenceLength = 0;
}
// these sequence counts are -1 because it is implied in end-of-sequence
@@ -252,7 +255,6 @@ namespace System
const int ExpectedSequenceCount = 8;
return
!expectingNumber &&
(sequenceLength <= 4) &&
(haveCompressor ? (sequenceCount < ExpectedSequenceCount) : (sequenceCount == ExpectedSequenceCount)) &&
!needsClosingBracket;
}
@@ -282,7 +284,7 @@ namespace System
// Nothing
//
internal static unsafe void Parse(string address, ushort* numbers, int start, ref string scopeId)
internal static unsafe void Parse(ReadOnlySpan<char> address, ushort* numbers, int start, ref string scopeId)
{
int number = 0;
int index = 0;
@@ -311,7 +313,7 @@ namespace System
for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i)
{
}
scopeId = address.Substring(start, i - start);
scopeId = new string(address.Slice(start, i - start));
// ignore prefix if any
for (; i < address.Length && address[i] != ']'; ++i)
{

View File

@@ -4,6 +4,8 @@
<BuildConfigurations>
netstandard-Unix;
netstandard-Windows_NT;
netcoreapp-Windows_NT;
netcoreapp-Unix;
</BuildConfigurations>
</PropertyGroup>
</Project>
</Project>

View File

@@ -0,0 +1,48 @@
// 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.Net.Sockets;
using Xunit;
namespace System.Net.Primitives.Functional.Tests
{
public sealed class IPAddressParsing_Span : IPAddressParsing
{
public override IPAddress Parse(string ipString) => IPAddress.Parse(ipString.AsReadOnlySpan());
public override bool TryParse(string ipString, out IPAddress address) => IPAddress.TryParse(ipString.AsReadOnlySpan(), out address);
[Theory]
[MemberData(nameof(ValidIpv4Addresses))]
[MemberData(nameof(ValidIpv6Addresses))]
public void TryFormat_ProvidedBufferLargerThanNeeded_Success(string addressString, string expected)
{
IPAddress address = IPAddress.Parse(addressString);
const int IPv4MaxLength = 15; // TryFormat currently requires at least this amount of space for IPv4 addresses
int requiredLength = address.AddressFamily == AddressFamily.InterNetwork ?
IPv4MaxLength :
address.ToString().Length;
var largerThanRequired = new char[requiredLength + 1];
Assert.True(address.TryFormat(new Span<char>(largerThanRequired), out int charsWritten));
Assert.Equal(expected.Length, charsWritten);
Assert.Equal(
address.AddressFamily == AddressFamily.InterNetworkV6 ? expected.ToLowerInvariant() : expected,
new string(largerThanRequired, 0, charsWritten));
}
[Theory]
[MemberData(nameof(ValidIpv4Addresses))]
[MemberData(nameof(ValidIpv6Addresses))]
public void TryFormat_ProvidedBufferTooSmall_Failure(string addressString, string expected)
{
IPAddress address = IPAddress.Parse(addressString);
var result = new char[address.ToString().Length - 1];
Assert.False(address.TryFormat(new Span<char>(result), out int charsWritten));
Assert.Equal(0, charsWritten);
Assert.Equal<char>(new char[result.Length], result);
}
}
}

View File

@@ -0,0 +1,57 @@
// 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
{
public static readonly object[][] IpAddresses =
{
new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 } },
new object[] { new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } },
};
[Theory]
[MemberData(nameof(IpAddresses))]
public static void TryWriteBytes_RightSizeBuffer_Success(byte[] address)
{
var result = new byte[address.Length];
IPAddress ip = new IPAddress(address);
Assert.True(ip.TryWriteBytes(new Span<byte>(result), out int bytesWritten));
Assert.Equal(address, result);
Assert.Equal(address.Length, bytesWritten);
}
[Theory]
[MemberData(nameof(IpAddresses))]
public static void TryWriteBytes_LargerBuffer_Success(byte[] address)
{
var result = new byte[address.Length + 1];
IPAddress ip = new IPAddress(address);
Assert.True(ip.TryWriteBytes(new Span<byte>(result), out int bytesWritten));
Assert.Equal<byte>(address, result.AsSpan().Slice(0, bytesWritten).ToArray());
Assert.Equal(address.Length, bytesWritten);
}
[Theory]
[MemberData(nameof(IpAddresses))]
public static void TryWriteBytes_TooSmallBuffer_Failure(byte[] address)
{
int bufferSize = address.Length - 1;
var result = new byte[bufferSize];
IPAddress ip = new IPAddress(address);
Assert.False(ip.TryWriteBytes(new Span<byte>(result), out int bytesWritten));
Assert.Equal(0, bytesWritten);
Assert.Equal<byte>(new byte[bufferSize], result);
}
}
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using Xunit;
@@ -17,22 +18,32 @@ namespace System.Net.Primitives.Functional.Tests
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 const string IpV4AddressString1 = "192.168.0.9";
private const string IpV4AddressString2 = "169.192.1.10";
private const string IpV6AddressString = "fe80::200:f8ff:fe21:67cf";
private static IPAddress IPV4Address()
private static readonly byte[] IpV4AddressBytes = { 0x01, 0x02, 0x03, 0x04 };
private static readonly byte[] IpV6AddressBytes1 = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
private static readonly byte[] IpV6AddressBytes2 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
private static IPAddress IPV4Address1()
{
return IPAddress.Parse("192.168.0.9");
return IPAddress.Parse(IpV4AddressString1);
}
private static IPAddress IPV4Address2()
{
return IPAddress.Parse(IpV4AddressString2);
}
private static IPAddress IPV6Address1()
{
return new IPAddress(ipV6AddressBytes1);
return new IPAddress(IpV6AddressBytes1);
}
private static IPAddress IPV6Address2()
{
return new IPAddress(ipV6AddressBytes2);
return new IPAddress(IpV6AddressBytes2);
}
[Theory]
@@ -69,8 +80,8 @@ namespace System.Net.Primitives.Functional.Tests
public static object[][] AddressBytesAndFamilies =
{
new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 }, AddressFamily.InterNetwork },
new object[] { ipV6AddressBytes1, AddressFamily.InterNetworkV6 },
new object[] { ipV6AddressBytes2, AddressFamily.InterNetworkV6 }
new object[] { IpV6AddressBytes1, AddressFamily.InterNetworkV6 },
new object[] { IpV6AddressBytes2, AddressFamily.InterNetworkV6 }
};
[Fact]
@@ -96,8 +107,8 @@ namespace System.Net.Primitives.Functional.Tests
{
foreach (long scopeId in new long[] { MinScopeId, MaxScopeId, 500 })
{
yield return new object[] { ipV6AddressBytes1, scopeId };
yield return new object[] { ipV6AddressBytes2, scopeId };
yield return new object[] { IpV6AddressBytes1, scopeId };
yield return new object[] { IpV6AddressBytes2, scopeId };
}
}
}
@@ -109,8 +120,8 @@ namespace System.Net.Primitives.Functional.Tests
AssertExtensions.Throws<ArgumentException>("address", () => new IPAddress(new byte[] { 0x01, 0x01, 0x02 }, 500));
AssertExtensions.Throws<ArgumentOutOfRangeException>("scopeid", () => new IPAddress(ipV6AddressBytes1, MinScopeId - 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("scopeid", () => new IPAddress(ipV6AddressBytes1, MaxScopeId + 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("scopeid", () => new IPAddress(IpV6AddressBytes1, MinScopeId - 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("scopeid", () => new IPAddress(IpV6AddressBytes1, MaxScopeId + 1));
}
[Fact]
@@ -128,7 +139,7 @@ namespace System.Net.Primitives.Functional.Tests
[Fact]
public static void ScopeId_Set_Invalid()
{
IPAddress ip = IPV4Address(); //IpV4
IPAddress ip = IPV4Address1(); //IpV4
Assert.ThrowsAny<Exception>(() => ip.ScopeId = 500);
Assert.ThrowsAny<Exception>(() => ip.ScopeId);
@@ -142,26 +153,34 @@ namespace System.Net.Primitives.Functional.Tests
{
long l1 = (long)0x1350;
long l2 = (long)0x5013000000000000;
long l3 = (long)0x0123456789ABCDEF;
long l4 = unchecked((long)0xEFCDAB8967452301);
int i1 = (int)0x1350;
int i2 = (int)0x50130000;
int i3 = (int)0x01234567;
int i4 = (int)0x67452301;
short s1 = (short)0x1350;
short s2 = (short)0x5013;
Assert.Equal(l2, IPAddress.HostToNetworkOrder(l1));
Assert.Equal(l4, IPAddress.HostToNetworkOrder(l3));
Assert.Equal(i2, IPAddress.HostToNetworkOrder(i1));
Assert.Equal(i4, IPAddress.HostToNetworkOrder(i3));
Assert.Equal(s2, IPAddress.HostToNetworkOrder(s1));
Assert.Equal(l1, IPAddress.NetworkToHostOrder(l2));
Assert.Equal(l3, IPAddress.NetworkToHostOrder(l4));
Assert.Equal(i1, IPAddress.NetworkToHostOrder(i2));
Assert.Equal(i3, IPAddress.NetworkToHostOrder(i4));
Assert.Equal(s1, IPAddress.NetworkToHostOrder(s2));
}
[Fact]
public static void IsLoopback_Get_Success()
{
IPAddress ip = IPV4Address(); //IpV4
IPAddress ip = IPV4Address1(); //IpV4
Assert.False(IPAddress.IsLoopback(ip));
ip = new IPAddress(IPAddress.Loopback.GetAddressBytes()); //IpV4 loopback
@@ -185,7 +204,7 @@ namespace System.Net.Primitives.Functional.Tests
{
Assert.True(IPAddress.Parse("ff02::1").IsIPv6Multicast);
Assert.False(IPAddress.Parse("Fe08::1").IsIPv6Multicast);
Assert.False(IPV4Address().IsIPv6Multicast);
Assert.False(IPV4Address1().IsIPv6Multicast);
}
[Fact]
@@ -193,7 +212,7 @@ namespace System.Net.Primitives.Functional.Tests
{
Assert.True(IPAddress.Parse("fe80::1").IsIPv6LinkLocal);
Assert.False(IPAddress.Parse("Fe08::1").IsIPv6LinkLocal);
Assert.False(IPV4Address().IsIPv6LinkLocal);
Assert.False(IPV4Address1().IsIPv6LinkLocal);
}
[Fact]
@@ -201,7 +220,7 @@ namespace System.Net.Primitives.Functional.Tests
{
Assert.True(IPAddress.Parse("FEC0::1").IsIPv6SiteLocal);
Assert.False(IPAddress.Parse("Fe08::1").IsIPv6SiteLocal);
Assert.False(IPV4Address().IsIPv6SiteLocal);
Assert.False(IPV4Address1().IsIPv6SiteLocal);
}
[Fact]
@@ -209,19 +228,19 @@ namespace System.Net.Primitives.Functional.Tests
{
Assert.True(IPAddress.Parse("2001::1").IsIPv6Teredo);
Assert.False(IPAddress.Parse("Fe08::1").IsIPv6Teredo);
Assert.False(IPV4Address().IsIPv6Teredo);
Assert.False(IPV4Address1().IsIPv6Teredo);
}
[Fact]
public static void Equals_Compare_Success()
{
IPAddress ip1 = IPAddress.Parse("192.168.0.9"); //IpV4
IPAddress ip2 = IPAddress.Parse("192.168.0.9"); //IpV4
IPAddress ip3 = IPAddress.Parse("169.192.1.10"); //IpV4
IPAddress ip1 = IPAddress.Parse(IpV4AddressString1); //IpV4
IPAddress ip2 = IPAddress.Parse(IpV4AddressString1); //IpV4
IPAddress ip3 = IPAddress.Parse(IpV4AddressString2); //IpV4
IPAddress ip4 = new IPAddress(ipV6AddressBytes1); //IpV6
IPAddress ip5 = new IPAddress(ipV6AddressBytes1); //IpV6
IPAddress ip6 = new IPAddress(ipV6AddressBytes2); //IpV6
IPAddress ip4 = IPV6Address1(); //IpV6
IPAddress ip5 = IPV6Address1(); //IpV6
IPAddress ip6 = IPV6Address2(); //IpV6
Assert.True(ip1.Equals(ip2));
Assert.True(ip2.Equals(ip1));
@@ -242,23 +261,56 @@ namespace System.Net.Primitives.Functional.Tests
Assert.False(ip4.GetHashCode().Equals(ip6.GetHashCode()));
}
[Theory]
[MemberData(nameof(GetValidIPAddresses))]
[MemberData(nameof(GeneratedIPAddresses))]
public static void GetHashCode_ValidIPAddresses_Success(IPAddress ip)
{
Assert.Equal(ip.GetHashCode(), ip.GetHashCode());
var clonedIp = ip.AddressFamily == AddressFamily.InterNetworkV6 ?
new IPAddress(ip.GetAddressBytes(), ip.ScopeId) :
new IPAddress(ip.GetAddressBytes());
Assert.Equal(ip.GetHashCode(), clonedIp.GetHashCode());
}
private static IEnumerable<object[]> GetValidIPAddresses()
{
return IPAddressParsing.ValidIpv4Addresses
.Concat(IPAddressParsing.ValidIpv6Addresses)
.Select(array => new object[] {IPAddress.Parse((string)array[0])});
}
public static readonly object[][] GeneratedIPAddresses =
{
new object[] {IPAddress.Parse(IpV4AddressString1)},
new object[] {IPAddress.Parse(IpV6AddressString)},
new object[] {new IPAddress(MinAddress)},
new object[] {new IPAddress(MaxAddress)},
new object[] {new IPAddress(IpV4AddressBytes)},
new object[] {new IPAddress(IpV6AddressBytes1)},
new object[] {new IPAddress(IpV6AddressBytes1, MinScopeId)},
};
#pragma warning disable 618
[Fact]
public static void Address_Property_Failure()
{
IPAddress ip1 = IPAddress.Parse("fe80::200:f8ff:fe21:67cf");
Assert.Throws<SocketException>(() => ip1.Address);
}
[Fact]
public static void Address_Property_Success()
{
IPAddress ip1 = IPAddress.Parse("192.168.0.9");
//192.168.0.10
long newIp4Address = 192 << 24 | 168 << 16 | 0 << 8 | 10;
ip1.Address = newIp4Address;
Assert.Equal("10.0.168.192" , ip1.ToString());
}
[Fact]
public static void Address_Property_Failure()
{
IPAddress ip = IPAddress.Parse("fe80::200:f8ff:fe21:67cf");
Assert.Throws<SocketException>(() => ip.Address);
}
[Fact]
public static void Address_Property_Success()
{
IPAddress ip1 = IPV4Address1();
IPAddress ip2 = IPV4Address2();
ip1.Address = ip2.Address;
Assert.Equal(ip1, ip2);
Assert.Equal(ip1.GetHashCode(), ip2.GetHashCode());
}
#pragma warning restore 618
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="System.Net.Primitives.Functional.Tests">
<Type Name="System.Net.CookieVariant" BinaryFormatter="All" />
<Type Name="System.Net.CookieCollection" BinaryFormatter="All" />
</Library>
</Directives>

View File

@@ -8,6 +8,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="CookieTest.cs" />
<Compile Include="CookieCollectionTest.cs" />
@@ -18,7 +22,9 @@
<Compile Include="DnsEndPointTest.cs" />
<Compile Include="EndPointTest.cs" />
<Compile Include="IPAddressParsing.cs" />
<Compile Include="IPAddressParsingSpan.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
<Compile Include="IPAddressTest.cs" />
<Compile Include="IPAddressSpanTest.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
<Compile Include="IPAddressMappingTest.cs" />
<Compile Include="IPEndPointTest.cs" />
<Compile Include="NetworkCredentialTest.cs" />
@@ -27,9 +33,6 @@
<Compile Include="SerializationTest.cs" />
<Compile Include="RequestCachePolicyTest.cs" />
<Compile Include="CookieContainerAddTest.cs" />
<Compile Include="$(CommonTestPath)\System\PlatformDetection.cs">
<Link>Common\System\PlatformDetection.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Diagnostics\Tracing\TestEventListener.cs">
<Link>Common\System\Diagnostics\Tracing\TestEventListener.cs</Link>
</Compile>
@@ -43,5 +46,11 @@
<Name>RemoteExecutorConsoleApp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Memory" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -51,6 +51,9 @@
<Compile Include="..\..\src\System\Net\EndPoint.cs">
<Link>ProductionCode\System\Net\EndPoint.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Marvin.cs">
<Link>ProductionCode\Common\System\Marvin.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs">
<Link>ProductionCode\Common\System\IO\StringBuilderCache.cs</Link>
</Compile>

View File

@@ -4,6 +4,8 @@
<BuildConfigurations>
netstandard-Unix;
netstandard-Windows_NT;
netcoreapp-Unix;
netcoreapp-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>
</Project>

View File

@@ -0,0 +1,156 @@
// 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
{
public static readonly object[][] TestAddresses =
{
new object[] { new byte[] { 0x8f, 0x18, 0x14, 0x24 } },
new object[] { new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 } },
};
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void TryWriteBytes(byte[] address)
{
var ip = new IPAddress(address);
var bytes = new byte[address.Length];
var bytesSpan = new Span<byte>(bytes);
int bytesWritten = 0;
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
ip.TryWriteBytes(bytesSpan, out bytesWritten); ip.TryWriteBytes(bytesSpan, out bytesWritten);
ip.TryWriteBytes(bytesSpan, out bytesWritten); ip.TryWriteBytes(bytesSpan, out bytesWritten);
ip.TryWriteBytes(bytesSpan, out bytesWritten); ip.TryWriteBytes(bytesSpan, out bytesWritten);
ip.TryWriteBytes(bytesSpan, out bytesWritten); ip.TryWriteBytes(bytesSpan, out bytesWritten);
}
}
}
}
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void GetAddressBytes(byte[] address)
{
var ip = new IPAddress(address);
byte[] bytes;
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
bytes = ip.GetAddressBytes(); bytes = ip.GetAddressBytes();
bytes = ip.GetAddressBytes(); bytes = ip.GetAddressBytes();
bytes = ip.GetAddressBytes(); bytes = ip.GetAddressBytes();
}
}
}
}
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void Ctor_Bytes(byte[] address)
{
IPAddress ip;
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
ip = new IPAddress(address); ip = new IPAddress(address);
ip = new IPAddress(address); ip = new IPAddress(address);
ip = new IPAddress(address); ip = new IPAddress(address);
ip = new IPAddress(address); ip = new IPAddress(address);
}
}
}
}
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void Ctor_Span(byte[] address)
{
var span = new ReadOnlySpan<byte>(address);
IPAddress ip;
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
ip = new IPAddress(span); ip = new IPAddress(span);
ip = new IPAddress(span); ip = new IPAddress(span);
ip = new IPAddress(span); ip = new IPAddress(span);
ip = new IPAddress(span); ip = new IPAddress(span);
}
}
}
}
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void TryFormat(byte[] address)
{
const int INET6_ADDRSTRLEN = 65;
var buffer = new char[INET6_ADDRSTRLEN];
var result = new Span<char>(buffer);
int charsWritten;
var ip = new IPAddress(address);
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
ip.TryFormat(result, out charsWritten);
}
}
}
}
[Benchmark]
[MeasureGCCounts]
[MemberData(nameof(TestAddresses))]
public static void ToString(byte[] address)
{
var ip = new IPAddress(address);
string result;
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < 10000; ++i)
{
result = ip.ToString(); result = ip.ToString();
result = ip.ToString(); result = ip.ToString();
result = ip.ToString(); result = ip.ToString();
result = ip.ToString(); result = ip.ToString();
result = ip.ToString(); result = ip.ToString();
result = ip.ToString(); result = ip.ToString();
}
}
}
}
}
}

View File

@@ -9,8 +9,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="CredentialCacheTests.cs" />
<Compile Include="IPAddressPerformanceTests.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
@@ -19,4 +24,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

Some files were not shown because too many files have changed in this diff Show More