Skip to content
Permalink
Browse files

Prepare Tor fallback work

  • Loading branch information...
nopara73 committed Dec 10, 2018
1 parent 4ea8a5c commit 3c5371486b15531152d8fce3d183f479728e91d2
@@ -12,6 +12,7 @@
using WalletWasabi.Helpers;
using WalletWasabi.Interfaces;
using WalletWasabi.Logging;
using WalletWasabi.TorSocks5;

namespace WalletWasabi.Gui
{
@@ -31,6 +32,12 @@ public class Config : IConfig
[JsonProperty(PropertyName = "TestNetBackendUriV3")]
public string TestNetBackendUriV3 { get; private set; }

[JsonProperty(PropertyName = "MainNetFallbackBackendUri")]
public string MainNetFallbackBackendUri { get; private set; }

[JsonProperty(PropertyName = "TestNetFallbackBackendUri")]
public string TestNetFallbackBackendUri { get; private set; }

[JsonProperty(PropertyName = "RegTestBackendUriV3")]
public string RegTestBackendUriV3 { get; private set; }

@@ -50,10 +57,16 @@ public class Config : IConfig
public int? TorSocks5Port { get; internal set; }

private Uri _backendUri;
private Uri _fallbackBackendUri;

public Uri GetCurrentBackendUri()
{
if (!(_backendUri is null)) return _backendUri;
if (TorProcessManager.RequestFallbackAddressUsage)
{
return GetFallbackBackendUri();
}

if (_backendUri != null) return _backendUri;

if (Network == Network.Main)
{
@@ -71,6 +84,26 @@ public Uri GetCurrentBackendUri()
return _backendUri;
}

public Uri GetFallbackBackendUri()
{
if (_fallbackBackendUri != null) return _fallbackBackendUri;

if (Network == Network.Main)
{
_fallbackBackendUri = new Uri(MainNetFallbackBackendUri);
}
else if (Network == Network.TestNet)
{
_fallbackBackendUri = new Uri(TestNetFallbackBackendUri);
}
else // RegTest
{
_fallbackBackendUri = new Uri(RegTestBackendUriV3);
}

return _fallbackBackendUri;
}

private IPEndPoint _torSocks5EndPoint;

public IPEndPoint GetTorSocks5EndPoint()
@@ -119,12 +152,15 @@ public Config(string filePath)
SetFilePath(filePath);
}

public Config(Network network, string mainNetBackendUriV3, string testNetBackendUriV3, string regTestBackendUriV3, string mainNetBlindingRsaPubKey, string testNetBlindingRsaPubKey, string regTestBlindingRsaPubKey, string torHost, int? torSocks5Port)
public Config(Network network, string mainNetBackendUriV3, string testNetBackendUriV3, string mainNetFallbackBackendUri, string testNetFallbackBackendUri, string regTestBackendUriV3, string mainNetBlindingRsaPubKey, string testNetBlindingRsaPubKey, string regTestBlindingRsaPubKey, string torHost, int? torSocks5Port)
{
Network = Guard.NotNull(nameof(network), network);

MainNetBackendUriV3 = Guard.NotNullOrEmptyOrWhitespace(nameof(mainNetBackendUriV3), mainNetBackendUriV3);
TestNetBackendUriV3 = Guard.NotNullOrEmptyOrWhitespace(nameof(testNetBackendUriV3), testNetBackendUriV3);
MainNetFallbackBackendUri = Guard.NotNullOrEmptyOrWhitespace(nameof(mainNetFallbackBackendUri), mainNetFallbackBackendUri);
TestNetFallbackBackendUri = Guard.NotNullOrEmptyOrWhitespace(nameof(testNetFallbackBackendUri), testNetFallbackBackendUri);
TestNetBackendUriV3 = Guard.NotNullOrEmptyOrWhitespace(nameof(testNetBackendUriV3), testNetBackendUriV3);
RegTestBackendUriV3 = Guard.NotNullOrEmptyOrWhitespace(nameof(regTestBackendUriV3), regTestBackendUriV3);

MainNetBlindingRsaPubKey = Guard.NotNullOrEmptyOrWhitespace(nameof(mainNetBlindingRsaPubKey), mainNetBlindingRsaPubKey);
@@ -155,6 +191,8 @@ public async Task LoadOrCreateDefaultFileAsync()

MainNetBackendUriV3 = "http://wasabiukrxmkdgve5kynjztuovbg43uxcbcxn6y2okcrsg7gb6jdmbad.onion/";
TestNetBackendUriV3 = "http://testwnp3fugjln6vh5vpj7mvq3lkqqwjj3c2aafyu7laxz42kgwh2rad.onion/";
MainNetFallbackBackendUri = "https://wasabiwallet.io/";
TestNetFallbackBackendUri = "https://wasabiwallet.co/";
RegTestBackendUriV3 = "http://localhost:37127/";

MainNetBlindingRsaPubKey = "16421152619146079007287475569112871971988560541093277613438316709041030720662622782033859387192362542996510605015506477964793447620206674394713753349543444988246276357919473682408472170521463339860947351211455351029147665615454176157348164935212551240942809518428851690991984017733153078846480521091423447691527000770982623947706172997649440619968085147635776736938871139581019988225202983052255684151711253254086264386774936200194229277914886876824852466823571396538091430866082004097086602287294474304344865162932126041736158327600847754258634325228417149098062181558798532036659383679712667027126535424484318399849";
@@ -189,6 +227,8 @@ public async Task LoadFileAsync()

MainNetBackendUriV3 = config.MainNetBackendUriV3 ?? MainNetBackendUriV3;
TestNetBackendUriV3 = config.TestNetBackendUriV3 ?? TestNetBackendUriV3;
MainNetFallbackBackendUri = config.MainNetFallbackBackendUri ?? MainNetFallbackBackendUri;
TestNetFallbackBackendUri = config.TestNetFallbackBackendUri ?? TestNetFallbackBackendUri;
RegTestBackendUriV3 = config.RegTestBackendUriV3 ?? RegTestBackendUriV3;

MainNetBlindingRsaPubKey = config.MainNetBlindingRsaPubKey ?? MainNetBlindingRsaPubKey;
@@ -221,17 +261,23 @@ public async Task<bool> CheckFileChangeAsync()
return true;
}

if (!MainNetBackendUriV3.Equals(config.MainNetBackendUriV3, StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (!TestNetBackendUriV3.Equals(config.TestNetBackendUriV3, StringComparison.OrdinalIgnoreCase))
{
return true;
}

if (!RegTestBackendUriV3.Equals(config.RegTestBackendUriV3, StringComparison.OrdinalIgnoreCase))
if (!MainNetFallbackBackendUri.Equals(config.MainNetFallbackBackendUri, StringComparison.OrdinalIgnoreCase))
{
return true;
}

if (!MainNetBackendUriV3.Equals(config.MainNetBackendUriV3, StringComparison.OrdinalIgnoreCase))
if (!TestNetFallbackBackendUri.Equals(config.TestNetFallbackBackendUri, StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (!RegTestBackendUriV3.Equals(config.RegTestBackendUriV3, StringComparison.OrdinalIgnoreCase))
{
return true;
}
@@ -137,7 +137,8 @@ public static void InitializeNoWallet()

TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), TorLogsFile);
TorManager.Start(false, DataDir);
TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir);
var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri);

Logger.LogInfo<TorProcessManager>($"{nameof(TorProcessManager)} is initialized.");

@@ -20,7 +20,25 @@ namespace WalletWasabi.TorSocks5
{
public class TorHttpClient : IDisposable
{
public static DateTimeOffset? TorDoesntWorkSince { get; private set; } = null; // This sets the first time the request failed with exception.
private static DateTimeOffset? TorDoesntWorkSinceBacking = null;

public static DateTimeOffset? TorDoesntWorkSince
{
get => TorDoesntWorkSinceBacking;
private set
{
if (value != TorDoesntWorkSinceBacking)
{
TorDoesntWorkSinceBacking = value;
if (value is null)
{
LatestTorException = null;
}
}
}
}

public static Exception LatestTorException { get; private set; } = null;

public Uri DestinationUri { get; }
public IPEndPoint TorSocks5EndPoint { get; }
@@ -112,26 +130,29 @@ public async Task<HttpResponseMessage> SendAsync(HttpMethod method, string relat
}
catch (TaskCanceledException ex)
{
if (TorDoesntWorkSince == null)
{
TorDoesntWorkSince = DateTimeOffset.UtcNow;
}
SetTorNotWorkingState(ex);
throw new OperationCanceledException(ex.Message, ex, cancel);
}
catch
catch (Exception ex)
{
if (TorDoesntWorkSince == null)
{
TorDoesntWorkSince = DateTimeOffset.UtcNow;
}
SetTorNotWorkingState(ex);
throw;
}
}

private static void SetTorNotWorkingState(Exception ex)
{
if (TorDoesntWorkSince == null)
{
TorDoesntWorkSince = DateTimeOffset.UtcNow;
}
LatestTorException = ex;
}

/// <remarks>
/// Throws OperationCancelledException if <paramref name="cancel"/> is set.
/// </remarks>
private async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancel = default)
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancel = default)
{
Guard.NotNull(nameof(request), request);

@@ -2,12 +2,15 @@
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Exceptions;
using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.TorSocks5.Models.Fields.OctetFields;
using WalletWasabi.WebClients.Wasabi;

namespace WalletWasabi.TorSocks5
{
@@ -16,6 +19,8 @@ public class TorProcessManager : IDisposable
public IPEndPoint TorSocks5EndPoint { get; }
public string LogFile { get; }

public static bool RequestFallbackAddressUsage { get; private set; } = false;

public Process TorProcess { get; private set; }

/// <param name="torSocks5EndPoint">Opt out Tor with null.</param>
@@ -206,7 +211,7 @@ public async Task<bool> IsTorRunningAsync()

private CancellationTokenSource Stop { get; }

public void StartMonitor(TimeSpan torMisbehaviorCheckPeriod, TimeSpan checkIfRunningAfterTorMisbehavedFor, string dataDirToStartWith)
public void StartMonitor(TimeSpan torMisbehaviorCheckPeriod, TimeSpan checkIfRunningAfterTorMisbehavedFor, string dataDirToStartWith, Uri fallBackTestRequestUri)
{
Logger.LogInfo<TorProcessManager>("Starting Tor monitor...");
Interlocked.Exchange(ref _running, 1);
@@ -224,22 +229,51 @@ public void StartMonitor(TimeSpan torMisbehaviorCheckPeriod, TimeSpan checkIfRun

await Task.Delay(torMisbehaviorCheckPeriod, Stop.Token).ConfigureAwait(false);

if (!(TorHttpClient.TorDoesntWorkSince is null)) // If Tor misbehaves.
if (TorHttpClient.TorDoesntWorkSince != null) // If Tor misbehaves.
{
TimeSpan torMisbehavedFor = (DateTimeOffset.UtcNow - TorHttpClient.TorDoesntWorkSince) ?? TimeSpan.Zero;

if (torMisbehavedFor > checkIfRunningAfterTorMisbehavedFor)
{
Logger.LogInfo<TorProcessManager>($"Tor didn't work properly for {(int)torMisbehavedFor.TotalSeconds} seconds. Maybe it crashed. Attempting to start it...");
Start(true, dataDirToStartWith); // Try starting Tor, if doesn't work it'll be another issue.
await Task.Delay(14000, Stop.Token).ConfigureAwait(false);
if (TorHttpClient.LatestTorException is TorSocks5FailureResponseException torEx)
{
if (torEx.RepField == RepField.HostUnreachable)
{
using (var client = new TorHttpClient(new Uri(fallBackTestRequestUri.DnsSafeHost), TorSocks5EndPoint))
{
var message = new HttpRequestMessage(HttpMethod.Get, fallBackTestRequestUri);
await client.SendAsync(message, Stop.Token);
}

// Check if it changed in the meantime...
if (TorHttpClient.LatestTorException is TorSocks5FailureResponseException torEx2 && torEx2.RepField == RepField.HostUnreachable)
{
// Fallback here...
RequestFallbackAddressUsage = true;
}
}
}
else
{
Logger.LogInfo<TorProcessManager>($"Tor didn't work properly for {(int)torMisbehavedFor.TotalSeconds} seconds. Maybe it crashed. Attempting to start it...");
Start(true, dataDirToStartWith); // Try starting Tor, if doesn't work it'll be another issue.
await Task.Delay(14000, Stop.Token).ConfigureAwait(false);
}
}
}
}
catch (TaskCanceledException ex)
{
Logger.LogTrace<TorProcessManager>(ex);
}
catch (OperationCanceledException ex)
{
Logger.LogTrace<TorProcessManager>(ex);
}
catch (TimeoutException ex)
{
Logger.LogTrace<TorProcessManager>(ex);
}
catch (Exception ex)
{
Logger.LogDebug<TorProcessManager>(ex);
@@ -115,7 +115,7 @@ public async Task<IEnumerable<ExchangeRate>> GetExchangeRatesAsync()

#region software

public async Task<(Version ClientVersion, int BackendMajorVersion)> GetVersionsAsync(CancellationToken cancel)
public async Task<(Version ClientVersion, int BackendMajorVersion)> GetVersionsAsync(CancellationToken cancel, bool setErrorState = true)
{
using (var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, "/api/software/versions", cancel: cancel))
{

0 comments on commit 3c53714

Please sign in to comment.
You can’t perform that action at this time.