diff --git a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs index b6543a6e1..588b624be 100644 --- a/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs +++ b/Duplicati/Library/Backend/AlternativeFTP/AlternativeFTPBackend.cs @@ -450,6 +450,11 @@ namespace Duplicati.Library.Backend.AlternativeFTP } } + public string DNSName + { + get { return null; } + } + private static System.IO.Stream StringToStream(string str) { var stream = new System.IO.MemoryStream(); diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs b/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs index 520d9a06c..099eed1b3 100644 --- a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs +++ b/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs @@ -457,6 +457,12 @@ namespace Duplicati.Library.Backend.AmazonCloudDrive return Strings.AmzCD.Description; } } + + public string DNSName + { + get { return null; } + } + #endregion #region IDisposable implementation public void Dispose() diff --git a/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs b/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs index d55eb17b0..a6cb8af56 100644 --- a/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs +++ b/Duplicati/Library/Backend/AzureBlob/AzureBlobBackend.cs @@ -157,8 +157,13 @@ namespace Duplicati.Library.Backend.AzureBlob { return Strings.AzureBlobBackend.Description_v2; } - } - + } + + public string DNSName + { + get { return null; } + } + public void Test() { this.TestList(); diff --git a/Duplicati/Library/Backend/Backblaze/B2.cs b/Duplicati/Library/Backend/Backblaze/B2.cs index 35ec87393..a93afb06d 100644 --- a/Duplicati/Library/Backend/Backblaze/B2.cs +++ b/Duplicati/Library/Backend/Backblaze/B2.cs @@ -422,6 +422,11 @@ namespace Duplicati.Library.Backend.Backblaze get { return Strings.B2.Description; } } + public string DNSName + { + get { return null; } + } + public void Dispose() { } diff --git a/Duplicati/Library/Backend/Box/BoxBackend.cs b/Duplicati/Library/Backend/Box/BoxBackend.cs index b20b259c7..71d67227c 100644 --- a/Duplicati/Library/Backend/Box/BoxBackend.cs +++ b/Duplicati/Library/Backend/Box/BoxBackend.cs @@ -337,6 +337,11 @@ namespace Duplicati.Library.Backend.Box } } + public string DNSName + { + get { return null; } + } + #endregion #region IDisposable implementation diff --git a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs index 82793def0..62a0cdcc1 100644 --- a/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs +++ b/Duplicati/Library/Backend/CloudFiles/CloudFiles.cs @@ -290,6 +290,11 @@ namespace Duplicati.Library.Backend get { return true; } } + public string DNSName + { + get { return null; } + } + public void Get(string remotename, System.IO.Stream stream) { var req = CreateRequest("/" + remotename, ""); diff --git a/Duplicati/Library/Backend/Dropbox/Dropbox.cs b/Duplicati/Library/Backend/Dropbox/Dropbox.cs index 281395868..c98ef226d 100644 --- a/Duplicati/Library/Backend/Dropbox/Dropbox.cs +++ b/Duplicati/Library/Backend/Dropbox/Dropbox.cs @@ -136,6 +136,11 @@ namespace Duplicati.Library.Backend public string Description { get { return Strings.Dropbox.Description; } } + public string DNSName + { + get { return null; } + } + public void Test() { this.TestList(); diff --git a/Duplicati/Library/Backend/FTP/FTPBackend.cs b/Duplicati/Library/Backend/FTP/FTPBackend.cs index e09bd165e..6f3e8b9dc 100644 --- a/Duplicati/Library/Backend/FTP/FTPBackend.cs +++ b/Duplicati/Library/Backend/FTP/FTPBackend.cs @@ -355,6 +355,11 @@ namespace Duplicati.Library.Backend } } + public string DNSName + { + get { return null; } + } + public void Test() { this.TestList(); diff --git a/Duplicati/Library/Backend/File/FileBackend.cs b/Duplicati/Library/Backend/File/FileBackend.cs index 343234e13..dec47fcf1 100644 --- a/Duplicati/Library/Backend/File/FileBackend.cs +++ b/Duplicati/Library/Backend/File/FileBackend.cs @@ -351,6 +351,11 @@ namespace Duplicati.Library.Backend } } + public string DNSName + { + get { return null; } + } + public void Rename(string oldname, string newname) { var source = GetRemoteName(oldname); diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs index 1d8bc335c..2bca35acb 100644 --- a/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs +++ b/Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs @@ -260,6 +260,12 @@ namespace Duplicati.Library.Backend.GoogleCloudStorage { get { return Strings.GoogleCloudStorage.Description; } } + + public string DNSName + { + get { return null; } + } + #endregion public void Put(string remotename, System.IO.Stream stream) diff --git a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs index 29bf82b3e..0c69c2813 100644 --- a/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs +++ b/Duplicati/Library/Backend/GoogleServices/GoogleDrive.cs @@ -346,6 +346,12 @@ namespace Duplicati.Library.Backend.GoogleDrive } } } + + public string DNSName + { + get { return null; } + } + #endregion #region IRenameEnabledBackend implementation diff --git a/Duplicati/Library/Backend/HubiC/HubiCBackend.cs b/Duplicati/Library/Backend/HubiC/HubiCBackend.cs index 1f8fb03c0..ea42996ca 100644 --- a/Duplicati/Library/Backend/HubiC/HubiCBackend.cs +++ b/Duplicati/Library/Backend/HubiC/HubiCBackend.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2015, The Duplicati Team +// Copyright (C) 2015, The Duplicati Team // http://www.duplicati.com, info@duplicati.com // // This library is free software; you can redistribute it and/or modify @@ -14,13 +14,181 @@ // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using System; using Duplicati.Library.Interface; using Duplicati.Library; using Duplicati.Library.Backend.OpenStack; using System.Collections.Generic; +using System; +using Duplicati.Library.Interface; +using Duplicati.Library; +using Duplicati.Library.Backend.OpenStack; +using System.Collections.Generic; namespace Duplicati.Library.Backend.HubiC { public class HubiCBackend : IBackend, IStreamingBackend - { private const string AUTHID_OPTION = "authid"; private const string HUBIC_API_URL = "https://api.hubic.com/1.0/"; private const string HUBIC_API_CREDENTIAL_URL = HUBIC_API_URL + "account/credentials"; private OpenStackStorage m_openstack; private class HubiCAuthResponse { public string token { get; set; } public string endpoint { get; set; } public DateTime? expires { get; set;} } private class OpenStackHelper : OpenStackStorage { private OAuthHelper m_helper; private HubiCAuthResponse m_token; public OpenStackHelper(string authid, string url) : base(url, MockOptions()) { m_helper = new OAuthHelper(authid, "hubic") { AutoAuthHeader = true }; } private static Dictionary MockOptions() { var res = new Dictionary(); res["openstack-authuri"] = "invalid://dont-use"; res["openstack-apikey"] = "invalid"; res["auth-username"] = "invalid"; return res; } private HubiCAuthResponse AuthToken { get { if (m_token == null || (m_token.expires != null && (m_token.expires.Value - DateTime.UtcNow).TotalSeconds < 30)) m_token = m_helper.ReadJSONResponse(HUBIC_API_CREDENTIAL_URL); return m_token; } } protected override string AccessToken { get { return AuthToken.token; } } protected override string SimpleStorageEndPoint { get { return AuthToken.endpoint; } } } public HubiCBackend() - { } - public HubiCBackend(string url, Dictionary options) { string authid = null; if (options.ContainsKey(AUTHID_OPTION)) authid = options[AUTHID_OPTION]; m_openstack = new OpenStackHelper(authid, url); } #region IStreamingBackend implementation public void Put(string remotename, System.IO.Stream stream) { m_openstack.Put(remotename, stream); } public void Get(string remotename, System.IO.Stream stream) { m_openstack.Get(remotename, stream); } #endregion #region IBackend implementation public IEnumerable List() { return m_openstack.List(); } public void Put(string remotename, string filename) { m_openstack.Put(remotename, filename); } public void Get(string remotename, string filename) { m_openstack.Get(remotename, filename); } public void Delete(string remotename) { m_openstack.Delete(remotename); } public void Test() { m_openstack.Test(); } public void CreateFolder() { m_openstack.CreateFolder(); } public string DisplayName { get { return Strings.HubiC.DisplayName; } } public string ProtocolKey { get { return "hubic"; } } public System.Collections.Generic.IList SupportedCommands { get { return new List(new ICommandLineArgument[] { new CommandLineArgument(AUTHID_OPTION, CommandLineArgument.ArgumentType.Password, Strings.HubiC.AuthidShort, Strings.HubiC.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("hubic"))), }); } } public string Description { get { return Strings.HubiC.Description; } } #endregion #region IDisposable implementation public void Dispose() { if (m_openstack != null) { m_openstack.Dispose(); m_openstack = null; } } #endregion } -} + { + private const string AUTHID_OPTION = "authid"; + private const string HUBIC_API_URL = "https://api.hubic.com/1.0/"; + private const string HUBIC_API_CREDENTIAL_URL = HUBIC_API_URL + "account/credentials"; + private OpenStackStorage m_openstack; + + private class HubiCAuthResponse + { + public string token { get; set; } + public string endpoint { get; set; } + public DateTime? expires { get; set;} + } + + private class OpenStackHelper : OpenStackStorage + { + private OAuthHelper m_helper; + private HubiCAuthResponse m_token; + + public OpenStackHelper(string authid, string url) + : base(url, MockOptions()) + { + m_helper = new OAuthHelper(authid, "hubic") { AutoAuthHeader = true }; + } + + private static Dictionary MockOptions() + { + var res = new Dictionary(); + res["openstack-authuri"] = "invalid://dont-use"; + res["openstack-apikey"] = "invalid"; + res["auth-username"] = "invalid"; + + return res; + } + + private HubiCAuthResponse AuthToken + { + get + { + if (m_token == null || (m_token.expires != null && (m_token.expires.Value - DateTime.UtcNow).TotalSeconds < 30)) + m_token = m_helper.ReadJSONResponse(HUBIC_API_CREDENTIAL_URL); + return m_token; + } + } + + protected override string AccessToken + { + get { return AuthToken.token; } + } + + protected override string SimpleStorageEndPoint + { + get { return AuthToken.endpoint; } + } + } + + public HubiCBackend() + { + } + + public HubiCBackend(string url, Dictionary options) + { + string authid = null; + if (options.ContainsKey(AUTHID_OPTION)) + authid = options[AUTHID_OPTION]; + + m_openstack = new OpenStackHelper(authid, url); + } + + #region IStreamingBackend implementation + + public void Put(string remotename, System.IO.Stream stream) + { + m_openstack.Put(remotename, stream); + } + + public void Get(string remotename, System.IO.Stream stream) + { + m_openstack.Get(remotename, stream); + } + + #endregion + + #region IBackend implementation + + public IEnumerable List() + { + return m_openstack.List(); + } + + public void Put(string remotename, string filename) + { + m_openstack.Put(remotename, filename); + } + + public void Get(string remotename, string filename) + { + m_openstack.Get(remotename, filename); + } + + public void Delete(string remotename) + { + m_openstack.Delete(remotename); + } + + public void Test() + { + m_openstack.Test(); + } + + public void CreateFolder() + { + m_openstack.CreateFolder(); + } + + public string DisplayName + { + get + { + return Strings.HubiC.DisplayName; + } + } + + public string ProtocolKey + { + get + { + return "hubic"; + } + } + + public System.Collections.Generic.IList SupportedCommands + { + get { + return new List(new ICommandLineArgument[] { + new CommandLineArgument(AUTHID_OPTION, CommandLineArgument.ArgumentType.Password, Strings.HubiC.AuthidShort, Strings.HubiC.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("hubic"))), + }); + } + } + + public string Description + { + get + { + return Strings.HubiC.Description; + } + } + + public string DNSName + { + get { return null; } + } + + #endregion + + #region IDisposable implementation + + public void Dispose() + { + if (m_openstack != null) + { + m_openstack.Dispose(); + m_openstack = null; + } + } + + #endregion + } +} diff --git a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs index 46f797351..4f44940be 100644 --- a/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs +++ b/Duplicati/Library/Backend/Jottacloud/Jottacloud.cs @@ -316,8 +316,13 @@ namespace Duplicati.Library.Backend public bool SupportsStreaming { get { return true; } - } - + } + + public string DNSName + { + get { return null; } + } + public void Get(string remotename, System.IO.Stream stream) { // Downloading from Jottacloud: Will only succeed if the file has a completed revision, diff --git a/Duplicati/Library/Backend/Mega/MegaBackend.cs b/Duplicati/Library/Backend/Mega/MegaBackend.cs index e9261717f..0e6719db9 100644 --- a/Duplicati/Library/Backend/Mega/MegaBackend.cs +++ b/Duplicati/Library/Backend/Mega/MegaBackend.cs @@ -260,6 +260,11 @@ namespace Duplicati.Library.Backend.Mega } } + public string DNSName + { + get { return null; } + } + #endregion #region IDisposable implementation diff --git a/Duplicati/Library/Backend/OneDrive/OneDrive.cs b/Duplicati/Library/Backend/OneDrive/OneDrive.cs index ff432b6b1..4f5a59a98 100644 --- a/Duplicati/Library/Backend/OneDrive/OneDrive.cs +++ b/Duplicati/Library/Backend/OneDrive/OneDrive.cs @@ -500,7 +500,12 @@ namespace Duplicati.Library.Backend } } - #endregion + public string DNSName + { + get { return null; } + } + + #endregion #region IStreamingBackend Members diff --git a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs index ed4f88cba..83c6758be 100644 --- a/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs +++ b/Duplicati/Library/Backend/OpenStack/OpenStackStorage.cs @@ -422,6 +422,12 @@ namespace Duplicati.Library.Backend.OpenStack return Strings.OpenStack.Description; } } + + public string DNSName + { + get { return null; } + } + #endregion #region IDisposable implementation public void Dispose() diff --git a/Duplicati/Library/Backend/Rclone/Rclone.cs b/Duplicati/Library/Backend/Rclone/Rclone.cs index 6d7596948..67771aeba 100644 --- a/Duplicati/Library/Backend/Rclone/Rclone.cs +++ b/Duplicati/Library/Backend/Rclone/Rclone.cs @@ -282,8 +282,13 @@ namespace Duplicati.Library.Backend { return Strings.Rclone.Description; } - } - + } + + public string DNSName + { + get { return null; } + } + public void Test() { this.TestList(); diff --git a/Duplicati/Library/Backend/S3/S3Backend.cs b/Duplicati/Library/Backend/S3/S3Backend.cs index 4d3e9ddf6..08d1eb8e9 100644 --- a/Duplicati/Library/Backend/S3/S3Backend.cs +++ b/Duplicati/Library/Backend/S3/S3Backend.cs @@ -474,6 +474,11 @@ namespace Duplicati.Library.Backend get { return m_wrapper; } } + public string DNSName + { + get { return null; } + } + private string GetFullKey(string name) { //AWS SDK encodes the filenames correctly diff --git a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs index c91b0d6a5..45a8ce8f4 100644 --- a/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs +++ b/Duplicati/Library/Backend/SSHv2/SSHv2Backend.cs @@ -368,5 +368,10 @@ namespace Duplicati.Library.Backend return m_con; } } + + public string DNSName + { + get { return null; } + } } } diff --git a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs index 1b86574ae..d011237cc 100644 --- a/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs +++ b/Duplicati/Library/Backend/SharePoint/SharePointBackend.cs @@ -113,12 +113,17 @@ namespace Duplicati.Library.Backend new CommandLineArgument("chunk-size", CommandLineArgument.ArgumentType.Size, Strings.SharePoint.DescriptionChunkSizeShort, Strings.SharePoint.DescriptionChunkSizeLong, "4mb"), }); } - } - + } + + public string DNSName + { + get { return null; } + } + #endregion - + #region [Constructors] - + public SharePointBackend() { } diff --git a/Duplicati/Library/Backend/Sia/Sia.cs b/Duplicati/Library/Backend/Sia/Sia.cs index 2839682d4..ae9c33fe7 100644 --- a/Duplicati/Library/Backend/Sia/Sia.cs +++ b/Duplicati/Library/Backend/Sia/Sia.cs @@ -438,12 +438,17 @@ namespace Duplicati.Library.Backend.Sia { return Strings.Sia.Description; } - } - + } + + public string DNSName + { + get { return null; } + } + #endregion - + #region IDisposable Members - + public void Dispose() { diff --git a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs index 274f56ffd..33ab2a91d 100644 --- a/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs +++ b/Duplicati/Library/Backend/TahoeLAFS/TahoeBackend.cs @@ -254,6 +254,11 @@ namespace Duplicati.Library.Backend get { return Strings.TahoeBackend.Description; } } + public string DNSName + { + get { return null; } + } + #endregion #region IDisposable Members diff --git a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs index 7e203394b..97a8127f6 100644 --- a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs +++ b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs @@ -33,6 +33,7 @@ namespace Duplicati.Library.Backend private string m_reverseProtocolUrl; private string m_rawurl; private string m_rawurlPort; + private string m_dnsName; private bool m_useIntegratedAuthentication = false; private bool m_forceDigestAuthentication = false; private bool m_useSSL = false; @@ -61,6 +62,7 @@ namespace Duplicati.Library.Backend { var u = new Utility.Uri(url); u.RequireHost(); + m_dnsName = u.Host; if (!string.IsNullOrEmpty(u.Username)) { @@ -311,6 +313,11 @@ namespace Duplicati.Library.Backend get { return Strings.WEBDAV.Description; } } + public string DNSName + { + get { return m_dnsName; } + } + public void Test() { this.List(); diff --git a/Duplicati/Library/Interface/IBackend.cs b/Duplicati/Library/Interface/IBackend.cs index 8281a9372..709006e54 100644 --- a/Duplicati/Library/Interface/IBackend.cs +++ b/Duplicati/Library/Interface/IBackend.cs @@ -81,6 +81,11 @@ namespace Duplicati.Library.Interface /// string Description { get; } + /// + /// The DNS name used to resolve the IP address for this backend + /// + string DNSName { get; } + /// /// The purpose of this method is to test the connection to the remote backend. /// If any problem is encountered, this method should throw an exception. diff --git a/Duplicati/Library/Main/BackendManager.cs b/Duplicati/Library/Main/BackendManager.cs index 15969fbcd..671769527 100644 --- a/Duplicati/Library/Main/BackendManager.cs +++ b/Duplicati/Library/Main/BackendManager.cs @@ -519,6 +519,22 @@ namespace Duplicati.Library.Main throw; } + if (ex is System.Net.WebException) + { + // Refresh DNS name if we fail to connect in order to prevent issues with incorrect DNS entries + if (((System.Net.WebException)ex).Status == System.Net.WebExceptionStatus.NameResolutionFailure) + { + try + { + if (!string.IsNullOrWhiteSpace(m_backend.DNSName)) + System.Net.Dns.GetHostEntry(m_backend.DNSName); + } + catch + { + } + } + } + m_statwriter.SendEvent(item.BackendActionType, retries < m_numberofretries ? BackendEventType.Retrying : BackendEventType.Failed, item.RemoteFilename, item.Size); bool recovered = false;