Remove allocations from Dns.* (dotnet/corefx#41061)
authorStephen Toub <stoub@microsoft.com>
Tue, 17 Sep 2019 12:20:14 +0000 (08:20 -0400)
committerGitHub <noreply@github.com>
Tue, 17 Sep 2019 12:20:14 +0000 (08:20 -0400)
This started as an effort to reduce the size of System.Net.NameResolution.dll when publishing a trimmed app.  It's not that big to begin with, but it's carrying around a copy of all of the IAsyncResult helper types, because the Get*Async methods are currently wrappers for the Begin/End* methods.

This PR inverts that, wrapping the Begin/End* methods instead around the Get*Async methods, using the same TaskToApm helper we use in other places in corefx for the same purpose.  This makes the Get*Async methods faster and lighterweight, but it does increase the number/amount of allocation in the Begin/End* APIs.  Since these are considered legacy, I normally would consider that a good trade, however we still use these Begin/End methods in a few places in System.Net.Sockets, and I didn't want to regress those use cases.

So, this also then trims some additional fat, which helps the Get*Async cases even further, and gets the Begin/End* to be even better than before the change.  This includes not allocating an IPHostEntry when we're just going to unwrap it and return its addresses, computing the exact IPAddress[] size we need rather than using a List<> to grow it and ToArray to create the actual array, avoiding creating the HostName if we don't need it, and avoiding an unnecessary SafeHandle allocation.

As part of this, I also noticed that we had some bugs in how some of our interop structures on Windows were defined.  In particular, fields that in the native types were size_t were defined as int rather than IntPtr in the managed code.  It appears we were saved by padding, but I fixed it regardless.

And as long as I was changing pretty much everything else, where I was touching code I also cleaned up some legacy style stuff.

Commit migrated from https://github.com/dotnet/corefx/commit/a55e95cbd9fca7ce5b3ad34c583642a35f42cd63

26 files changed:
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs
src/libraries/Common/src/Interop/Windows/WinSock/AddressInfo.cs [deleted file]
src/libraries/Common/src/Interop/Windows/WinSock/AddressInfoEx.cs [deleted file]
src/libraries/Common/src/Interop/Windows/WinSock/AddressInfoHints.cs
src/libraries/Common/src/Interop/Windows/WinSock/Interop.GetAddrInfoExW.cs
src/libraries/Common/src/Interop/Windows/WinSock/Interop.GetAddrInfoW.cs
src/libraries/Common/src/Interop/Windows/WinSock/Interop.SocketConstructorFlags.cs
src/libraries/Common/src/Interop/Windows/WinSock/Interop.freeaddrinfo.cs [deleted file]
src/libraries/Common/src/Interop/Windows/WinSock/SafeFreeAddrInfo.cs [deleted file]
src/libraries/Common/src/System/Net/DebugSafeHandle.cs
src/libraries/Common/tests/System/Net/Configuration.Http.cs
src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj
src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs [moved from src/libraries/System.Net.NameResolution/src/System/Net/DNS.cs with 51% similarity]
src/libraries/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs [deleted file]
src/libraries/System.Net.NameResolution/src/System/Net/IPHostEntry.cs
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionUtilities.cs [deleted file]
src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostByAddressTest.cs
src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs
src/libraries/System.Net.NameResolution/tests/FunctionalTests/TestSettings.cs
src/libraries/System.Net.NameResolution/tests/PalTests/Fakes/IPAddressFakeExtensions.cs
src/libraries/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs
src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj
src/libraries/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs
src/libraries/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj

index e3b330b..e2d8474 100644 (file)
@@ -5,8 +5,6 @@
 using System;
 using System.Runtime.InteropServices;
 
-using Microsoft.Win32.SafeHandles;
-
 internal partial class Interop
 {
     internal partial class Kernel32
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/AddressInfo.cs b/src/libraries/Common/src/Interop/Windows/WinSock/AddressInfo.cs
deleted file mode 100644 (file)
index 93f500c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 System.Runtime.InteropServices;
-#if !SYSTEM_NET_SOCKETS_DLL
-using SocketType = System.Net.Internals.SocketType;
-using ProtocolFamily = System.Net.Internals.ProtocolFamily;
-#endif
-
-namespace System.Net.Sockets
-{
-    // data structures and types needed for getaddrinfo calls.
-    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
-    internal unsafe struct AddressInfo
-    {
-        internal AddressInfoHints ai_flags;
-        internal AddressFamily ai_family;
-        internal SocketType ai_socktype;
-        internal ProtocolFamily ai_protocol;
-        internal int ai_addrlen;
-        internal sbyte* ai_canonname;   // Ptr to the canonical name - check for NULL
-        internal byte* ai_addr;         // Ptr to the sockaddr structure
-        internal AddressInfo* ai_next;  // Ptr to the next AddressInfo structure
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/AddressInfoEx.cs b/src/libraries/Common/src/Interop/Windows/WinSock/AddressInfoEx.cs
deleted file mode 100644 (file)
index 0972101..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.Internals;
-using System.Runtime.InteropServices;
-
-namespace System.Net.Sockets
-{
-    [StructLayout(LayoutKind.Sequential)]
-    internal unsafe struct AddressInfoEx
-    {
-        internal AddressInfoHints ai_flags;
-        internal AddressFamily ai_family;
-        internal SocketType ai_socktype;
-        internal ProtocolFamily ai_protocol;
-        internal int ai_addrlen;
-        internal IntPtr ai_canonname;   // Ptr to the canonical name - check for NULL
-        internal byte* ai_addr;         // Ptr to the sockaddr structure
-        internal IntPtr ai_blob;         // Unused ptr to blob data about provider
-        internal int ai_bloblen;
-        internal IntPtr ai_provider; // Unused ptr to the namespace provider guid
-        internal AddressInfoEx* ai_next;        // Next structure in linked list
-    }
-}
index 62ea626..232d4ec 100644 (file)
@@ -2,8 +2,6 @@
 // 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.Runtime.InteropServices;
-
 namespace System.Net.Sockets
 {
     [Flags]
index d64cc8c..c0a4899 100644 (file)
@@ -13,6 +13,8 @@ internal static partial class Interop
     {
         internal const string GetAddrInfoExCancelFunctionName = "GetAddrInfoExCancel";
 
+        internal const int NS_ALL = 0;
+
         internal unsafe delegate void LPLOOKUPSERVICE_COMPLETION_ROUTINE([In] int dwError, [In] int dwBytes, [In] NativeOverlapped* lpOverlapped);
 
         [DllImport(Libraries.Ws2_32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
@@ -21,15 +23,30 @@ internal static partial class Interop
             [In] string pServiceName,
             [In] int dwNamespace,
             [In] IntPtr lpNspId,
-            [In] ref AddressInfoEx pHints,
-            [Out] out AddressInfoEx* ppResult,
+            [In] AddressInfoEx* pHints,
+            [Out] AddressInfoEx** ppResult,
             [In] IntPtr timeout,
-            [In] ref NativeOverlapped lpOverlapped,
+            [In] NativeOverlapped* lpOverlapped,
             [In] LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
-            [Out] out IntPtr lpNameHandle
-        );
+            [Out] IntPtr* lpNameHandle);
 
         [DllImport(Libraries.Ws2_32, ExactSpelling = true)]
-        internal static extern unsafe void FreeAddrInfoExW([In] AddressInfoEx* pAddrInfo);
+        internal static extern unsafe void FreeAddrInfoExW(AddressInfoEx* pAddrInfo);
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal unsafe struct AddressInfoEx
+        {
+            internal AddressInfoHints ai_flags;
+            internal AddressFamily ai_family;
+            internal int ai_socktype;
+            internal int ai_protocol;
+            internal IntPtr ai_addrlen;
+            internal IntPtr ai_canonname;    // Ptr to the canonical name - check for NULL
+            internal byte* ai_addr;          // Ptr to the sockaddr structure
+            internal IntPtr ai_blob;         // Unused ptr to blob data about provider
+            internal IntPtr ai_bloblen;
+            internal IntPtr ai_provider;     // Unused ptr to the namespace provider guid
+            internal AddressInfoEx* ai_next; // Next structure in linked list
+        }
     }
 }
index 91ff6b5..54fb797 100644 (file)
@@ -5,18 +5,32 @@
 using System;
 using System.Net.Sockets;
 using System.Runtime.InteropServices;
-using System.Text;
 
 internal static partial class Interop
 {
     internal static partial class Winsock
     {
         [DllImport(Interop.Libraries.Ws2_32, ExactSpelling = true, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
-        internal static extern int GetAddrInfoW(
-            [In] string nodename,
-            [In] string servicename,
-            [In] ref AddressInfo hints,
-            [Out] out SafeFreeAddrInfo handle
-            );
+        internal static extern unsafe int GetAddrInfoW(
+            [In] string pNameName,
+            [In] string pServiceName,
+            [In] AddressInfo* pHints,
+            [Out] AddressInfo** ppResult);
+
+        [DllImport(Interop.Libraries.Ws2_32, ExactSpelling = true, SetLastError = true)]
+        internal static extern unsafe void FreeAddrInfoW(AddressInfo* info);
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+        internal unsafe struct AddressInfo
+        {
+            internal AddressInfoHints ai_flags;
+            internal AddressFamily ai_family;
+            internal int ai_socktype;
+            internal int ai_protocol;
+            internal IntPtr ai_addrlen;
+            internal sbyte* ai_canonname;   // Ptr to the canonical name - check for NULL
+            internal byte* ai_addr;         // Ptr to the sockaddr structure
+            internal AddressInfo* ai_next;  // Ptr to the next AddressInfo structure
+        }
     }
 }
index f3b61aa..4a2e892 100644 (file)
@@ -3,8 +3,6 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
 
 internal static partial class Interop
 {
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.freeaddrinfo.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.freeaddrinfo.cs
deleted file mode 100644 (file)
index adeb5c2..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Text;
-
-internal static partial class Interop
-{
-    internal static partial class Winsock
-    {
-        [DllImport(Interop.Libraries.Ws2_32, ExactSpelling = true, SetLastError = true)]
-        internal static extern void freeaddrinfo([In] IntPtr info);
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/SafeFreeAddrInfo.cs b/src/libraries/Common/src/Interop/Windows/WinSock/SafeFreeAddrInfo.cs
deleted file mode 100644 (file)
index 1d26467..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics;
-
-namespace System.Net.Sockets
-{
-#if DEBUG
-    internal sealed class SafeFreeAddrInfo : DebugSafeHandle
-    {
-#else
-    internal sealed class SafeFreeAddrInfo : SafeHandleZeroOrMinusOneIsInvalid {
-#endif
-        private SafeFreeAddrInfo() : base(true) { }
-
-        internal static int GetAddrInfo(string nodename, string servicename, ref AddressInfo hints, out SafeFreeAddrInfo outAddrInfo)
-        {
-            return Interop.Winsock.GetAddrInfoW(nodename, servicename, ref hints, out outAddrInfo);
-        }
-
-        protected override bool ReleaseHandle()
-        {
-            Interop.Winsock.freeaddrinfo(handle);
-            return true;
-        }
-    }
-}
index e2e7c46..ad41a64 100644 (file)
@@ -4,12 +4,6 @@
 
 using Microsoft.Win32.SafeHandles;
 
-using System.Net.NetworkInformation;
-using System.Net.Sockets;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
 namespace System.Net
 {
 #if DEBUG
@@ -36,8 +30,7 @@ namespace System.Net
         {
             _trace = "WARNING! GC-ed  >>" + this.GetType().ToString() + "<< (should be explicitly closed) \r\n";
 #if TRACE_VERBOSE
-            string stacktrace = Environment.StackTrace;
-            _trace += stacktrace;
+            _trace += Environment.StackTrace;
 #endif
         }
 
index a648108..aa37c69 100644 (file)
@@ -2,7 +2,6 @@
 // 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;
 using System.Collections.Generic;
 using System.Linq;
 
index 8c54b79..3ee88c6 100644 (file)
@@ -5,9 +5,8 @@
     <Configurations>netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="System\Net\DNS.cs" />
+    <Compile Include="System\Net\Dns.cs" />
     <Compile Include="System\Net\IPHostEntry.cs" />
-    <Compile Include="System\Net\NameResolutionUtilities.cs" />
     <Compile Include="System\Net\NetEventSource.NameResolution.cs" />
     <!-- Logging -->
     <Compile Include="$(CommonPath)\System\Net\Logging\DebugThreadTracking.cs">
     <Compile Include="$(CommonPath)\System\Net\InternalException.cs">
       <Link>Common\System\Net\InternalException.cs</Link>
     </Compile>
-    <!-- System.Net common -->
-    <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.cs">
-      <Link>Common\System\Net\ContextAwareResult.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\System\Net\LazyAsyncResult.cs">
-      <Link>Common\System\Net\LazyAsyncResult.cs</Link>
+    <Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\TaskToApm.cs">
+      <Link>Common\CoreLib\System\Threading\Tasks\TaskToApm.cs</Link>
     </Compile>
+    <!-- System.Net common -->
     <Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolType.cs">
       <Link>Common\System\Net\Sockets\ProtocolType.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
       <Link>Common\System\Net\ByteOrder.cs</Link>
     </Compile>
-    <Compile Include="System\Net\DnsResolveAsyncResult.cs" />
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
     <Compile Include="System\Net\NameResolutionPal.Windows.cs" />
     <Compile Include="System\Net\NameResolutionPal.Win32.cs" Condition="'$(TargetGroup)' != 'uap'" />
     <Compile Include="System\Net\NameResolutionPal.Uap.cs" Condition="'$(TargetGroup)' == 'uap'" />
-    <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Windows.cs">
-      <Link>Common\System\Net\ContextAwareResult.Windows.cs</Link>
-    </Compile>
     <!-- Debug only -->
     <Compile Include="$(CommonPath)\System\Net\DebugSafeHandle.cs">
       <Link>Common\System\Net\DebugSafeHandle.cs</Link>
@@ -71,9 +63,6 @@
     <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
       <Link>Interop\Windows\Interop.Libraries.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfo.cs">
-      <Link>Interop\Windows\WinSock\AddressInfo.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfoHints.cs">
       <Link>Interop\Windows\WinSock\AddressInfoHints.cs</Link>
     </Compile>
@@ -92,9 +81,6 @@
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.GetAddrInfoW.cs">
       <Link>Interop\Windows\WinSock\Interop.GetAddrInfoW.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.freeaddrinfo.cs">
-      <Link>Interop\Windows\Winsock\Interop.freeaddinfo.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.WSAStartup.cs">
       <Link>Interop\Windows\WinSock\Interop.WSAStartup.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolFamily.cs">
       <Link>Common\System\Net\Sockets\ProtocolFamily.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\SafeFreeAddrInfo.cs">
-      <Link>Interop\Windows\WinSock\SafeFreeAddrInfo.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfoEx.cs">
-      <Link>Interop\Windows\WinSock\AddressInfoEx.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs">
       <Link>Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs</Link>
     </Compile>
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
     <Compile Include="System\Net\NameResolutionPal.Unix.cs" />
-    <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Unix.cs">
-      <Link>Common\System\Net\ContextAwareResult.Unix.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Net\InteropIPAddressExtensions.Unix.cs">
       <Link>Common\System\Net\InteropIPAddressExtensions.Unix.cs</Link>
     </Compile>
     <Reference Include="System.Threading" />
     <Reference Include="System.Threading.Overlapped" />
     <Reference Include="System.Threading.Tasks" />
+    <Reference Include="System.Threading.ThreadPool" />
   </ItemGroup>
 </Project>
 using System.Globalization;
 using System.Net.Internals;
 using System.Net.Sockets;
-using System.Runtime.ExceptionServices;
 using System.Threading;
 using System.Threading.Tasks;
 
 namespace System.Net
 {
-    /// <devdoc>
-    ///    <para>Provides simple
-    ///       domain name resolution functionality.</para>
-    /// </devdoc>
-
+    /// <summary>Provides simple domain name resolution functionality.</summary>
     public static class Dns
     {
-        // Host names any longer than this automatically fail at the winsock level.
-        // If the host name is 255 chars, the last char must be a dot.
-        private const int MaxHostName = 255;
-
-        [Obsolete("GetHostByName is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IPHostEntry GetHostByName(string hostName)
+        /// <summary>Gets the host name of the local machine.</summary>
+        public static string GetHostName()
         {
+            if (NetEventSource.IsEnabled) NetEventSource.Info(null, null);
             NameResolutionPal.EnsureSocketsAreInitialized();
 
-            if (hostName == null)
-            {
-                throw new ArgumentNullException(nameof(hostName));
-            }
-
-            // See if it's an IP Address.
-            IPAddress address;
-            if (IPAddress.TryParse(hostName, out address))
-            {
-                return NameResolutionUtilities.GetUnresolvedAnswer(address);
-            }
-            return InternalGetHostByName(hostName);
+            return NameResolutionPal.GetHostName();
         }
 
-        private static void ValidateHostName(string hostName)
+        public static IPHostEntry GetHostEntry(IPAddress address)
         {
-            if (hostName.Length > MaxHostName // If 255 chars, the last one must be a dot.
-                || hostName.Length == MaxHostName && hostName[MaxHostName - 1] != '.')
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
+            NameResolutionPal.EnsureSocketsAreInitialized();
+
+            if (address is null)
             {
-                throw new ArgumentOutOfRangeException(nameof(hostName), SR.Format(SR.net_toolong,
-                    nameof(hostName), MaxHostName.ToString(NumberFormatInfo.CurrentInfo)));
+                throw new ArgumentNullException(nameof(address));
             }
-        }
-
-        private static IPHostEntry InternalGetHostByName(string hostName)
-        {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
-            IPHostEntry ipHostEntry = null;
 
-            ValidateHostName(hostName);
-
-            int nativeErrorCode;
-            SocketError errorCode = NameResolutionPal.TryGetAddrInfo(hostName, out ipHostEntry, out nativeErrorCode);
-            if (errorCode != SocketError.Success)
+            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
             {
-                throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
+                throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(address)));
             }
 
+            IPHostEntry ipHostEntry = GetHostEntryCore(address);
+
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
-        } // GetHostByName
+        }
 
-        [Obsolete("GetHostByAddress is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IPHostEntry GetHostByAddress(string address)
+        public static IPHostEntry GetHostEntry(string hostNameOrAddress)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
             NameResolutionPal.EnsureSocketsAreInitialized();
 
-            if (address == null)
+            if (hostNameOrAddress is null)
             {
-                throw new ArgumentNullException(nameof(address));
+                throw new ArgumentNullException(nameof(hostNameOrAddress));
             }
 
-            IPHostEntry ipHostEntry = InternalGetHostByAddress(IPAddress.Parse(address));
-
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
-            return ipHostEntry;
-        } // GetHostByAddress
-
-        [Obsolete("GetHostByAddress is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IPHostEntry GetHostByAddress(IPAddress address)
-        {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            // See if it's an IP Address.
+            IPHostEntry ipHostEntry;
+            if (IPAddress.TryParse(hostNameOrAddress, out IPAddress address))
+            {
+                if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
+                {
+                    throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)));
+                }
 
-            if (address == null)
+                ipHostEntry = GetHostEntryCore(address);
+            }
+            else
             {
-                throw new ArgumentNullException(nameof(address));
+                ipHostEntry = GetHostEntryCore(hostNameOrAddress);
             }
 
-            IPHostEntry ipHostEntry = InternalGetHostByAddress(address);
-
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
-        } // GetHostByAddress
+        }
 
-        // Does internal IPAddress reverse and then forward lookups (for Legacy and current public methods).
-        private static IPHostEntry InternalGetHostByAddress(IPAddress address)
+        public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress) =>
+            GetHostEntryCoreAsync(hostNameOrAddress, justReturnParsedIp: false, throwOnIIPAny: true);
+
+        public static Task<IPHostEntry> GetHostEntryAsync(IPAddress address)
         {
             if (NetEventSource.IsEnabled) NetEventSource.Info(null, address);
+            NameResolutionPal.EnsureSocketsAreInitialized();
 
-            //
-            // Try to get the data for the host from it's address
-            //
-            // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string
-            // will only return that address and not the full list.
-
-            // Do a reverse lookup to get the host name.
-            SocketError errorCode;
-            int nativeErrorCode;
-            string name = NameResolutionPal.TryGetNameInfo(address, out errorCode, out nativeErrorCode);
-            if (errorCode == SocketError.Success)
+            if (address is null)
             {
-                // Do the forward lookup to get the IPs for that host name
-                IPHostEntry hostEntry;
-                errorCode = NameResolutionPal.TryGetAddrInfo(name, out hostEntry, out nativeErrorCode);
-                if (errorCode == SocketError.Success)
-                {
-                    return hostEntry;
-                }
-
-                if (NetEventSource.IsEnabled) NetEventSource.Error(null, SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode));
-
-                // One of two things happened:
-                // 1. There was a ptr record in dns, but not a corollary A/AAA record.
-                // 2. The IP was a local (non-loopback) IP that resolved to a connection specific dns suffix.
-                //    - Workaround, Check "Use this connection's dns suffix in dns registration" on that network
-                //      adapter's advanced dns settings.
-
-                // Just return the resolved host name and no IPs.
-                return hostEntry;
+                throw new ArgumentNullException(nameof(address));
             }
 
-            throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
-
-        } // InternalGetHostByAddress
-
-        /*****************************************************************************
-         Function :    gethostname
-
-         Abstract:     Queries the hostname from DNS
-
-         Input Parameters:
+            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
+            {
+                throw new ArgumentException(SR.net_invalid_ip_addr, nameof(address));
+            }
 
-         Returns: String
-        ******************************************************************************/
+            return RunAsync(s => GetHostEntryCore((IPAddress)s), address);
+        }
 
-        /// <devdoc>
-        ///    <para>Gets the host name of the local machine.</para>
-        /// </devdoc>
-        public static string GetHostName()
+        public static IAsyncResult BeginGetHostEntry(IPAddress address, AsyncCallback requestCallback, object stateObject)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Info(null, null);
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
 
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            IAsyncResult asyncResult = TaskToApm.Begin(GetHostEntryAsync(address), requestCallback, stateObject);
 
-            return NameResolutionPal.GetHostName();
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
+            return asyncResult;
         }
 
-        [Obsolete("Resolve is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IPHostEntry Resolve(string hostName)
+        public static IAsyncResult BeginGetHostEntry(string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
 
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            IAsyncResult asyncResult = TaskToApm.Begin(GetHostEntryAsync(hostNameOrAddress), requestCallback, stateObject);
 
-            if (hostName == null)
-            {
-                throw new ArgumentNullException(nameof(hostName));
-            }
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
+            return asyncResult;
+        }
 
-            // See if it's an IP Address.
-            IPAddress address;
-            IPHostEntry ipHostEntry;
+        public static IPHostEntry EndGetHostEntry(IAsyncResult asyncResult)
+        {
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
 
-            if (IPAddress.TryParse(hostName, out address) && (address.AddressFamily != AddressFamily.InterNetworkV6 || SocketProtocolSupportPal.OSSupportsIPv6))
-            {
-                try
-                {
-                    ipHostEntry = InternalGetHostByAddress(address);
-                }
-                catch (SocketException ex)
-                {
-                    if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
-                    ipHostEntry = NameResolutionUtilities.GetUnresolvedAnswer(address);
-                }
-            }
-            else
-            {
-                ipHostEntry = InternalGetHostByName(hostName);
-            }
+            IPHostEntry ipHostEntry = TaskToApm.End<IPHostEntry>(asyncResult ?? throw new ArgumentNullException(nameof(asyncResult)));
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
         }
 
-        private static void ResolveCallback(object context)
+        public static IPAddress[] GetHostAddresses(string hostNameOrAddress)
         {
-            DnsResolveAsyncResult result = (DnsResolveAsyncResult)context;
-            IPHostEntry hostEntry;
-            try
-            {
-                if (result.IpAddress != null)
-                {
-                    hostEntry = InternalGetHostByAddress(result.IpAddress);
-                }
-                else
-                {
-                    hostEntry = InternalGetHostByName(result.HostName);
-                }
-            }
-            catch (OutOfMemoryException)
-            {
-                throw;
-            }
-            catch (Exception exception)
-            {
-                result.InvokeCallback(exception);
-                return;
-            }
-
-            result.InvokeCallback(hostEntry);
-        }
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
+            NameResolutionPal.EnsureSocketsAreInitialized();
 
-        // Helpers for async GetHostByName, ResolveToAddresses, and Resolve - they're almost identical
-        // If hostName is an IPString and justReturnParsedIP==true then no reverse lookup will be attempted, but the original address is returned.
-        private static IAsyncResult HostResolutionBeginHelper(string hostName, bool justReturnParsedIp, bool throwOnIIPAny, AsyncCallback requestCallback, object state)
-        {
-            if (hostName == null)
+            if (hostNameOrAddress is null)
             {
-                throw new ArgumentNullException(nameof(hostName));
+                throw new ArgumentNullException(nameof(hostNameOrAddress));
             }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Info(null, hostName);
-
             // See if it's an IP Address.
-            IPAddress ipAddress;
-            DnsResolveAsyncResult asyncResult;
-            if (IPAddress.TryParse(hostName, out ipAddress))
+            IPAddress[] addresses;
+            if (IPAddress.TryParse(hostNameOrAddress, out IPAddress address))
             {
-                if (throwOnIIPAny && (ipAddress.Equals(IPAddress.Any) || ipAddress.Equals(IPAddress.IPv6Any)))
-                {
-                    throw new ArgumentException(SR.net_invalid_ip_addr, nameof(hostName));
-                }
-
-                asyncResult = new DnsResolveAsyncResult(ipAddress, null, state, requestCallback);
-
-                if (justReturnParsedIp)
+                if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
                 {
-                    IPHostEntry hostEntry = NameResolutionUtilities.GetUnresolvedAnswer(ipAddress);
-                    asyncResult.StartPostingAsyncOp(false);
-                    asyncResult.InvokeCallback(hostEntry);
-                    asyncResult.FinishPostingAsyncOp();
-                    return asyncResult;
+                    throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)));
                 }
-            }
-            else
-            {
-                asyncResult = new DnsResolveAsyncResult(hostName, null, state, requestCallback);
-            }
 
-            // Set up the context, possibly flow.
-            asyncResult.StartPostingAsyncOp(false);
-
-            // If the OS supports it and 'hostName' is not an IP Address, resolve the name asynchronously
-            // instead of calling the synchronous version in the ThreadPool.
-            if (NameResolutionPal.SupportsGetAddrInfoAsync && ipAddress == null)
-            {
-                ValidateHostName(hostName);
-                NameResolutionPal.GetAddrInfoAsync(asyncResult);
+                addresses = new IPAddress[] { address };
             }
             else
             {
-                // Start the resolve.
-                Task.Factory.StartNew(
-                    s => ResolveCallback(s),
-                    asyncResult,
-                    CancellationToken.None,
-                    TaskCreationOptions.DenyChildAttach,
-                    TaskScheduler.Default);
+                addresses = GetHostAddressesCore(hostNameOrAddress);
             }
 
-            // Finish the flowing, maybe it completed?  This does nothing if we didn't initiate the flowing above.
-            asyncResult.FinishPostingAsyncOp();
-            return asyncResult;
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, addresses);
+            return addresses;
         }
 
-        private static IAsyncResult HostResolutionBeginHelper(IPAddress address, bool flowContext, AsyncCallback requestCallback, object state)
+        public static Task<IPAddress[]> GetHostAddressesAsync(string hostNameOrAddress) =>
+            (Task<IPAddress[]>)GetHostEntryOrAddressesCoreAsync(hostNameOrAddress, justReturnParsedIp: true, throwOnIIPAny: true, justAddresses: true);
+
+        public static IAsyncResult BeginGetHostAddresses(string hostNameOrAddress, AsyncCallback requestCallback, object state)
         {
-            if (address == null)
-            {
-                throw new ArgumentNullException(nameof(address));
-            }
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
 
-            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
-            {
-                throw new ArgumentException(SR.net_invalid_ip_addr, nameof(address));
-            }
+            IAsyncResult asyncResult = TaskToApm.Begin(GetHostAddressesAsync(hostNameOrAddress), requestCallback, state);
 
-            if (NetEventSource.IsEnabled) NetEventSource.Info(null, address);
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
+            return asyncResult;
+        }
 
-            // Set up the context, possibly flow.
-            DnsResolveAsyncResult asyncResult = new DnsResolveAsyncResult(address, null, state, requestCallback);
-            if (flowContext)
-            {
-                asyncResult.StartPostingAsyncOp(false);
-            }
+        public static IPAddress[] EndGetHostAddresses(IAsyncResult asyncResult)
+        {
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
 
-            // Start the resolve.
-            Task.Factory.StartNew(
-                s => ResolveCallback(s),
-                asyncResult,
-                CancellationToken.None,
-                TaskCreationOptions.DenyChildAttach,
-                TaskScheduler.Default);
+            IPAddress[] addresses = TaskToApm.End<IPAddress[]>(asyncResult ?? throw new ArgumentNullException(nameof(asyncResult)));
 
-            // Finish the flowing, maybe it completed?  This does nothing if we didn't initiate the flowing above.
-            asyncResult.FinishPostingAsyncOp();
-            return asyncResult;
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, addresses);
+            return addresses;
         }
 
-        private static IPHostEntry HostResolutionEndHelper(IAsyncResult asyncResult)
+        [Obsolete("GetHostByName is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IPHostEntry GetHostByName(string hostName)
         {
-            //
-            // parameter validation
-            //
-            if (asyncResult == null)
-            {
-                throw new ArgumentNullException(nameof(asyncResult));
-            }
-            DnsResolveAsyncResult castedResult = asyncResult as DnsResolveAsyncResult;
-            if (castedResult == null)
-            {
-                throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
-            }
-            if (castedResult.EndCalled)
+            NameResolutionPal.EnsureSocketsAreInitialized();
+
+            if (hostName is null)
             {
-                throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndResolve)));
+                throw new ArgumentNullException(nameof(hostName));
             }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Info(null);
-
-            castedResult.InternalWaitForCompletion();
-            castedResult.EndCalled = true;
-
-            Exception exception = castedResult.Result as Exception;
-            if (exception != null)
+            if (IPAddress.TryParse(hostName, out IPAddress address))
             {
-                ExceptionDispatchInfo.Throw(exception);
+                return CreateHostEntryForAddress(address);
             }
 
-            return (IPHostEntry)castedResult.Result;
+            return GetHostEntryCore(hostName);
         }
 
         [Obsolete("BeginGetHostByName is obsoleted for this type, please use BeginGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
@@ -366,230 +200,279 @@ namespace System.Net
         {
             if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
 
-            NameResolutionPal.EnsureSocketsAreInitialized();
-
-            IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, true, true, requestCallback, stateObject);
+            IAsyncResult asyncResult = TaskToApm.Begin(GetHostEntryCoreAsync(hostName, justReturnParsedIp: true, throwOnIIPAny: true), requestCallback, stateObject);
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
             return asyncResult;
-        } // BeginGetHostByName
+        }
 
         [Obsolete("EndGetHostByName is obsoleted for this type, please use EndGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
         public static IPHostEntry EndGetHostByName(IAsyncResult asyncResult)
         {
             if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
-            NameResolutionPal.EnsureSocketsAreInitialized();
 
-            IPHostEntry ipHostEntry = HostResolutionEndHelper(asyncResult);
+            IPHostEntry ipHostEntry = TaskToApm.End<IPHostEntry>(asyncResult ?? throw new ArgumentNullException(nameof(asyncResult)));
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
-        } // EndGetHostByName()
+        }
 
-        public static IPHostEntry GetHostEntry(string hostNameOrAddress)
+        [Obsolete("GetHostByAddress is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IPHostEntry GetHostByAddress(string address)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
             NameResolutionPal.EnsureSocketsAreInitialized();
 
-            if (hostNameOrAddress == null)
+            if (address is null)
             {
-                throw new ArgumentNullException(nameof(hostNameOrAddress));
+                throw new ArgumentNullException(nameof(address));
             }
 
-            // See if it's an IP Address.
-            IPAddress address;
-            IPHostEntry ipHostEntry;
-            if (IPAddress.TryParse(hostNameOrAddress, out address))
-            {
-                if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
-                {
-                    throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)));
-                }
-
-                ipHostEntry = InternalGetHostByAddress(address);
-            }
-            else
-            {
-                ipHostEntry = InternalGetHostByName(hostNameOrAddress);
-            }
+            IPHostEntry ipHostEntry = GetHostEntryCore(IPAddress.Parse(address));
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
         }
 
-
-        public static IPHostEntry GetHostEntry(IPAddress address)
+        [Obsolete("GetHostByAddress is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IPHostEntry GetHostByAddress(IPAddress address)
         {
             if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
             NameResolutionPal.EnsureSocketsAreInitialized();
 
-            if (address == null)
+            if (address is null)
             {
                 throw new ArgumentNullException(nameof(address));
             }
 
-            if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
-            {
-                throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(address)));
-            }
-
-            IPHostEntry ipHostEntry = InternalGetHostByAddress(address);
+            IPHostEntry ipHostEntry = GetHostEntryCore(address);
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
-        } // GetHostEntry
+        }
 
-        public static IPAddress[] GetHostAddresses(string hostNameOrAddress)
+        [Obsolete("Resolve is obsoleted for this type, please use GetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IPHostEntry Resolve(string hostName)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
             NameResolutionPal.EnsureSocketsAreInitialized();
 
-            if (hostNameOrAddress == null)
+            if (hostName is null)
             {
-                throw new ArgumentNullException(nameof(hostNameOrAddress));
+                throw new ArgumentNullException(nameof(hostName));
             }
 
             // See if it's an IP Address.
-            IPAddress address;
-            IPAddress[] addresses;
-            if (IPAddress.TryParse(hostNameOrAddress, out address))
+            IPHostEntry ipHostEntry;
+            if (IPAddress.TryParse(hostName, out IPAddress address) &&
+                (address.AddressFamily != AddressFamily.InterNetworkV6 || SocketProtocolSupportPal.OSSupportsIPv6))
             {
-                if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any))
+                try
                 {
-                    throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)));
+                    ipHostEntry = GetHostEntryCore(address);
+                }
+                catch (SocketException ex)
+                {
+                    if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
+                    ipHostEntry = CreateHostEntryForAddress(address);
                 }
-                addresses = new IPAddress[] { address };
             }
             else
             {
-                // InternalGetHostByName works with IP addresses (and avoids a reverse-lookup), but we need
-                // explicit handling in order to do the ArgumentException and guarantee the behavior.
-                addresses = InternalGetHostByName(hostNameOrAddress).AddressList;
+                ipHostEntry = GetHostEntryCore(hostName);
             }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, addresses);
-            return addresses;
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
+            return ipHostEntry;
         }
 
-        public static IAsyncResult BeginGetHostEntry(string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
+        [Obsolete("BeginResolve is obsoleted for this type, please use BeginGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IAsyncResult BeginResolve(string hostName, AsyncCallback requestCallback, object stateObject)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
 
-            IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, false, true, requestCallback, stateObject);
+            IAsyncResult asyncResult = TaskToApm.Begin(GetHostEntryCoreAsync(hostName, justReturnParsedIp: false, throwOnIIPAny: false), requestCallback, stateObject);
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
             return asyncResult;
-        } // BeginResolve
+        }
 
-        public static IAsyncResult BeginGetHostEntry(IPAddress address, AsyncCallback requestCallback, object stateObject)
+        [Obsolete("EndResolve is obsoleted for this type, please use EndGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
+        public static IPHostEntry EndResolve(IAsyncResult asyncResult)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, address);
-
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
+            IPHostEntry ipHostEntry;
 
-            IAsyncResult asyncResult = HostResolutionBeginHelper(address, true, requestCallback, stateObject);
+            try
+            {
+                ipHostEntry = TaskToApm.End<IPHostEntry>(asyncResult);
+            }
+            catch (SocketException ex)
+            {
+                IPAddress address = asyncResult switch
+                {
+                    Task t => t.AsyncState as IPAddress,
+                    TaskToApm.TaskAsyncResult twar => twar._task.AsyncState as IPAddress,
+                    _ => null
+                };
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
-            return asyncResult;
-        } // BeginResolve
+                if (address is null)
+                    throw; // BeginResolve was called with a HostName, not an IPAddress
 
-        public static IPHostEntry EndGetHostEntry(IAsyncResult asyncResult)
-        {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
-            IPHostEntry ipHostEntry = HostResolutionEndHelper(asyncResult);
+                if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
+                ipHostEntry = CreateHostEntryForAddress(address);
+            }
 
             if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
             return ipHostEntry;
-        } // EndResolve()
+        }
 
-        public static IAsyncResult BeginGetHostAddresses(string hostNameOrAddress, AsyncCallback requestCallback, object state)
+        private static IPHostEntry GetHostEntryCore(string hostName) =>
+            (IPHostEntry)GetHostEntryOrAddressesCore(hostName, justAddresses: false);
+
+        private static IPAddress[] GetHostAddressesCore(string hostName) =>
+            (IPAddress[])GetHostEntryOrAddressesCore(hostName, justAddresses: true);
+
+        private static object GetHostEntryOrAddressesCore(string hostName, bool justAddresses)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
+            ValidateHostName(hostName);
 
-            IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, true, true, requestCallback, state);
+            SocketError errorCode = NameResolutionPal.TryGetAddrInfo(hostName, justAddresses, out hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode);
+            if (errorCode != SocketError.Success)
+            {
+                throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
+            }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
-            return asyncResult;
-        } // BeginResolve
+            object result = justAddresses ? (object)
+                addresses :
+                new IPHostEntry
+                {
+                    AddressList = addresses,
+                    HostName = hostName,
+                    Aliases = aliases
+                };
 
-        public static IPAddress[] EndGetHostAddresses(IAsyncResult asyncResult)
-        {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
-            IPHostEntry ipHostEntry = HostResolutionEndHelper(asyncResult);
+            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, result);
+            return result;
+        }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
-            return ipHostEntry.AddressList;
-        } // EndResolveToAddresses
+        private static IPHostEntry GetHostEntryCore(IPAddress address) =>
+            (IPHostEntry)GetHostEntryOrAddressesCore(address, justAddresses: false);
 
-        [Obsolete("BeginResolve is obsoleted for this type, please use BeginGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IAsyncResult BeginResolve(string hostName, AsyncCallback requestCallback, object stateObject)
+        private static IPAddress[] GetHostAddressesCore(IPAddress address) =>
+            (IPAddress[])GetHostEntryOrAddressesCore(address, justAddresses: true);
+
+        // Does internal IPAddress reverse and then forward lookups (for Legacy and current public methods).
+        private static object GetHostEntryOrAddressesCore(IPAddress address, bool justAddresses)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
+            if (NetEventSource.IsEnabled) NetEventSource.Info(null, address);
 
-            NameResolutionPal.EnsureSocketsAreInitialized();
+            // Try to get the data for the host from its address.
+            // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string
+            // will only return that address and not the full list.
 
-            IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, false, false, requestCallback, stateObject);
+            // Do a reverse lookup to get the host name.
+            string name = NameResolutionPal.TryGetNameInfo(address, out SocketError errorCode, out int nativeErrorCode);
+            if (errorCode != SocketError.Success)
+            {
+                throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
+            }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
-            return asyncResult;
-        } // BeginResolve
+            // Do the forward lookup to get the IPs for that host name
+            errorCode = NameResolutionPal.TryGetAddrInfo(name, justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out nativeErrorCode);
 
+            if (errorCode != SocketError.Success)
+            {
+                if (NetEventSource.IsEnabled) NetEventSource.Error(null, SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode));
+            }
 
-        [Obsolete("EndResolve is obsoleted for this type, please use EndGetHostEntry instead. https://go.microsoft.com/fwlink/?linkid=14202")]
-        public static IPHostEntry EndResolve(IAsyncResult asyncResult)
+            // One of three things happened:
+            // 1. Success.
+            // 2. There was a ptr record in dns, but not a corollary A/AAA record.
+            // 3. The IP was a local (non-loopback) IP that resolved to a connection specific dns suffix.
+            //    - Workaround, Check "Use this connection's dns suffix in dns registration" on that network
+            //      adapter's advanced dns settings.
+            // Return whatever we got.
+
+            return justAddresses ?
+                (object)addresses :
+                new IPHostEntry
+                {
+                    HostName = hostName,
+                    Aliases = aliases,
+                    AddressList = addresses
+                };
+        }
+
+        private static Task<IPHostEntry> GetHostEntryCoreAsync(string hostName, bool justReturnParsedIp, bool throwOnIIPAny) =>
+            (Task<IPHostEntry>)GetHostEntryOrAddressesCoreAsync(hostName, justReturnParsedIp, throwOnIIPAny, justAddresses: false);
+
+        // If hostName is an IPString and justReturnParsedIP==true then no reverse lookup will be attempted, but the original address is returned.
+        private static Task GetHostEntryOrAddressesCoreAsync(string hostName, bool justReturnParsedIp, bool throwOnIIPAny, bool justAddresses)
         {
-            if (NetEventSource.IsEnabled) NetEventSource.Enter(null, asyncResult);
-            IPHostEntry ipHostEntry;
+            if (NetEventSource.IsEnabled) NetEventSource.Info(null, hostName);
+            NameResolutionPal.EnsureSocketsAreInitialized();
 
-            try
+            if (hostName is null)
             {
-                ipHostEntry = HostResolutionEndHelper(asyncResult);
+                throw new ArgumentNullException(nameof(hostName));
             }
-            catch (SocketException ex)
+
+            // See if it's an IP Address.
+            if (IPAddress.TryParse(hostName, out IPAddress ipAddress))
             {
-                IPAddress address = ((DnsResolveAsyncResult)asyncResult).IpAddress;
-                if (address == null)
-                    throw; // BeginResolve was called with a HostName, not an IPAddress
+                if (throwOnIIPAny && (ipAddress.Equals(IPAddress.Any) || ipAddress.Equals(IPAddress.IPv6Any)))
+                {
+                    throw new ArgumentException(SR.net_invalid_ip_addr, nameof(hostName));
+                }
 
-                if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
-                ipHostEntry = NameResolutionUtilities.GetUnresolvedAnswer(address);
+                if (justReturnParsedIp)
+                {
+                    return justAddresses ? (Task)
+                        Task.FromResult(new[] { ipAddress }) :
+                        Task.FromResult(CreateHostEntryForAddress(ipAddress));
+                }
+
+                return justAddresses ? (Task)
+                    RunAsync(s => GetHostAddressesCore((IPAddress)s), ipAddress) :
+                    RunAsync(s => GetHostEntryCore((IPAddress)s), ipAddress);
             }
 
-            if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
-            return ipHostEntry;
-        } // EndResolve()
+            // If the OS supports it and 'hostName' is not an IP Address, resolve the name asynchronously
+            // instead of calling the synchronous version in the ThreadPool.
+            if (NameResolutionPal.SupportsGetAddrInfoAsync && ipAddress is null)
+            {
+                ValidateHostName(hostName);
+                return NameResolutionPal.GetAddrInfoAsync(hostName, justAddresses);
+            }
 
-        //************* Task-based async public methods *************************
-        public static Task<IPAddress[]> GetHostAddressesAsync(string hostNameOrAddress)
-        {
-            NameResolutionPal.EnsureSocketsAreInitialized();
-            return Task<IPAddress[]>.Factory.FromAsync(
-                (arg, requestCallback, stateObject) => BeginGetHostAddresses(arg, requestCallback, stateObject),
-                asyncResult => EndGetHostAddresses(asyncResult),
-                hostNameOrAddress,
-                null);
+            return justAddresses ? (Task)
+                RunAsync(s => GetHostAddressesCore((string)s), hostName) :
+                RunAsync(s => GetHostEntryCore((string)s), hostName);
         }
 
-        public static Task<IPHostEntry> GetHostEntryAsync(IPAddress address)
-        {
-            NameResolutionPal.EnsureSocketsAreInitialized();
-            return Task<IPHostEntry>.Factory.FromAsync(
-                (arg, requestCallback, stateObject) => BeginGetHostEntry(arg, requestCallback, stateObject),
-                asyncResult => EndGetHostEntry(asyncResult),
-                address,
-                null);
-        }
+        private static Task<TResult> RunAsync<TResult>(Func<object, TResult> func, object arg) =>
+            Task.Factory.StartNew(func, arg, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+
+        private static IPHostEntry CreateHostEntryForAddress(IPAddress address) =>
+            new IPHostEntry
+            {
+                HostName = address.ToString(),
+                Aliases = Array.Empty<string>(),
+                AddressList = new IPAddress[] { address }
+            };
 
-        public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress)
+        private static void ValidateHostName(string hostName)
         {
-            NameResolutionPal.EnsureSocketsAreInitialized();
-            return Task<IPHostEntry>.Factory.FromAsync(
-                (arg, requestCallback, stateObject) => BeginGetHostEntry(arg, requestCallback, stateObject),
-                asyncResult => EndGetHostEntry(asyncResult),
-                hostNameOrAddress,
-                null);
+            const int MaxHostName = 255;
+
+            if (hostName.Length > MaxHostName ||
+                (hostName.Length == MaxHostName && hostName[MaxHostName - 1] != '.')) // If 255 chars, the last one must be a dot.
+            {
+                throw new ArgumentOutOfRangeException(nameof(hostName),
+                    SR.Format(SR.net_toolong, nameof(hostName), MaxHostName.ToString(NumberFormatInfo.CurrentInfo)));
+            }
         }
     }
 }
diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs b/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs
deleted file mode 100644 (file)
index 2edf0d4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-namespace System.Net
-{
-    internal sealed class DnsResolveAsyncResult : ContextAwareResult
-    {
-        internal string HostName { get; }
-        internal IPAddress IpAddress { get; }
-
-        // Forward lookup
-        internal DnsResolveAsyncResult(string hostName, object myObject, object myState, AsyncCallback myCallBack)
-            : base(myObject, myState, myCallBack)
-        {
-            HostName = hostName;
-        }
-
-        // Reverse lookup
-        internal DnsResolveAsyncResult(IPAddress ipAddress, object myObject, object myState, AsyncCallback myCallBack)
-            : base(myObject, myState, myCallBack)
-        {
-            IpAddress = ipAddress;
-        }
-    }
-}
index 43b3ec8..e9029df 100644 (file)
@@ -4,78 +4,16 @@
 
 namespace System.Net
 {
-    // Host information
-    /// <devdoc>
-    ///    <para>Provides a container class for Internet host address information.</para>
-    /// </devdoc>
+    /// <summary>Provides a container class for Internet host address information.</summary>
     public class IPHostEntry
     {
-        private string _hostName;
-        private string[] _aliases;
-        private IPAddress[] _addressList;
-        // CBT: When doing a DNS resolve, can the resulting host name trusted as an SPN?
-        // Only used on Win7Sp1+.  Assume trusted by default.
-        internal bool isTrustedHost = true;
+        /// <summary>Gets or sets the DNS name of the host.</summary>
+        public string HostName { get; set; }
 
-        /// <devdoc>
-        ///    <para>
-        ///       Contains the DNS
-        ///       name of the host.
-        ///    </para>
-        /// </devdoc>
-        /// <devdoc>
-        /// </devdoc>
-        public string HostName
-        {
-            get
-            {
-                return _hostName;
-            }
-            set
-            {
-                _hostName = value;
-            }
-        }
+        /// <summary>Gets or sets a list of aliases that are associated with a host.</summary>
+        public string[] Aliases { get; set; }
 
-        /// <devdoc>
-        ///    <para>
-        ///       Provides an
-        ///       array of strings containing other DNS names that resolve to the IP addresses
-        ///       in <see cref="AddressList"/>.
-        ///    </para>
-        /// </devdoc>
-        /// <devdoc>
-        /// </devdoc>
-        public string[] Aliases
-        {
-            get
-            {
-                return _aliases;
-            }
-            set
-            {
-                _aliases = value;
-            }
-        }
-
-        /// <devdoc>
-        ///    <para>
-        ///       Provides an
-        ///       array of <see cref="IPAddress"/> objects.
-        ///    </para>
-        /// </devdoc>
-        /// <devdoc>
-        /// </devdoc>
-        public IPAddress[] AddressList
-        {
-            get
-            {
-                return _addressList;
-            }
-            set
-            {
-                _addressList = value;
-            }
-        }
-    } // class IPHostEntry
-} // namespace System.Net
+        /// <summary>Gets or sets a list of IP addresses that are associated with a host.</summary>
+        public IPAddress[] AddressList { get; set; }
+    }
+}
index 6434fbd..47a6a20 100644 (file)
@@ -8,6 +8,7 @@ using System.Net.Internals;
 using System.Net.Sockets;
 using System.Runtime.InteropServices;
 using System.Text;
+using System.Threading.Tasks;
 
 namespace System.Net
 {
@@ -15,6 +16,11 @@ namespace System.Net
     {
         public const bool SupportsGetAddrInfoAsync = false;
 
+        public static void EnsureSocketsAreInitialized() { } // No-op for Unix
+
+        internal static Task GetAddrInfoAsync(string hostName, bool justAddresses) =>
+            throw new NotSupportedException();
+
         private static SocketError GetSocketErrorForNativeError(int error)
         {
             switch (error)
@@ -38,90 +44,84 @@ namespace System.Net
             }
         }
 
-        private static unsafe IPHostEntry CreateIPHostEntry(Interop.Sys.HostEntry hostEntry)
+        private static unsafe void ParseHostEntry(Interop.Sys.HostEntry hostEntry, bool justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses)
         {
-            string hostName = null;
-            if (hostEntry.CanonicalName != null)
+            try
             {
-                hostName = Marshal.PtrToStringAnsi((IntPtr)hostEntry.CanonicalName);
-            }
-
-            int numAddresses = hostEntry.IPAddressCount;
+                hostName = !justAddresses && hostEntry.CanonicalName != null ?
+                    Marshal.PtrToStringAnsi((IntPtr)hostEntry.CanonicalName) :
+                    null;
 
-            IPAddress[] ipAddresses;
-            if (numAddresses == 0)
-            {
-                ipAddresses = Array.Empty<IPAddress>();
-            }
-            else
-            {
-                //
-                // getaddrinfo returns multiple entries per address, for each socket type (datagram, stream, etc.).
-                // Our callers expect just one entry for each address.  So we need to deduplicate the results.
-                // It's important to keep the addresses in order, since they are returned in the order in which
-                // connections should be attempted.
-                //
-                // We assume that the list returned by getaddrinfo is relatively short; after all, the intent is that
-                // the caller may need to attempt to contact every address in the list before giving up on a connection
-                // attempt.  So an O(N^2) algorithm should be fine here.  Keep in mind that any "better" algorithm
-                // is likely to involve extra allocations, hashing, etc., and so will probably be more expensive than
-                // this one in the typical (short list) case.
-                //
-                var nativeAddresses = new Interop.Sys.IPAddress[hostEntry.IPAddressCount];
-                var nativeAddressCount = 0;
-
-                var addressListHandle = hostEntry.AddressListHandle;
-                for (int i = 0; i < hostEntry.IPAddressCount; i++)
+                IPAddress[] localAddresses;
+                if (hostEntry.IPAddressCount == 0)
+                {
+                    localAddresses = Array.Empty<IPAddress>();
+                }
+                else
                 {
-                    var nativeIPAddress = default(Interop.Sys.IPAddress);
-                    int err = Interop.Sys.GetNextIPAddress(&hostEntry, &addressListHandle, &nativeIPAddress);
-                    Debug.Assert(err == 0);
+                    // getaddrinfo returns multiple entries per address, for each socket type (datagram, stream, etc.).
+                    // Our callers expect just one entry for each address.  So we need to deduplicate the results.
+                    // It's important to keep the addresses in order, since they are returned in the order in which
+                    // connections should be attempted.
+                    //
+                    // We assume that the list returned by getaddrinfo is relatively short; after all, the intent is that
+                    // the caller may need to attempt to contact every address in the list before giving up on a connection
+                    // attempt.  So an O(N^2) algorithm should be fine here.  Keep in mind that any "better" algorithm
+                    // is likely to involve extra allocations, hashing, etc., and so will probably be more expensive than
+                    // this one in the typical (short list) case.
+
+                    var nativeAddresses = new Interop.Sys.IPAddress[hostEntry.IPAddressCount];
+                    int nativeAddressCount = 0;
+
+                    Interop.Sys.addrinfo* addressListHandle = hostEntry.AddressListHandle;
+                    for (int i = 0; i < hostEntry.IPAddressCount; i++)
+                    {
+                        Interop.Sys.IPAddress nativeIPAddress = default;
+                        int err = Interop.Sys.GetNextIPAddress(&hostEntry, &addressListHandle, &nativeIPAddress);
+                        Debug.Assert(err == 0);
+
+                        if (Array.IndexOf(nativeAddresses, nativeIPAddress, 0, nativeAddressCount) == -1)
+                        {
+                            nativeAddresses[nativeAddressCount++] = nativeIPAddress;
+                        }
+                    }
 
-                    if (Array.IndexOf(nativeAddresses, nativeIPAddress, 0, nativeAddressCount) == -1)
+                    localAddresses = new IPAddress[nativeAddressCount];
+                    for (int i = 0; i < nativeAddressCount; i++)
                     {
-                        nativeAddresses[nativeAddressCount] = nativeIPAddress;
-                        nativeAddressCount++;
+                        localAddresses[i] = nativeAddresses[i].GetIPAddress();
                     }
                 }
 
-                ipAddresses = new IPAddress[nativeAddressCount];
-                for (int i = 0; i < nativeAddressCount; i++)
+                string[] localAliases = Array.Empty<string>();
+                if (!justAddresses && hostEntry.Aliases != null)
                 {
-                    ipAddresses[i] = nativeAddresses[i].GetIPAddress();
-                }
-            }
+                    int numAliases = 0;
+                    while (hostEntry.Aliases[numAliases] != null)
+                    {
+                        numAliases++;
+                    }
 
-            int numAliases;
-            for (numAliases = 0; hostEntry.Aliases != null && hostEntry.Aliases[numAliases] != null; numAliases++)
-            {
-            }
+                    if (numAliases > 0)
+                    {
+                        localAliases = new string[numAliases];
+                        for (int i = 0; i < localAliases.Length; i++)
+                        {
+                            localAliases[i] = Marshal.PtrToStringAnsi((IntPtr)hostEntry.Aliases[i]);
+                        }
+                    }
+                }
 
-            string[] aliases;
-            if (numAliases == 0)
-            {
-                aliases = Array.Empty<string>();
+                aliases = localAliases;
+                addresses = localAddresses;
             }
-            else
+            finally
             {
-                aliases = new string[numAliases];
-                for (int i = 0; i < numAliases; i++)
-                {
-                    Debug.Assert(hostEntry.Aliases[i] != null);
-                    aliases[i] = Marshal.PtrToStringAnsi((IntPtr)hostEntry.Aliases[i]);
-                }
+                Interop.Sys.FreeHostEntry(&hostEntry);
             }
-
-            Interop.Sys.FreeHostEntry(&hostEntry);
-
-            return new IPHostEntry
-            {
-                HostName = hostName,
-                AddressList = ipAddresses,
-                Aliases = aliases
-            };
         }
 
-        public static unsafe SocketError TryGetAddrInfo(string name, out IPHostEntry hostinfo, out int nativeErrorCode)
+        public static unsafe SocketError TryGetAddrInfo(string name, bool justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode)
         {
             if (name == "")
             {
@@ -133,22 +133,18 @@ namespace System.Net
             int result = Interop.Sys.GetHostEntryForName(name, &entry);
             if (result != 0)
             {
-                hostinfo = NameResolutionUtilities.GetUnresolvedAnswer(name);
                 nativeErrorCode = result;
+                hostName = name;
+                aliases = Array.Empty<string>();
+                addresses = Array.Empty<IPAddress>();
                 return GetSocketErrorForNativeError(result);
             }
 
-            hostinfo = CreateIPHostEntry(entry);
-
+            ParseHostEntry(entry, justAddresses, out hostName, out aliases, out addresses);
             nativeErrorCode = 0;
             return SocketError.Success;
         }
 
-        internal static void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
-        {
-            throw new NotSupportedException();
-        }
-
         public static unsafe string TryGetNameInfo(IPAddress addr, out SocketError socketError, out int nativeErrorCode)
         {
             byte* buffer = stackalloc byte[Interop.Sys.NI_MAXHOST + 1 /*for null*/];
@@ -182,17 +178,9 @@ namespace System.Net
 
             socketError = GetSocketErrorForNativeError(error);
             nativeErrorCode = error;
-            return socketError != SocketError.Success ? null : Marshal.PtrToStringAnsi((IntPtr)buffer);
+            return socketError == SocketError.Success ? Marshal.PtrToStringAnsi((IntPtr)buffer) : null;
         }
 
-        public static string GetHostName()
-        {
-            return Interop.Sys.GetHostName();
-        }
-
-        public static void EnsureSocketsAreInitialized()
-        {
-            // No-op for Unix.
-        }
+        public static string GetHostName() => Interop.Sys.GetHostName();
     }
 }
index 5f70982..576043d 100644 (file)
 // 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 System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
-using System.Text;
+using System.Net.Sockets;
 using System.Threading;
 using System.Threading.Tasks;
-using Microsoft.Win32.SafeHandles;
-using ProtocolFamily = System.Net.Internals.ProtocolFamily;
+using System.Diagnostics;
 
 namespace System.Net
 {
     internal static partial class NameResolutionPal
     {
-        //
-        // used by GetHostName() to preallocate a buffer for the call to gethostname.
-        //
-        private const int HostNameBufferLength = 256;
-
-        private static bool s_initialized;
+        private static volatile bool s_initialized;
         private static readonly object s_initializedLock = new object();
 
         private static readonly unsafe Interop.Winsock.LPLOOKUPSERVICE_COMPLETION_ROUTINE s_getAddrInfoExCallback = GetAddressInfoExCallback;
         private static bool s_getAddrInfoExSupported;
 
-        public static bool SupportsGetAddrInfoAsync
+        public static void EnsureSocketsAreInitialized()
         {
-            get
+            if (!s_initialized)
             {
-                EnsureSocketsAreInitialized();
-                return s_getAddrInfoExSupported;
+                InitializeSockets();
             }
-        }
-
-        /*++
-
-        Routine Description:
-
-            Takes a native pointer (expressed as an int) to a hostent structure,
-            and converts the information in their to an IPHostEntry class. This
-            involves walking through an array of native pointers, and a temporary
-            ArrayList object is used in doing this.
 
-        Arguments:
-
-            nativePointer   - Native pointer to hostent structure.
-
-
-
-        Return Value:
-
-            An IPHostEntry structure.
-
-        --*/
-        private static IPHostEntry NativeToHostEntry(IntPtr nativePointer)
-        {
-            //
-            // marshal pointer to struct
-            //
-
-            hostent Host = Marshal.PtrToStructure<hostent>(nativePointer);
-            IPHostEntry HostEntry = new IPHostEntry();
-
-            if (Host.h_name != IntPtr.Zero)
+            static void InitializeSockets()
             {
-                HostEntry.HostName = Marshal.PtrToStringAnsi(Host.h_name);
-                if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"HostEntry.HostName: {HostEntry.HostName}");
-            }
-
-            // decode h_addr_list to ArrayList of IP addresses.
-            // The h_addr_list field is really a pointer to an array of pointers
-            // to IP addresses. Loop through the array, and while the pointer
-            // isn't NULL read the IP address, convert it to an IPAddress class,
-            // and add it to the list.
-
-            var TempIPAddressList = new List<IPAddress>();
-            int IPAddressToAdd;
-            string AliasToAdd;
-            IntPtr currentArrayElement;
+                lock (s_initializedLock)
+                {
+                    if (!s_initialized)
+                    {
+                        SocketError errorCode = Interop.Winsock.WSAStartup();
+                        if (errorCode != SocketError.Success)
+                        {
+                            // WSAStartup does not set LastWin32Error
+                            throw new SocketException((int)errorCode);
+                        }
 
-            //
-            // get the first pointer in the array
-            //
-            currentArrayElement = Host.h_addr_list;
-            nativePointer = Marshal.ReadIntPtr(currentArrayElement);
+                        s_getAddrInfoExSupported = GetAddrInfoExSupportsOverlapped();
+                        s_initialized = true;
+                    }
+                }
+            }
+        }
 
-            while (nativePointer != IntPtr.Zero)
+        public static bool SupportsGetAddrInfoAsync
+        {
+            get
             {
-                //
-                // if it's not null it points to an IPAddress,
-                // read it...
-                //
-                IPAddressToAdd = Marshal.ReadInt32(nativePointer);
-#if BIGENDIAN
-                // IP addresses from native code are always a byte array
-                // converted to int.  We need to convert the address into
-                // a uniform integer value.
-                IPAddressToAdd = (int)(((uint)IPAddressToAdd << 24) |
-                                        (((uint)IPAddressToAdd & 0x0000FF00) << 8) |
-                                        (((uint)IPAddressToAdd >> 8) & 0x0000FF00) |
-                                        ((uint)IPAddressToAdd >> 24));
-#endif
-
-                if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"currentArrayElement:{currentArrayElement} nativePointer:{nativePointer} IPAddressToAdd:{IPAddressToAdd}");
-
-                //
-                // ...and add it to the list
-                //
-                TempIPAddressList.Add(new IPAddress((long)IPAddressToAdd & 0x0FFFFFFFF));
-
-                //
-                // now get the next pointer in the array and start over
-                //
-                currentArrayElement = currentArrayElement + IntPtr.Size;
-                nativePointer = Marshal.ReadIntPtr(currentArrayElement);
+                EnsureSocketsAreInitialized();
+                return s_getAddrInfoExSupported;
             }
+        }
 
-            HostEntry.AddressList = TempIPAddressList.ToArray();
-
-            //
-            // Now do the same thing for the aliases.
-            //
-
-            var TempAliasList = new List<string>();
-
-            currentArrayElement = Host.h_aliases;
-            nativePointer = Marshal.ReadIntPtr(currentArrayElement);
+        public static unsafe SocketError TryGetAddrInfo(string name, bool justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode)
+        {
+            aliases = Array.Empty<string>();
 
-            while (nativePointer != IntPtr.Zero)
+            var hints = new Interop.Winsock.AddressInfo { ai_family = AddressFamily.Unspecified }; // Gets all address families
+            if (!justAddresses)
             {
-                if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"currentArrayElement:{currentArrayElement} nativePointer:{nativePointer}");
-
-                //
-                // if it's not null it points to an Alias,
-                // read it...
-                //
-                AliasToAdd = Marshal.PtrToStringAnsi(nativePointer);
-
-                //
-                // ...and add it to the list
-                //
-                TempAliasList.Add(AliasToAdd);
-
-                //
-                // now get the next pointer in the array and start over
-                //
-                currentArrayElement = currentArrayElement + IntPtr.Size;
-                nativePointer = Marshal.ReadIntPtr(currentArrayElement);
+                hints.ai_flags = AddressInfoHints.AI_CANONNAME;
             }
 
-            HostEntry.Aliases = TempAliasList.ToArray();
-
-            return HostEntry;
-        } // NativeToHostEntry
-
-        public static unsafe SocketError TryGetAddrInfo(string name, out IPHostEntry hostinfo, out int nativeErrorCode)
-        {
-            //
-            // Use SocketException here to show operation not supported
-            // if, by some nefarious means, this method is called on an
-            // unsupported platform.
-            //
-            SafeFreeAddrInfo root = null;
-            var addresses = new List<IPAddress>();
-            string canonicalname = null;
-
-            AddressInfo hints = new AddressInfo();
-            hints.ai_flags = AddressInfoHints.AI_CANONNAME;
-            hints.ai_family = AddressFamily.Unspecified;   // gets all address families
-
-            nativeErrorCode = 0;
-
-            //
-            // Use try / finally so we always get a shot at freeaddrinfo
-            //
+            Interop.Winsock.AddressInfo* result = null;
             try
             {
-                SocketError errorCode = (SocketError)SafeFreeAddrInfo.GetAddrInfo(name, null, ref hints, out root);
+                SocketError errorCode = (SocketError)Interop.Winsock.GetAddrInfoW(name, null, &hints, &result);
                 if (errorCode != SocketError.Success)
-                { // Should not throw, return mostly blank hostentry
-                    hostinfo = NameResolutionUtilities.GetUnresolvedAnswer(name);
+                {
+                    nativeErrorCode = (int)errorCode;
+                    hostName = name;
+                    addresses = Array.Empty<IPAddress>();
                     return errorCode;
                 }
 
-                AddressInfo* pAddressInfo = (AddressInfo*)root.DangerousGetHandle();
-                //
-                // Process the results
-                //
-                while (pAddressInfo != null)
-                {
-                    //
-                    // Retrieve the canonical name for the host - only appears in the first AddressInfo
-                    // entry in the returned array.
-                    //
-                    if (canonicalname == null && pAddressInfo->ai_canonname != null)
-                    {
-                        canonicalname = Marshal.PtrToStringUni((IntPtr)pAddressInfo->ai_canonname);
-                    }
-                    //
-                    // Only process IPv4 or IPv6 Addresses. Note that it's unlikely that we'll
-                    // ever get any other address families, but better to be safe than sorry.
-                    // We also filter based on whether IPv6 is supported on the current
-                    // platform / machine.
-                    //
-                    var socketAddress = new ReadOnlySpan<byte>(pAddressInfo->ai_addr, pAddressInfo->ai_addrlen);
-
-                    if (pAddressInfo->ai_family == AddressFamily.InterNetwork)
-                    {
-                        if (socketAddress.Length == SocketAddressPal.IPv4AddressSize)
-                            addresses.Add(CreateIPv4Address(socketAddress));
-                    }
-                    else if (pAddressInfo->ai_family == AddressFamily.InterNetworkV6 && SocketProtocolSupportPal.OSSupportsIPv6)
-                    {
-                        if (socketAddress.Length == SocketAddressPal.IPv6AddressSize)
-                            addresses.Add(CreateIPv6Address(socketAddress));
-                    }
-                    //
-                    // Next addressinfo entry
-                    //
-                    pAddressInfo = pAddressInfo->ai_next;
-                }
+                addresses = ParseAddressInfo(result, justAddresses, out hostName);
+                nativeErrorCode = 0;
+                return SocketError.Success;
             }
             finally
             {
-                if (root != null)
+                if (result != null)
                 {
-                    root.Dispose();
+                    Interop.Winsock.FreeAddrInfoW(result);
                 }
             }
-
-            //
-            // Finally, put together the IPHostEntry
-            //
-            hostinfo = new IPHostEntry();
-
-            hostinfo.HostName = canonicalname != null ? canonicalname : name;
-            hostinfo.Aliases = Array.Empty<string>();
-            hostinfo.AddressList = addresses.ToArray();
-
-            return SocketError.Success;
         }
 
         public static unsafe string TryGetNameInfo(IPAddress addr, out SocketError errorCode, out int nativeErrorCode)
@@ -255,7 +102,6 @@ namespace System.Net
             const int NI_MAXHOST = 1025;
             char* hostname = stackalloc char[NI_MAXHOST];
 
-            nativeErrorCode = 0;
             fixed (byte* addressBufferPtr = addressBuffer)
             {
                 errorCode = Interop.Winsock.GetNameInfoW(
@@ -268,60 +114,38 @@ namespace System.Net
                     (int)Interop.Winsock.NameInfoFlags.NI_NAMEREQD);
             }
 
-            return errorCode == SocketError.Success ? new string(hostname) : null;
+            if (errorCode == SocketError.Success)
+            {
+                nativeErrorCode = 0;
+                return new string(hostname);
+            }
+
+            nativeErrorCode = (int)errorCode;
+            return null;
         }
 
         public static unsafe string GetHostName()
         {
-            //
-            // note that we could cache the result ourselves since you
-            // wouldn't expect the hostname of the machine to change during
-            // execution, but this might still happen and we would want to
-            // react to that change.
-            //
+            // We do not cache the result in case the hostname changes.
 
+            const int HostNameBufferLength = 256;
             byte* buffer = stackalloc byte[HostNameBufferLength];
             if (Interop.Winsock.gethostname(buffer, HostNameBufferLength) != SocketError.Success)
             {
                 throw new SocketException();
             }
-            return new string((sbyte*)buffer);
-        }
 
-        public static void EnsureSocketsAreInitialized()
-        {
-            if (!Volatile.Read(ref s_initialized))
-            {
-                lock (s_initializedLock)
-                {
-                    if (!s_initialized)
-                    {
-                        SocketError errorCode = Interop.Winsock.WSAStartup();
-
-                        if (errorCode != SocketError.Success)
-                        {
-                            //
-                            // failed to initialize, throw
-                            //
-                            // WSAStartup does not set LastWin32Error
-                            throw new SocketException((int)errorCode);
-                        }
-
-                        s_getAddrInfoExSupported = GetAddrInfoExSupportsOverlapped();
-
-                        Volatile.Write(ref s_initialized, true);
-                    }
-                }
-            }
+            return new string((sbyte*)buffer);
         }
 
-        public static unsafe void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+        public static unsafe Task GetAddrInfoAsync(string hostName, bool justAddresses)
         {
             GetAddrInfoExContext* context = GetAddrInfoExContext.AllocateContext();
 
+            GetAddrInfoExState state;
             try
             {
-                var state = new GetAddrInfoExState(asyncResult);
+                state = new GetAddrInfoExState(hostName, justAddresses);
                 context->QueryStateHandle = state.CreateHandle();
             }
             catch
@@ -330,18 +154,24 @@ namespace System.Net
                 throw;
             }
 
-            AddressInfoEx hints = new AddressInfoEx();
-            hints.ai_flags = AddressInfoHints.AI_CANONNAME;
-            hints.ai_family = AddressFamily.Unspecified; // Gets all address families
+            var hints = new Interop.Winsock.AddressInfoEx { ai_family = AddressFamily.Unspecified }; // Gets all address families
+            if (!justAddresses)
+            {
+                hints.ai_flags = AddressInfoHints.AI_CANONNAME;
+            }
 
-            SocketError errorCode =
-                (SocketError)Interop.Winsock.GetAddrInfoExW(asyncResult.HostName, null, 0 /* NS_ALL*/, IntPtr.Zero, ref hints, out context->Result, IntPtr.Zero, ref context->Overlapped, s_getAddrInfoExCallback, out context->CancelHandle);
+            SocketError errorCode = (SocketError)Interop.Winsock.GetAddrInfoExW(
+                hostName, null, Interop.Winsock.NS_ALL, IntPtr.Zero, &hints, &context->Result, IntPtr.Zero, &context->Overlapped, s_getAddrInfoExCallback, &context->CancelHandle);
 
             if (errorCode != SocketError.IOPending)
+            {
                 ProcessResult(errorCode, context);
+            }
+
+            return state.Task;
         }
 
-        private static unsafe void GetAddressInfoExCallback([In] int error, [In] int bytes, [In] NativeOverlapped* overlapped)
+        private static unsafe void GetAddressInfoExCallback(int error, int bytes, NativeOverlapped* overlapped)
         {
             // Can be casted directly to GetAddrInfoExContext* because the overlapped is its first field
             GetAddrInfoExContext* context = (GetAddrInfoExContext*)overlapped;
@@ -355,52 +185,148 @@ namespace System.Net
             {
                 GetAddrInfoExState state = GetAddrInfoExState.FromHandleAndFree(context->QueryStateHandle);
 
-                if (errorCode != SocketError.Success)
+                if (errorCode == SocketError.Success)
+                {
+                    IPAddress[] addresses = ParseAddressInfoEx(context->Result, state.JustAddresses, out string hostName);
+                    state.SetResult(state.JustAddresses ? (object)
+                        addresses :
+                        new IPHostEntry
+                        {
+                            HostName = hostName ?? state.HostName,
+                            Aliases = Array.Empty<string>(),
+                            AddressList = addresses
+                        });
+                }
+                else
                 {
-                    state.CompleteAsyncResult(new SocketException((int)errorCode));
-                    return;
+                    state.SetResult(new SocketException((int)errorCode));
                 }
+            }
+            finally
+            {
+                GetAddrInfoExContext.FreeContext(context);
+            }
+        }
+
+        private static unsafe IPAddress[] ParseAddressInfo(Interop.Winsock.AddressInfo* addressInfoPtr, bool justAddresses, out string hostName)
+        {
+            Debug.Assert(addressInfoPtr != null);
 
-                AddressInfoEx* result = context->Result;
-                string canonicalName = null;
+            // Count how many results we have.
+            int addressCount = 0;
+            for (Interop.Winsock.AddressInfo* result = addressInfoPtr; result != null; result = result->ai_next)
+            {
+                int addressLength = (int)result->ai_addrlen;
 
-                List<IPAddress> addresses = new List<IPAddress>();
+                if (result->ai_family == AddressFamily.InterNetwork)
+                {
+                    if (addressLength == SocketAddressPal.IPv4AddressSize)
+                    {
+                        addressCount++;
+                    }
+                }
+                else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+                {
+                    if (addressLength == SocketAddressPal.IPv6AddressSize)
+                    {
+                        addressCount++;
+                    }
+                }
+            }
 
-                while (result != null)
+            // Store them into the array.
+            var addresses = new IPAddress[addressCount];
+            addressCount = 0;
+            string canonicalName = justAddresses ? "NONNULLSENTINEL" : null;
+            for (Interop.Winsock.AddressInfo* result = addressInfoPtr; result != null; result = result->ai_next)
+            {
+                if (canonicalName == null && result->ai_canonname != null)
                 {
-                    if (canonicalName == null && result->ai_canonname != IntPtr.Zero)
-                        canonicalName = Marshal.PtrToStringUni(result->ai_canonname);
+                    canonicalName = Marshal.PtrToStringUni((IntPtr)result->ai_canonname);
+                }
 
-                    var socketAddress = new ReadOnlySpan<byte>(result->ai_addr, result->ai_addrlen);
+                int addressLength = (int)result->ai_addrlen;
+                var socketAddress = new ReadOnlySpan<byte>(result->ai_addr, addressLength);
 
-                    if (result->ai_family == AddressFamily.InterNetwork)
+                if (result->ai_family == AddressFamily.InterNetwork)
+                {
+                    if (addressLength == SocketAddressPal.IPv4AddressSize)
                     {
-                        if (socketAddress.Length == SocketAddressPal.IPv4AddressSize)
-                            addresses.Add(CreateIPv4Address(socketAddress));
+                        addresses[addressCount++] = CreateIPv4Address(socketAddress);
                     }
-                    else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+                }
+                else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+                {
+                    if (addressLength == SocketAddressPal.IPv6AddressSize)
                     {
-                        if (socketAddress.Length == SocketAddressPal.IPv6AddressSize)
-                            addresses.Add(CreateIPv6Address(socketAddress));
+                        addresses[addressCount++] = CreateIPv6Address(socketAddress);
                     }
-
-                    result = result->ai_next;
                 }
+            }
 
-                if (canonicalName == null)
-                    canonicalName = state.HostName;
+            hostName = justAddresses ? null : canonicalName;
+            return addresses;
+        }
 
-                state.CompleteAsyncResult(new IPHostEntry
+        private static unsafe IPAddress[] ParseAddressInfoEx(Interop.Winsock.AddressInfoEx* addressInfoExPtr, bool justAddresses, out string hostName)
+        {
+            Debug.Assert(addressInfoExPtr != null);
+
+            // First count how many address results we have.
+            int addressCount = 0;
+            for (Interop.Winsock.AddressInfoEx* result = addressInfoExPtr; result != null; result = result->ai_next)
+            {
+                int addressLength = (int)result->ai_addrlen;
+
+                if (result->ai_family == AddressFamily.InterNetwork)
                 {
-                    HostName = canonicalName,
-                    Aliases = Array.Empty<string>(),
-                    AddressList = addresses.ToArray()
-                });
+                    if (addressLength == SocketAddressPal.IPv4AddressSize)
+                    {
+                        addressCount++;
+                    }
+                }
+                else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+                {
+                    if (addressLength == SocketAddressPal.IPv6AddressSize)
+                    {
+                        addressCount++;
+                    }
+                }
             }
-            finally
+
+            // Then store them into an array.
+            var addresses = new IPAddress[addressCount];
+            addressCount = 0;
+            string canonicalName = justAddresses ? "NONNULLSENTINEL" : null;
+            for (Interop.Winsock.AddressInfoEx* result = addressInfoExPtr; result != null; result = result->ai_next)
             {
-                GetAddrInfoExContext.FreeContext(context);
+                if (canonicalName == null && result->ai_canonname != IntPtr.Zero)
+                {
+                    canonicalName = Marshal.PtrToStringUni(result->ai_canonname);
+                }
+
+                int addressLength = (int)result->ai_addrlen;
+                var socketAddress = new ReadOnlySpan<byte>(result->ai_addr, addressLength);
+
+                if (result->ai_family == AddressFamily.InterNetwork)
+                {
+                    if (addressLength == SocketAddressPal.IPv4AddressSize)
+                    {
+                        addresses[addressCount++] = CreateIPv4Address(socketAddress);
+                    }
+                }
+                else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+                {
+                    if (addressLength == SocketAddressPal.IPv6AddressSize)
+                    {
+                        addresses[addressCount++] = CreateIPv6Address(socketAddress);
+                    }
+                }
             }
+
+            // Return the parsed host name (if we got one) and addresses.
+            hostName = justAddresses ? null : canonicalName;
+            return addresses;
         }
 
         private static unsafe IPAddress CreateIPv4Address(ReadOnlySpan<byte> socketAddress)
@@ -412,57 +338,83 @@ namespace System.Net
         private static unsafe IPAddress CreateIPv6Address(ReadOnlySpan<byte> socketAddress)
         {
             Span<byte> address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
-            uint scope;
-            SocketAddressPal.GetIPv6Address(socketAddress, address, out scope);
-
-            return new IPAddress(address, (long)scope);
+            SocketAddressPal.GetIPv6Address(socketAddress, address, out uint scope);
+            return new IPAddress(address, scope);
         }
 
-        #region GetAddrInfoAsync Helper Classes
-
-        //
-        // Warning: If this ever ported to NETFX, AppDomain unloads needs to be handled
-        // to protect against AppDomainUnloadException if there are pending operations.
-        //
-
-        private sealed class GetAddrInfoExState
+        private sealed class GetAddrInfoExState : IThreadPoolWorkItem
         {
-            private readonly DnsResolveAsyncResult _asyncResult;
+            private AsyncTaskMethodBuilder<IPHostEntry> IPHostEntryBuilder;
+            private AsyncTaskMethodBuilder<IPAddress[]> IPAddressArrayBuilder;
             private object _result;
 
-            public string HostName => _asyncResult.HostName;
-
-            public GetAddrInfoExState(DnsResolveAsyncResult asyncResult)
+            public GetAddrInfoExState(string hostName, bool justAddresses)
             {
-                _asyncResult = asyncResult;
+                HostName = hostName;
+                JustAddresses = justAddresses;
+                if (justAddresses)
+                {
+                    IPAddressArrayBuilder = AsyncTaskMethodBuilder<IPAddress[]>.Create();
+                    _ = IPAddressArrayBuilder.Task; // force initialization
+                }
+                else
+                {
+                    IPHostEntryBuilder = AsyncTaskMethodBuilder<IPHostEntry>.Create();
+                    _ = IPHostEntryBuilder.Task; // force initialization
+                }
             }
 
-            public void CompleteAsyncResult(object o)
-            {
-                // We don't want to expose the GetAddrInfoEx callback thread to user code.
-                // The callback occurs in a native windows thread pool.
+            public string HostName { get; }
 
-                _result = o;
+            public bool JustAddresses { get; }
 
-                Task.Factory.StartNew(s =>
-                {
-                    var self = (GetAddrInfoExState)s;
-                    self._asyncResult.InvokeCallback(self._result);
-                }, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+            public Task Task => JustAddresses ? (Task)IPAddressArrayBuilder.Task : IPHostEntryBuilder.Task;
+
+            public void SetResult(object result)
+            {
+                // Store the result and then queue this object to the thread pool to actually complete the Tasks, as we
+                // want to avoid invoking continuations on the Windows callback thread. Effectively we're manually
+                // implementing TaskCreationOptions.RunContinuationsAsynchronously, which we can't use because we're
+                // using AsyncTaskMethodBuilder, which we're using in order to create either a strongly-typed Task<IPHostEntry>
+                // or Task<IPAddress[]> without allocating additional objects.
+                Debug.Assert(result is Exception || result is IPAddress[] || result is IPHostEntry);
+                _result = result;
+                ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);
             }
 
-            public IntPtr CreateHandle()
+            void IThreadPoolWorkItem.Execute()
             {
-                GCHandle handle = GCHandle.Alloc(this, GCHandleType.Normal);
-                return GCHandle.ToIntPtr(handle);
+                if (JustAddresses)
+                {
+                    if (_result is Exception e)
+                    {
+                        IPAddressArrayBuilder.SetException(e);
+                    }
+                    else
+                    {
+                        IPAddressArrayBuilder.SetResult((IPAddress[])_result);
+                    }
+                }
+                else
+                {
+                    if (_result is Exception e)
+                    {
+                        IPHostEntryBuilder.SetException(e);
+                    }
+                    else
+                    {
+                        IPHostEntryBuilder.SetResult((IPHostEntry)_result);
+                    }
+                }
             }
 
+            public IntPtr CreateHandle() => GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Normal));
+
             public static GetAddrInfoExState FromHandleAndFree(IntPtr handle)
             {
                 GCHandle gcHandle = GCHandle.FromIntPtr(handle);
                 var state = (GetAddrInfoExState)gcHandle.Target;
                 gcHandle.Free();
-
                 return state;
             }
         }
@@ -471,7 +423,7 @@ namespace System.Net
         private unsafe struct GetAddrInfoExContext
         {
             public NativeOverlapped Overlapped;
-            public AddressInfoEx* Result;
+            public Interop.Winsock.AddressInfoEx* Result;
             public IntPtr CancelHandle;
             public IntPtr QueryStateHandle;
 
@@ -479,19 +431,18 @@ namespace System.Net
             {
                 var context = (GetAddrInfoExContext*)Marshal.AllocHGlobal(sizeof(GetAddrInfoExContext));
                 *context = default;
-
                 return context;
             }
 
             public static void FreeContext(GetAddrInfoExContext* context)
             {
                 if (context->Result != null)
+                {
                     Interop.Winsock.FreeAddrInfoExW(context->Result);
+                }
 
                 Marshal.FreeHGlobal((IntPtr)context);
             }
         }
-
-        #endregion
     }
 }
diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionUtilities.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionUtilities.cs
deleted file mode 100644 (file)
index 4be4755..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-namespace System.Net
-{
-    internal static class NameResolutionUtilities
-    {
-        public static IPHostEntry GetUnresolvedAnswer(IPAddress address)
-        {
-            return new IPHostEntry
-            {
-                HostName = address.ToString(),
-                Aliases = Array.Empty<string>(),
-                AddressList = new IPAddress[] { address }
-            };
-        }
-
-        public static IPHostEntry GetUnresolvedAnswer(string name)
-        {
-            return new IPHostEntry
-            {
-                HostName = name,
-                Aliases = Array.Empty<string>(),
-                AddressList = Array.Empty<IPAddress>()
-            };
-        }
-    }
-}
index 3a89a36..b54874d 100644 (file)
@@ -12,7 +12,6 @@ namespace System.Net.NameResolution.Tests
     public class GetHostByAddressTest
     {
         [Fact]
-
         public void DnsObsoleteGetHostByAddress_BadIPString_Throws()
         {
             Assert.Throws<FormatException>(() => Dns.GetHostByAddress("badIPString"));
index da8716f..e3d015d 100644 (file)
@@ -8,7 +8,6 @@ using System.Net.Sockets;
 using System.Threading.Tasks;
 
 using Xunit;
-using Xunit.Sdk;
 
 namespace System.Net.NameResolution.Tests
 {
@@ -74,10 +73,12 @@ namespace System.Net.NameResolution.Tests
         [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue(32797)]
         [InlineData("")]
         [InlineData(TestSettings.LocalHost)]
-        public async Task Dns_GetHostEntryAsync_HostString_Ok(string hostName) => await TestGetHostEntryAsync(() => Dns.GetHostEntryAsync(hostName));
+        public async Task Dns_GetHostEntryAsync_HostString_Ok(string hostName) =>
+            await TestGetHostEntryAsync(() => Dns.GetHostEntryAsync(hostName));
 
         [Fact]
-        public async Task Dns_GetHostEntryAsync_IPString_Ok() => await TestGetHostEntryAsync(() => Dns.GetHostEntryAsync(TestSettings.LocalIPString));
+        public async Task Dns_GetHostEntryAsync_IPString_Ok() =>
+            await TestGetHostEntryAsync(() => Dns.GetHostEntryAsync(TestSettings.LocalIPString));
 
         private static async Task TestGetHostEntryAsync(Func<Task<IPHostEntry>> getHostEntryFunc)
         {
@@ -95,10 +96,20 @@ namespace System.Net.NameResolution.Tests
         }
 
         [Fact]
-        public async Task Dns_GetHostEntryAsync_NullStringHost_Fail() => await Assert.ThrowsAsync<ArgumentNullException>(() => Dns.GetHostEntryAsync((string)null));
+        public async Task Dns_GetHostEntry_NullStringHost_Fail()
+        {
+            Assert.Throws<ArgumentNullException>(() => Dns.GetHostEntry((string)null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => Dns.GetHostEntryAsync((string)null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, (string)null, null));
+        }
 
         [Fact]
-        public async Task Dns_GetHostEntryAsync_NullIPAddressHost_Fail() => await Assert.ThrowsAsync<ArgumentNullException>(() => Dns.GetHostEntryAsync((IPAddress)null));
+        public async Task Dns_GetHostEntryAsync_NullIPAddressHost_Fail()
+        {
+            Assert.Throws<ArgumentNullException>(() => Dns.GetHostEntry((IPAddress)null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => Dns.GetHostEntryAsync((IPAddress)null));
+            await Assert.ThrowsAsync<ArgumentNullException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, (IPAddress)null, null));
+        }
 
         public static IEnumerable<object[]> GetInvalidAddresses()
         {
@@ -109,125 +120,114 @@ namespace System.Net.NameResolution.Tests
 
         [Theory]
         [MemberData(nameof(GetInvalidAddresses))]
-        public async Task Dns_GetHostEntryAsync_AnyIPAddress_Fail(IPAddress address)
+        public async Task Dns_GetHostEntry_AnyIPAddress_Fail(IPAddress address)
         {
-            string addressString = address.ToString();
+            Assert.Throws<ArgumentException>(() => Dns.GetHostEntry(address));
+            Assert.Throws<ArgumentException>(() => Dns.GetHostEntry(address.ToString()));
 
             await Assert.ThrowsAsync<ArgumentException>(() => Dns.GetHostEntryAsync(address));
-            await Assert.ThrowsAsync<ArgumentException>(() => Dns.GetHostEntryAsync(addressString));
-        }
+            await Assert.ThrowsAsync<ArgumentException>(() => Dns.GetHostEntryAsync(address.ToString()));
 
-        [Fact]
-        public void DnsBeginGetHostEntry_BadName_Throws()
-        {
-            IAsyncResult asyncObject = Dns.BeginGetHostEntry("BadName", null, null);
-            Assert.ThrowsAny<SocketException>(() => Dns.EndGetHostEntry(asyncObject));
+            await Assert.ThrowsAsync<ArgumentException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, address, null));
+            await Assert.ThrowsAsync<ArgumentException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, address.ToString(), null));
         }
 
         [Fact]
-        public void DnsBeginGetHostEntry_BadIpString_Throws()
+        public async Task DnsGetHostEntry_MachineName_AllVariationsMatch()
         {
-            IAsyncResult asyncObject = Dns.BeginGetHostEntry("0.0.1.1", null, null);
-            Assert.ThrowsAny<SocketException>(() => Dns.EndGetHostEntry(asyncObject));
-        }
+            IPHostEntry syncResult = Dns.GetHostEntry(TestSettings.LocalHost);
+            IPHostEntry apmResult = Dns.EndGetHostEntry(Dns.BeginGetHostEntry(TestSettings.LocalHost, null, null));
+            IPHostEntry asyncResult = await Dns.GetHostEntryAsync(TestSettings.LocalHost);
 
-        [Fact]
-        public void DnsBeginGetHostEntry_MachineName_MatchesGetHostEntry()
-        {
-            IAsyncResult asyncObject = Dns.BeginGetHostEntry(TestSettings.LocalHost, null, null);
-            IPHostEntry results = Dns.EndGetHostEntry(asyncObject);
-            IPHostEntry entry = Dns.GetHostEntry(TestSettings.LocalHost);
+            Assert.Equal(syncResult.HostName, apmResult.HostName);
+            Assert.Equal(syncResult.HostName, asyncResult.HostName);
 
-            Assert.Equal(entry.HostName, results.HostName);
-            Assert.Equal(entry.AddressList, results.AddressList);
+            Assert.Equal(syncResult.AddressList, apmResult.AddressList);
+            Assert.Equal(syncResult.AddressList, asyncResult.AddressList);
         }
 
         [Fact]
-        public void DnsBeginGetHostEntry_Loopback_MatchesGetHostEntry()
+        public async Task DnsGetHostEntry_Loopback_AllVariationsMatch()
         {
-            IAsyncResult asyncObject = Dns.BeginGetHostEntry(IPAddress.Loopback, null, null);
-            IPHostEntry results = Dns.EndGetHostEntry(asyncObject);
-            IPHostEntry entry = Dns.GetHostEntry(IPAddress.Loopback);
+            IPHostEntry syncResult = Dns.GetHostEntry(IPAddress.Loopback);
+            IPHostEntry apmResult = Dns.EndGetHostEntry(Dns.BeginGetHostEntry(IPAddress.Loopback, null, null));
+            IPHostEntry asyncResult = await Dns.GetHostEntryAsync(IPAddress.Loopback);
 
-            Assert.Equal(entry.HostName, results.HostName);
+            Assert.Equal(syncResult.HostName, apmResult.HostName);
+            Assert.Equal(syncResult.HostName, asyncResult.HostName);
 
-            Assert.Equal(entry.AddressList, results.AddressList);
+            Assert.Equal(syncResult.AddressList, apmResult.AddressList);
+            Assert.Equal(syncResult.AddressList, asyncResult.AddressList);
         }
 
-        [Fact]
-        public void DnsGetHostEntry_BadName_Throws()
-        {
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry("BadName"));
-        }
-
-        [Fact]
-        public void DnsGetHostEntry_BadIpString_Throws()
-        {
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry("0.0.1.1"));
-        }
-
-        [Fact]
-        public void DnsGetHostEntry_HostAlmostTooLong254Chars_Throws()
-        {
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry(
-                "Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee"
+        [Theory]
+        [InlineData("BadName")] // unknown name
+        [InlineData("0.0.1.1")] // unknown address
+        [InlineData("Test-\u65B0-Unicode")] // unknown unicode name
+        [InlineData("xn--test--unicode-0b01a")] // unknown punicode name
+        [InlineData("Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee"
                 + "eeeeend.Almost.There.Are.We.Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualll"
-                + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Are"));
-        }
-
-        [Fact]
-        public void DnsGetHostEntry_HostAlmostTooLong254CharsAndDot_Throws()
+                + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Are")] // very long name but not too long
+        public async Task DnsGetHostEntry_BadName_ThrowsSocketException(string hostNameOrAddress)
         {
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry(
-                "Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee"
-                + "eeeeend.Almost.There.Are.We.Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualll"
-                + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Are."));
+            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry(hostNameOrAddress));
+            await Assert.ThrowsAnyAsync<SocketException>(() => Dns.GetHostEntryAsync(hostNameOrAddress));
+            await Assert.ThrowsAnyAsync<SocketException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null));
         }
 
-        [Fact]
-        public void DnsGetHostEntry_HostTooLong255Chars_Throws()
-        {
-            Assert.ThrowsAny<ArgumentOutOfRangeException>(() => Dns.GetHostEntry(
-                "Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee"
+        [Theory]
+        [InlineData("Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualllllllly.I.Will.Get.To.The.Eeeee"
                 + "eeeeend.Almost.There.Are.We.Really.Long.Name.Over.One.Hundred.And.Twenty.Six.Chars.Eeeeeeeventualll"
-                + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Aret"));
+                + "llllly.I.Will.Get.To.The.Eeeeeeeeeend.Almost.There.Aret")]
+        public async Task DnsGetHostEntry_BadName_ThrowsArgumentOutOfRangeException(string hostNameOrAddress)
+        {
+            Assert.ThrowsAny<ArgumentOutOfRangeException>(() => Dns.GetHostEntry(hostNameOrAddress));
+            await Assert.ThrowsAnyAsync<ArgumentOutOfRangeException>(() => Dns.GetHostEntryAsync(hostNameOrAddress));
+            await Assert.ThrowsAnyAsync<ArgumentOutOfRangeException>(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null));
         }
 
-        [Fact]
-        public void DnsGetHostEntry_LocalHost_ReturnsFqdnAndLoopbackIPs()
+        [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(2)]
+        public async Task DnsGetHostEntry_LocalHost_ReturnsFqdnAndLoopbackIPs(int mode)
         {
-            IPHostEntry entry = Dns.GetHostEntry("localhost");
+            IPHostEntry entry = mode switch
+            {
+                0 => Dns.GetHostEntry("localhost"),
+                1 => await Dns.GetHostEntryAsync("localhost"),
+                _ => await Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, "localhost", null)
+            };
 
             Assert.NotNull(entry.HostName);
             Assert.True(entry.HostName.Length > 0, "Empty host name");
-
             Assert.True(entry.AddressList.Length >= 1, "No local IPs");
-            foreach (IPAddress addr in entry.AddressList)
-                Assert.True(IPAddress.IsLoopback(addr), "Not a loopback address: " + addr);
+            Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), "Not a loopback address: " + addr));
         }
 
-        [Fact]
-        public void DnsGetHostEntry_LoopbackIP_MatchesGetHostEntryLoopbackString()
+        [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(2)]
+        public async Task DnsGetHostEntry_LoopbackIP_MatchesGetHostEntryLoopbackString(int mode)
         {
-            IPHostEntry ipEntry = Dns.GetHostEntry(IPAddress.Loopback);
-            IPHostEntry stringEntry = Dns.GetHostEntry(IPAddress.Loopback.ToString());
+            IPAddress address = IPAddress.Loopback;
+
+            IPHostEntry ipEntry = mode switch
+            {
+                0 => Dns.GetHostEntry(address),
+                1 => await Dns.GetHostEntryAsync(address),
+                _ => await Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, address, null)
+            };
+            IPHostEntry stringEntry = mode switch
+            {
+                0 => Dns.GetHostEntry(address.ToString()),
+                1 => await Dns.GetHostEntryAsync(address.ToString()),
+                _ => await Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, address.ToString(), null)
+            };
 
             Assert.Equal(ipEntry.HostName, stringEntry.HostName);
             Assert.Equal(ipEntry.AddressList, stringEntry.AddressList);
         }
-
-        [Fact]
-        public void DnsGetHostEntry_UnknownUnicodeHost_HostNotFound()
-        {
-            // This would succeed if the name was registered in DNS
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry("Test-\u65B0-Unicode"));
-        }
-
-        [Fact]
-        public void DnsGetHostEntry_UnknownPunicodeHost_HostNotFound()
-        {
-            // This would succeed if the name was registered in DNS
-            Assert.ThrowsAny<SocketException>(() => Dns.GetHostEntry("xn--test--unicode-0b01a"));
-        }
     }
 }
index 0a76e96..5741d1a 100644 (file)
@@ -2,11 +2,7 @@
 // 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;
-using System.Net;
 using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Text;
 using System.Threading.Tasks;
 
 namespace System.Net.NameResolution.Tests
index e6777d4..96e5ad4 100644 (file)
@@ -2,8 +2,6 @@
 // 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.Diagnostics;
-
 namespace System.Net
 {
     internal static class IPAddressFakeExtensions
index d0dab1c..ed10320 100644 (file)
@@ -4,7 +4,6 @@
 
 using System.IO;
 using System.Net.Sockets;
-using System.Net.Test.Common;
 using System.Runtime.InteropServices;
 using Xunit;
 using Xunit.Abstractions;
@@ -36,29 +35,31 @@ namespace System.Net.NameResolution.PalTests
             Assert.NotNull(NameResolutionPal.GetHostName());
         }
 
-        [Fact]
-        public void TryGetAddrInfo_LocalHost()
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public void TryGetAddrInfo_LocalHost(bool justAddresses)
         {
-            IPHostEntry hostEntry;
-            int nativeErrorCode;
-            SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", out hostEntry, out nativeErrorCode);
+            SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode);
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
-            Assert.NotNull(hostEntry.HostName);
-            Assert.NotNull(hostEntry.AddressList);
-            Assert.NotNull(hostEntry.Aliases);
+            if (!justAddresses)
+            {
+                Assert.NotNull(hostName);
+            }
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
         }
 
-        [Fact]
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
         [OuterLoop("Uses external server")]
-        public void TryGetAddrInfo_HostName()
+        public void TryGetAddrInfo_HostName(bool justAddresses)
         {
             string hostName = NameResolutionPal.GetHostName();
             Assert.NotNull(hostName);
 
-            IPHostEntry hostEntry;
-            int nativeErrorCode;
-            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, out hostEntry, out nativeErrorCode);
+            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, justAddresses, out hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode);
             if (error == SocketError.HostNotFound && (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)))
             {
                 // On Unix, we are not guaranteed to be able to resove the local host. The ability to do so depends on the
@@ -67,10 +68,12 @@ namespace System.Net.NameResolution.PalTests
             }
 
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
-            Assert.NotNull(hostEntry.HostName);
-            Assert.NotNull(hostEntry.AddressList);
-            Assert.NotNull(hostEntry.Aliases);
+            if (!justAddresses)
+            {
+                Assert.NotNull(hostName);
+            }
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
         }
 
         [Fact]
@@ -101,13 +104,13 @@ namespace System.Net.NameResolution.PalTests
         [Fact]
         public void TryGetAddrInfo_LocalHost_TryGetNameInfo()
         {
-            IPHostEntry hostEntry;
-            int nativeErrorCode;
-            SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", out hostEntry, out nativeErrorCode);
+            SocketError error = NameResolutionPal.TryGetAddrInfo("localhost", justAddresses: false, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode);
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
+            Assert.NotNull(hostName);
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
 
-            string name = NameResolutionPal.TryGetNameInfo(hostEntry.AddressList[0], out error, out nativeErrorCode);
+            string name = NameResolutionPal.TryGetNameInfo(addresses[0], out error, out nativeErrorCode);
             Assert.Equal(SocketError.Success, error);
             Assert.NotNull(name);
         }
@@ -119,9 +122,7 @@ namespace System.Net.NameResolution.PalTests
             string hostName = NameResolutionPal.GetHostName();
             Assert.NotNull(hostName);
 
-            IPHostEntry hostEntry;
-            int nativeErrorCode;
-            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, out hostEntry, out nativeErrorCode);
+            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, justAddresses: false, out hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode);
             if (error == SocketError.HostNotFound)
             {
                 // On Unix, getaddrinfo returns host not found, if all the machine discovery settings on the local network
@@ -131,9 +132,11 @@ namespace System.Net.NameResolution.PalTests
             }
 
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
+            Assert.NotNull(hostName);
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
 
-            string name = NameResolutionPal.TryGetNameInfo(hostEntry.AddressList[0], out error, out nativeErrorCode);
+            string name = NameResolutionPal.TryGetNameInfo(addresses[0], out error, out nativeErrorCode);
             if (error == SocketError.HostNotFound)
             {
                 // On Unix, getaddrinfo returns private ipv4 address for hostname. If the OS doesn't have the
@@ -146,35 +149,38 @@ namespace System.Net.NameResolution.PalTests
             Assert.NotNull(name);
         }
 
-        [Fact]
-        public void TryGetAddrInfo_ExternalHost()
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public void TryGetAddrInfo_ExternalHost(bool justAddresses)
         {
             string hostName = "microsoft.com";
 
-            IPHostEntry hostEntry;
-            int nativeErrorCode;
-            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, out hostEntry, out nativeErrorCode);
+            SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, justAddresses, out hostName, out string[] aliases, out IPAddress[] addresses, out _);
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
         }
 
-        [Fact]
-        public void TryGetNameInfo_LocalHost_IPv4_TryGetAddrInfo()
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public void TryGetNameInfo_LocalHost_IPv4_TryGetAddrInfo(bool justAddresses)
         {
-            SocketError error;
-            int nativeErrorCode;
-            string name = NameResolutionPal.TryGetNameInfo(new IPAddress(new byte[] { 127, 0, 0, 1 }), out error, out nativeErrorCode);
+            string name = NameResolutionPal.TryGetNameInfo(new IPAddress(new byte[] { 127, 0, 0, 1 }), out SocketError error, out _);
             Assert.Equal(SocketError.Success, error);
             Assert.NotNull(name);
 
-            IPHostEntry hostEntry;
-            error = NameResolutionPal.TryGetAddrInfo(name, out hostEntry, out nativeErrorCode);
+            error = NameResolutionPal.TryGetAddrInfo(name, justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out _);
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
         }
 
-        [Fact]
-        public void TryGetNameInfo_LocalHost_IPv6_TryGetAddrInfo()
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public void TryGetNameInfo_LocalHost_IPv6_TryGetAddrInfo(bool justAddresses)
         {
             SocketError error;
             int nativeErrorCode;
@@ -187,15 +193,15 @@ namespace System.Net.NameResolution.PalTests
             Assert.Equal(SocketError.Success, error);
             Assert.NotNull(name);
 
-            IPHostEntry hostEntry;
-            error = NameResolutionPal.TryGetAddrInfo(name, out hostEntry, out nativeErrorCode);
+            error = NameResolutionPal.TryGetAddrInfo(name, justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out _);
             if (SocketError.Success != error && Environment.OSVersion.Platform == PlatformID.Unix)
             {
                 LogUnixInfo();
             }
 
             Assert.Equal(SocketError.Success, error);
-            Assert.NotNull(hostEntry);
+            Assert.NotNull(aliases);
+            Assert.NotNull(addresses);
         }
 
         [Fact]
index 1679260..174a698 100644 (file)
     <Compile Include="$(CommonPath)\System\Net\Logging\NetEventSource.Common.cs">
       <Link>Common\System\Net\Logging\NetEventSource.cs</Link>
     </Compile>
-    <Compile Include="..\..\src\System\Net\NameResolutionUtilities.cs">
-      <Link>ProductionCode\System\Net\NameResolutionUtilities.cs</Link>
-    </Compile>
-    <Compile Include="..\..\src\System\Net\DnsResolveAsyncResult.cs">
-      <Link>ProductionCode\System\Net\DnsResolveAsyncResult.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolType.cs" Condition="'$(OSGroup)' == 'Windows_NT'">
       <Link>Common\System\Net\Sockets\ProtocolType.cs</Link>
     </Compile>
@@ -77,9 +71,6 @@
     <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
       <Link>Interop\Windows\Interop.Libraries.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfo.cs">
-      <Link>Interop\Windows\WinSock\AddressInfo.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfoHints.cs">
       <Link>Interop\Windows\WinSock\AddressInfoHints.cs</Link>
     </Compile>
@@ -98,9 +89,6 @@
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.GetAddrInfoW.cs">
       <Link>Interop\Windows\WinSock\Interop.GetAddrInfoW.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.freeaddrinfo.cs">
-      <Link>Interop\Windows\Winsock\Interop.freeaddinfo.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.WSAStartup.cs">
       <Link>Interop\Windows\WinSock\Interop.WSAStartup.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolFamily.cs">
       <Link>Common\System\Net\Sockets\ProtocolFamily.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\SafeFreeAddrInfo.cs">
-      <Link>Interop\Windows\WinSock\SafeFreeAddrInfo.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Windows\WinSock\AddressInfoEx.cs">
-      <Link>Interop\Windows\WinSock\AddressInfoEx.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs">
       <Link>Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs</Link>
     </Compile>
index 69d1bc9..e66b3e0 100644 (file)
@@ -2,9 +2,8 @@
 // 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.Diagnostics;
 using System.Net.Sockets;
-using System.Threading;
+using System.Threading.Tasks;
 
 namespace System.Net
 {
@@ -35,7 +34,7 @@ namespace System.Net
             FakesEnsureSocketsAreInitializedCallCount++;
         }
 
-        internal static SocketError TryGetAddrInfo(string hostName, out IPHostEntry ipHostEntry, out int nativeErrorCode)
+        internal static SocketError TryGetAddrInfo(string name, bool justAddresses, out string hostName, out string[] aliases, out IPAddress[] addresses, out int nativeErrorCode)
         {
             throw new NotImplementedException();
         }
@@ -51,7 +50,7 @@ namespace System.Net
             throw new NotImplementedException();
         }
 
-        internal static void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+        internal static Task GetAddrInfoAsync(string hostName, bool justAddresses)
         {
             throw new NotImplementedException();
         }
index f8eb745..7a6818e 100644 (file)
     <Compile Include="..\..\src\System\Net\IPHostEntry.cs">
       <Link>ProductionCode\System\Net\IPHostEntry.cs</Link>
     </Compile>
-    <Compile Include="..\..\src\System\Net\DNS.cs">
-      <Link>ProductionCode\System\Net\DNS.cs</Link>
-    </Compile>
-    <Compile Include="..\..\src\System\Net\DnsResolveAsyncResult.cs">
-      <Link>ProductionCode\System\Net\DnsResolveAsyncResult.cs</Link>
+    <Compile Include="..\..\src\System\Net\Dns.cs">
+      <Link>ProductionCode\System\Net\Dns.cs</Link>
     </Compile>
   </ItemGroup>
   <ItemGroup>
@@ -43,5 +40,8 @@
     <Compile Include="$(CommonPath)\System\Net\InternalException.cs">
       <Link>Common\System\Net\InternalException.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\TaskToApm.cs">
+      <Link>Common\CoreLib\System\Threading\Tasks\TaskToApm.cs</Link>
+    </Compile>
   </ItemGroup>
 </Project>
\ No newline at end of file