CS/PingAsync.cs
using System;
using System.Net; using System.Threading.Tasks; using System.Linq; using System.Net.NetworkInformation; using System.Net.Sockets; namespace Valentia.CS { public class DnsResponse { public string HostName { get; private set; } public IPAddress IPAddress { get; private set; } public bool IsResolved { get { IPAddress item = null; return !IPAddress.TryParse(this.HostName, out item); } } public DnsResponse(string hostName, IPAddress ip) { this.HostName = hostName; this.IPAddress = ip; } } public class DnsResolver { public static DnsResponse ResolveIP(IPAddress ip, TimeSpan timeout) { Func<IPAddress, IPHostEntry> callback = s => Dns.GetHostEntry(s); var result = callback.BeginInvoke(ip, null, null); if (!result.AsyncWaitHandle.WaitOne(timeout, false)) { return new DnsResponse(ip.ToString(), ip); } var hostEntry = callback.EndInvoke(result); return new DnsResponse(hostEntry.HostName, ip); } public static DnsResponse ResolveHostName(string hostNameOrAddress, TimeSpan timeout) { Func<string, IPHostEntry> callback = s => Dns.GetHostEntry(s); var result = callback.BeginInvoke(hostNameOrAddress, null, null); if (!result.AsyncWaitHandle.WaitOne(timeout, false)) { return new DnsResponse(hostNameOrAddress, null); } var hostEntry = callback.EndInvoke(result); var ip = hostEntry.AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork); return new DnsResponse(hostNameOrAddress, ip); } } public class PingResponse { public string HostNameOrAddress { get; set; } public IPAddress IPAddress { get; set; } public IPStatus Status { get; set; } public bool IsSuccess { get; set; } public long RoundTripTime { get; set; } public bool IsResolved { get; set; } } public class NetworkInformationExtensions { private static readonly byte[] _buffer = new byte[16]; private static readonly PingOptions _options = new PingOptions(64, false); private static readonly TimeSpan _pingTimeout = TimeSpan.FromMilliseconds(10); private static readonly TimeSpan _dnsTimeout = TimeSpan.FromMilliseconds(20); private static bool _resolveDns = true; public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress) { return await PingAsync(hostNameOrAddress, _pingTimeout, _resolveDns, _dnsTimeout); } public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout) { return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); } public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, bool resolveDns) { return await PingAsync(hostNameOrAddress, _pingTimeout, resolveDns, _dnsTimeout); } public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns) { return await PingAsync(hostNameOrAddress, pingTimeout, resolveDns, _dnsTimeout); } public static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, TimeSpan dnsTimeout) { return await PingAsync(hostNameOrAddress, pingTimeout, _resolveDns, _dnsTimeout); } private static async Task<PingResponse[]> PingAsync(string[] hostNameOrAddress, TimeSpan pingTimeout, bool resolveDns, TimeSpan dnsTimeout) { var pingResult = await Task.WhenAll(hostNameOrAddress.Select(async x => { // Resolve only when incoming is HostName. IPAddress ip = null; DnsResponse resolve = null; var isIpAddress = IPAddress.TryParse(x, out ip); if (!isIpAddress) { resolve = DnsResolver.ResolveHostName(x, dnsTimeout); ip = resolve.IPAddress; } // Execute PingAsync PingReply reply = null; using (var ping = new Ping()) { try { reply = await ping.SendPingAsync(ip, (int)pingTimeout.TotalMilliseconds, _buffer, _options); } catch { // ping throw should never stop operation. just return null. } } // set RoundtripTime long roundTripTime = 0; if (reply != null) roundTripTime = reply.RoundtripTime; // set Status var status = IPStatus.DestinationHostUnreachable; if (reply != null) status = reply.Status; // set IsSuccess var isSuccess = status == IPStatus.Success; // return when PingFailed || HostName || OmitResolveDns if (!isSuccess || !isIpAddress || !resolveDns) return new PingResponse { HostNameOrAddress = x, IPAddress = ip, Status = status, RoundTripTime = roundTripTime, IsSuccess = isSuccess, IsResolved = !isIpAddress && ip != null, }; // Resolve Dns only for success host entry. var host = x; resolve = DnsResolver.ResolveIP(ip, dnsTimeout); if (resolve != null) host = resolve.HostName; return new PingResponse { HostNameOrAddress = host, IPAddress = ip, Status = status, RoundTripTime = roundTripTime, IsSuccess = true, IsResolved = resolve != null && resolve.IsResolved, }; }).ToArray()); return pingResult; } } } |