Skip to content

Commit d79061a

Browse files
committed
Fix resolver list reload on startup
1 parent af633cf commit d79061a

8 files changed

Lines changed: 190 additions & 48 deletions

File tree

SimpleDnsCrypt/SimpleDnsCrypt.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
<DependentUpon>Strings.resx</DependentUpon>
149149
</Compile>
150150
<Compile Include="Tools\ApplicationUpdater.cs" />
151+
<Compile Include="Tools\AsyncHelpers.cs" />
151152
<Compile Include="Tools\DnsCryptProxyListManager.cs" />
152153
<Compile Include="Tools\DnscryptProxyManager.cs" />
153154
<Compile Include="Tools\IShell.cs" />
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace SimpleDnsCrypt.Tools
7+
{
8+
/// <summary>
9+
/// http://stackoverflow.com/a/5097066/1837988
10+
/// </summary>
11+
public static class AsyncHelpers
12+
{
13+
/// <summary>
14+
/// Execute's an async Task<T> method which has a void return value synchronously
15+
/// </summary>
16+
/// <param name="task">Task<T> method to execute</param>
17+
public static void RunSync(Func<Task> task)
18+
{
19+
var oldContext = SynchronizationContext.Current;
20+
var synch = new ExclusiveSynchronizationContext();
21+
SynchronizationContext.SetSynchronizationContext(synch);
22+
synch.Post(async _ =>
23+
{
24+
try
25+
{
26+
await task();
27+
}
28+
catch (Exception e)
29+
{
30+
synch.InnerException = e;
31+
throw;
32+
}
33+
finally
34+
{
35+
synch.EndMessageLoop();
36+
}
37+
}, null);
38+
synch.BeginMessageLoop();
39+
40+
SynchronizationContext.SetSynchronizationContext(oldContext);
41+
}
42+
43+
/// <summary>
44+
/// Execute's an async Task<T> method which has a T return type synchronously
45+
/// </summary>
46+
/// <typeparam name="T">Return Type</typeparam>
47+
/// <param name="task">Task<T> method to execute</param>
48+
/// <returns></returns>
49+
public static T RunSync<T>(Func<Task<T>> task)
50+
{
51+
var oldContext = SynchronizationContext.Current;
52+
var synch = new ExclusiveSynchronizationContext();
53+
SynchronizationContext.SetSynchronizationContext(synch);
54+
T ret = default(T);
55+
synch.Post(async _ =>
56+
{
57+
try
58+
{
59+
ret = await task();
60+
}
61+
catch (Exception e)
62+
{
63+
synch.InnerException = e;
64+
throw;
65+
}
66+
finally
67+
{
68+
synch.EndMessageLoop();
69+
}
70+
}, null);
71+
synch.BeginMessageLoop();
72+
SynchronizationContext.SetSynchronizationContext(oldContext);
73+
return ret;
74+
}
75+
76+
private class ExclusiveSynchronizationContext : SynchronizationContext
77+
{
78+
private bool done;
79+
public Exception InnerException { get; set; }
80+
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
81+
readonly Queue<Tuple<SendOrPostCallback, object>> items =
82+
new Queue<Tuple<SendOrPostCallback, object>>();
83+
84+
public override void Send(SendOrPostCallback d, object state)
85+
{
86+
throw new NotSupportedException("We cannot send to our same thread");
87+
}
88+
89+
public override void Post(SendOrPostCallback d, object state)
90+
{
91+
lock (items)
92+
{
93+
items.Enqueue(Tuple.Create(d, state));
94+
}
95+
workItemsWaiting.Set();
96+
}
97+
98+
public void EndMessageLoop()
99+
{
100+
Post(_ => done = true, null);
101+
}
102+
103+
public void BeginMessageLoop()
104+
{
105+
while (!done)
106+
{
107+
Tuple<SendOrPostCallback, object> task = null;
108+
lock (items)
109+
{
110+
if (items.Count > 0)
111+
{
112+
task = items.Dequeue();
113+
}
114+
}
115+
if (task != null)
116+
{
117+
task.Item1(task.Item2);
118+
if (InnerException != null) // the method threw an exeption
119+
{
120+
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
121+
}
122+
}
123+
else
124+
{
125+
workItemsWaiting.WaitOne();
126+
}
127+
}
128+
}
129+
130+
public override SynchronizationContext CreateCopy()
131+
{
132+
return this;
133+
}
134+
}
135+
}
136+
}

SimpleDnsCrypt/ViewModels/MainViewModel.cs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public sealed class MainViewModel : Screen, IShell
3232
private bool _actAsGlobalGateway;
3333
private bool _isPrimaryResolverRunning;
3434
private bool _isRefreshingResolverList;
35-
private bool _isSecondaryResolverRunning;
35+
private bool _updateResolverListOnStart;
36+
private bool _isSecondaryResolverRunning;
3637
private bool _isUninstallingServices;
3738
private bool _isWorkingOnPrimaryService;
3839
private bool _isWorkingOnSecondaryService;
@@ -92,6 +93,8 @@ private MainViewModel(IWindowManager windowManager, IEventAggregator eventAggreg
9293
DisplayName = string.Format("{0} {1} ({2})", Global.ApplicationName, VersionUtilities.PublishVersion,
9394
LocalizationEx.GetUiString("global_ipv6_disabled", Thread.CurrentThread.CurrentCulture));
9495
_resolvers = new List<DnsCryptProxyEntry>();
96+
//TODO: make UpdateResolverListOnStart configurable by user
97+
_updateResolverListOnStart = Global.UpdateResolverListOnStart;
9598
_isWorkingOnPrimaryService = false;
9699
_isWorkingOnSecondaryService = false;
97100

@@ -129,16 +132,13 @@ private MainViewModel(IWindowManager windowManager, IEventAggregator eventAggreg
129132
Global.DnsCryptProxyFolder, Global.DnsCryptProxyResolverListName);
130133
var proxyListSignature = Path.Combine(Directory.GetCurrentDirectory(),
131134
Global.DnsCryptProxyFolder, Global.DnsCryptProxySignatureFileName);
132-
//TODO: make UpdateResolverListOnStart configurable
133-
if (!File.Exists(proxyList) || !File.Exists(proxyListSignature) || Global.UpdateResolverListOnStart)
135+
if (!File.Exists(proxyList) || !File.Exists(proxyListSignature) || UpdateResolverListOnStart)
134136
{
135-
// download and verify the proxy list if there is none.
136-
// it`s a really small file, so go on.
137-
RefreshResolverList();
138-
//DnsCryptProxyListManager.UpdateResolverListAsync().ConfigureAwait(false);
139-
}
137+
// download and verify the proxy list if there is no one.
138+
AsyncHelpers.RunSync(DnsCryptProxyListManager.UpdateResolverListAsync);
139+
}
140140

141-
var dnsProxyList =
141+
var dnsProxyList =
142142
DnsCryptProxyListManager.ReadProxyList(proxyList, proxyListSignature, true);
143143
if (dnsProxyList != null && dnsProxyList.Any())
144144
{
@@ -173,8 +173,8 @@ private MainViewModel(IWindowManager windowManager, IEventAggregator eventAggreg
173173
Environment.Exit(1);
174174
}
175175

176-
// if there is no selected primary resolver, add a default resolver
177-
if (PrimaryResolver == null)
176+
// if there is no selected primary resolver, add a default resolver
177+
if (PrimaryResolver == null)
178178
{
179179
var tmpResolver = dnsProxyList.SingleOrDefault(d => d.Name.Equals(Global.DefaultPrimaryResolverName));
180180
if (tmpResolver == null)
@@ -313,10 +313,23 @@ public bool ShowHiddenCards
313313
}
314314
}
315315

316-
/// <summary>
317-
/// Formatted name of the primary resolver.
318-
/// </summary>
319-
public string PrimaryResolverTitle
316+
/// <summary>
317+
/// Update the resolver csv on startup.
318+
/// </summary>
319+
public bool UpdateResolverListOnStart
320+
{
321+
get { return _updateResolverListOnStart; }
322+
set
323+
{
324+
_updateResolverListOnStart = value;
325+
NotifyOfPropertyChange(() => UpdateResolverListOnStart);
326+
}
327+
}
328+
329+
/// <summary>
330+
/// Formatted name of the primary resolver.
331+
/// </summary>
332+
public string PrimaryResolverTitle
320333
{
321334
get { return _primaryResolverTitle; }
322335
set
@@ -419,8 +432,8 @@ private async void UpdateAsync()
419432
var update = await ApplicationUpdater.CheckForRemoteUpdateAsync().ConfigureAwait(true);
420433
if (update.CanUpdate)
421434
{
422-
var boxType = (update.Update.Type == UpdateType.Standard) ? BoxType.Default : BoxType.Warning;
423-
var boxText = (update.Update.Type == UpdateType.Standard)
435+
var boxType = update.Update.Type == UpdateType.Standard ? BoxType.Default : BoxType.Warning;
436+
var boxText = update.Update.Type == UpdateType.Standard
424437
? LocalizationEx.GetUiString("dialog_message_update_standard_text",
425438
Thread.CurrentThread.CurrentCulture)
426439
: LocalizationEx.GetUiString("dialog_message_update_critical_text",
@@ -773,17 +786,17 @@ await Task.Run(() =>
773786
}
774787
}
775788

776-
/// <summary>
777-
/// Refresh the resolver list from the newest csv file.
778-
/// </summary>
779-
/// <exception cref="UnauthorizedAccessException"></exception>
780-
/// <exception cref="NotSupportedException"></exception>
781-
/// <exception cref="ArgumentOutOfRangeException"></exception>
782-
/// <exception cref="ArgumentException"></exception>
783-
/// <exception cref="ArgumentNullException"></exception>
784-
public async void RefreshResolverList()
789+
/// <summary>
790+
/// Refresh the resolver list from the newest csv file.
791+
/// </summary>
792+
/// <exception cref="UnauthorizedAccessException"></exception>
793+
/// <exception cref="NotSupportedException"></exception>
794+
/// <exception cref="ArgumentOutOfRangeException"></exception>
795+
/// <exception cref="ArgumentException"></exception>
796+
/// <exception cref="ArgumentNullException"></exception>
797+
public async void RefreshResolverListAsync()
785798
{
786-
IsRefreshingResolverList = true;
799+
IsRefreshingResolverList = true;
787800
var state = await DnsCryptProxyListManager.UpdateResolverListAsync().ConfigureAwait(false);
788801
await Task.Run(() =>
789802
{
@@ -800,22 +813,24 @@ await Task.Run(() =>
800813
DnsCryptProxyListManager.ReadProxyList(proxyList, proxyListSignature, true);
801814
if (dnsProxyList != null && dnsProxyList.Any())
802815
{
803-
_resolvers.Clear();
816+
Resolvers.Clear();
804817
foreach (var dnsProxy in dnsProxyList)
805818
{
806819
if (
807820
dnsProxy.ProviderPublicKey.Equals(
808821
PrimaryDnsCryptProxyManager.DnsCryptProxy.Parameter.ProviderKey))
809822
{
810823
_primaryResolver = dnsProxy;
811-
}
824+
// restore the local port
825+
_primaryResolver.LocalPort = PrimaryDnsCryptProxyManager.DnsCryptProxy.Parameter.LocalPort;
826+
}
812827
if (
813828
dnsProxy.ProviderPublicKey.Equals(
814829
SecondaryDnsCryptProxyManager.DnsCryptProxy.Parameter.ProviderKey))
815830
{
816831
_secondaryResolver = dnsProxy;
817832
}
818-
_resolvers.Add(dnsProxy);
833+
Resolvers.Add(dnsProxy);
819834
}
820835
}
821836
}
@@ -825,6 +840,7 @@ await Task.Run(() =>
825840
LocalizationEx.GetUiString("dialog_message_refresh_failed", Thread.CurrentThread.CurrentCulture),
826841
LocalizationEx.GetUiString("dialog_warning_title", Thread.CurrentThread.CurrentCulture),
827842
MessageBoxButton.OK, BoxType.Warning);
843+
828844
}
829845
IsRefreshingResolverList = false;
830846
}

SimpleDnsCrypt/Views/MainView.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@
590590
Foreground="{DynamicResource AccentColorBrush}"
591591
Margin="15,16" HorizontalAlignment="Center"
592592
VerticalAlignment="Center" Grid.ColumnSpan="2" />
593-
<Button x:Name="RefreshResolverList" Grid.Column="2"
593+
<Button x:Name="RefreshResolverListAsync" Grid.Column="2"
594594
IsEnabled="{Binding IsRefreshingResolverList, Converter={StaticResource ReverseBoolToEnabledConverter}}"
595595
Cursor="Hand" Width="180" Content="{lex:Loc Key=advanced_settings_refresh_resolver_button}"
596596
Margin="0,10,0,0" Style="{StaticResource AccentedSquareButtonStyle}"
-369 KB
Binary file not shown.
-31 KB
Binary file not shown.

0 commit comments

Comments
 (0)