using System;
using System.Runtime.InteropServices;
-using Microsoft.Win32.SafeHandles;
-
internal partial class Interop
{
internal partial class Kernel32
+++ /dev/null
-// 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
- }
-}
+++ /dev/null
-// 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
- }
-}
// 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]
{
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)]
[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
+ }
}
}
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
+ }
}
}
// 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
{
+++ /dev/null
-// 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);
- }
-}
+++ /dev/null
-// 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;
- }
- }
-}
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
{
_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
}
// 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;
<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>
<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>
<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")]
{
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)));
+ }
}
}
}
+++ /dev/null
-// 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;
- }
- }
-}
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; }
+ }
+}
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
+using System.Threading.Tasks;
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)
}
}
- 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 == "")
{
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*/];
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();
}
}
// 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)
const int NI_MAXHOST = 1025;
char* hostname = stackalloc char[NI_MAXHOST];
- nativeErrorCode = 0;
fixed (byte* addressBufferPtr = addressBuffer)
{
errorCode = Interop.Winsock.GetNameInfoW(
(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
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;
{
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)
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;
}
}
private unsafe struct GetAddrInfoExContext
{
public NativeOverlapped Overlapped;
- public AddressInfoEx* Result;
+ public Interop.Winsock.AddressInfoEx* Result;
public IntPtr CancelHandle;
public IntPtr QueryStateHandle;
{
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
}
}
+++ /dev/null
-// 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>()
- };
- }
- }
-}
public class GetHostByAddressTest
{
[Fact]
-
public void DnsObsoleteGetHostByAddress_BadIPString_Throws()
{
Assert.Throws<FormatException>(() => Dns.GetHostByAddress("badIPString"));
using System.Threading.Tasks;
using Xunit;
-using Xunit.Sdk;
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)
{
}
[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()
{
[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"));
- }
}
}
// 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
// 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
using System.IO;
using System.Net.Sockets;
-using System.Net.Test.Common;
using System.Runtime.InteropServices;
using Xunit;
using Xunit.Abstractions;
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
}
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]
[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);
}
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
}
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
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;
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]
<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>
<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>
<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>
// 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
{
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();
}
throw new NotImplementedException();
}
- internal static void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+ internal static Task GetAddrInfoAsync(string hostName, bool justAddresses)
{
throw new NotImplementedException();
}
<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>
<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