Skip to content

Commit

Permalink
DnsResolver refactoring.
Browse files Browse the repository at this point in the history
Imported Wokhan UI libs and helpers (manually, will add them to github / nuget soon).
Note: Looks like the icons are not showing up properly everytime in the Connections page. Double check required.
  • Loading branch information
wokhan committed Mar 10, 2020
1 parent c5c3b8f commit 50c3636
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 187 deletions.
5 changes: 5 additions & 0 deletions Common/Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
<PackageReference Include="System.Management" Version="4.7.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Wokhan.Core">
<HintPath>..\TempSharedLib\Wokhan.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Shield.ico" />
</ItemGroup>
Expand Down
132 changes: 53 additions & 79 deletions Common/Net/Dns/DnsResolver.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Wokhan.Collections;
using Wokhan.WindowsFirewallNotifier.Common.Helpers;

/// <summary>
Expand All @@ -20,111 +22,83 @@ public static class DnsResolver
/// <summary>
/// Dictionary of resolved IP addresses.
/// </summary>
public static readonly Dictionary<IPAddress, CachedIPHostEntry> CachedIPHostEntryDict = new Dictionary<IPAddress, CachedIPHostEntry>();

public static async Task ResolveIpAddresses(IEnumerable<string> ipAddressList, int maxEntriesToResolve = 1000)
{
if (ipAddressList == null)
{
return;
}

var ipList = ipAddressList.Select(s => IPAddress.TryParse(s, out IPAddress parsedIP) ? parsedIP : LogHelper.WarnAndReturn<IPAddress>($"Cannot parse IP {s}", null));

await ResolveIpAddresses(ipList, maxEntriesToResolve).ConfigureAwait(false);
}
/// <summary>
/// Resolves given ip addresses to IPHostEntry and stores them in CachedIPHostEntryDict.
/// </summary>
/// <param name="ipAddressList">IP address list to resolve</param>
/// <param name="maxEntriesToResolve">Max entries to resolve for this task</param>
/// <returns></returns>
public static async Task ResolveIpAddresses(IEnumerable<IPAddress> ipAddressList, int maxEntriesToResolve = 1000)
{
await Task.Run(() =>
{
ipAddressList.Take(maxEntriesToResolve)
.AsParallel()
.ForAll(ip => ResolveIP(ip));
}).ConfigureAwait(false);
}
public static readonly ObservableDictionary<IPAddress, CachedIPHostEntry> CachedIPHostEntryDict = new ObservableDictionary<IPAddress, CachedIPHostEntry>();

[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "<Pending>")]
public static async Task<CachedIPHostEntry> ResolveIpAddress(string ip)
public static async void ResolveIpAddress(string ip, Action<CachedIPHostEntry> updateRemoteHostNameCallback)
{
return await Task.Run(() =>
await Task.Run(() =>
{
if (!IsIPValid(ip))
{
return CachedIPHostEntry.EMTPY;
updateRemoteHostNameCallback(CachedIPHostEntry.EMTPY);
return;
}
IPAddress ipa = null;
try
{
ipa = IPAddress.Parse(ip);
ResolveIP(ipa);
return CachedIPHostEntryDict[ipa];
} catch (Exception e)
{
return CachedIPHostEntry.CreateErrorEntry(ipa, e);
}
}).ConfigureAwait(false);
}

internal static bool IsIPValid(string ip) => !string.IsNullOrWhiteSpace(ip) && ip != "0.0.0.0" && ip != "::" && ip != "::0";
try
{
if (CachedIPHostEntryDict.ContainsKey(ipa))
{
NotifyCollectionChangedEventHandler add = (sender, args) =>
{
if (args.Action == NotifyCollectionChangedAction.Replace)
{
var entry = (KeyValuePair<IPAddress, CachedIPHostEntry>)args.NewItems[0];
if (entry.Key == ipa)
updateRemoteHostNameCallback(entry.Value);
}
};
CachedIPHostEntryDict.CollectionChanged += add;
CachedIPHostEntryDict.CollectionChanged += (s, e) => CachedIPHostEntryDict.CollectionChanged -= add;
}
else
{
PutEntry(ipa, CachedIPHostEntry.EMTPY); // reserve slot
updateRemoteHostNameCallback(CachedIPHostEntry.EMTPY);

public static string getResolvedHostName(string ipAddress)
{
if (!IsIPValid(ipAddress))
{
return "invalid ip";
}
CachedIPHostEntryDict.TryGetValue(IPAddress.Parse(ipAddress), out CachedIPHostEntry ipHost);
if (ipHost == null)
{
return "unkown host";
}
return ipHost.DisplayText;
}
// http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Net/System/Net/DNS@cs/1305376/DNS@cs
IPHostEntry resolvedEntry = System.Net.Dns.GetHostEntry(ipa);
var entry = new CachedIPHostEntry
{
HostEntry = resolvedEntry,
IsResolved = true,
DisplayText = resolvedEntry.HostName
};
PutEntry(ipa, entry);
}
}
catch (Exception e)
{
PutEntry(ipa, CachedIPHostEntry.CreateErrorEntry(ipa, e));
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "<Pending>")]
private static void ResolveIP(IPAddress ip)
{
try
{
if (!CachedIPHostEntryDict.ContainsKey(ip))
updateRemoteHostNameCallback(CachedIPHostEntryDict[ipa]);
}
catch (Exception e)
{
PutEntry(ip, CachedIPHostEntry.EMTPY); // reserve slot
// http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Net/System/Net/DNS@cs/1305376/DNS@cs
IPHostEntry resolvedEntry = System.Net.Dns.GetHostEntry(address: ip);
var entry = new CachedIPHostEntry
{
HostEntry = resolvedEntry,
IsResolved = true,
DisplayText = resolvedEntry.HostName
};
PutEntry(ip, entry);
updateRemoteHostNameCallback(CachedIPHostEntry.CreateErrorEntry(ipa, e));
}
}
catch (Exception e)
{
PutEntry(ip, CachedIPHostEntry.CreateErrorEntry(ip, e));
}
}).ConfigureAwait(false);
}

internal static bool IsIPValid(string ip) => !string.IsNullOrWhiteSpace(ip) && ip != "0.0.0.0" && ip != "::" && ip != "::0";

private static void PutEntry(IPAddress ip, CachedIPHostEntry entry)
{
lock (CachedIPHostEntryDict)
{
if (CachedIPHostEntryDict.ContainsKey(ip))
if (CachedIPHostEntryDict.TryAdd(ip, entry))
{
CachedIPHostEntryDict[ip] = entry;
LogHelper.Debug($"End resolve IPHostEntry for {ip}: IsResolved={entry.IsResolved}, HasErrors={entry.HasErrors}, ToolTipText={entry.DisplayText}");
LogHelper.Debug($"Start resolve IPHostEntry for {ip}: IsResolved={entry.IsResolved}, HasErrors={entry.HasErrors}, ToolTipText={entry.DisplayText}");
}
else
{
CachedIPHostEntryDict.Add(ip, entry);
LogHelper.Debug($"Start resolve IPHostEntry for {ip}: IsResolved={entry.IsResolved}, HasErrors={entry.HasErrors}, ToolTipText={entry.DisplayText}");
CachedIPHostEntryDict[ip] = entry;
LogHelper.Debug($"End resolve IPHostEntry for {ip}: IsResolved={entry.IsResolved}, HasErrors={entry.HasErrors}, ToolTipText={entry.DisplayText}");
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions Console/Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="Wokhan.Core">
<HintPath>..\TempSharedLib\Wokhan.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Resource Include="version.xml" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 50c3636

Please sign in to comment.