aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/checkcloudconnection.cpp107
-rw-r--r--core/checkcloudconnection.h1
-rw-r--r--core/git-access.c11
-rw-r--r--core/git-access.h1
4 files changed, 84 insertions, 36 deletions
diff --git a/core/checkcloudconnection.cpp b/core/checkcloudconnection.cpp
index 714b62836..05e529b90 100644
--- a/core/checkcloudconnection.cpp
+++ b/core/checkcloudconnection.cpp
@@ -35,48 +35,51 @@ bool CheckCloudConnection::checkServer()
if (verbose)
fprintf(stderr, "Checking cloud connection...\n");
- QTimer timer;
- timer.setSingleShot(true);
QEventLoop loop;
- QNetworkRequest request;
- request.setRawHeader("Accept", "text/plain");
- request.setRawHeader("User-Agent", getUserAgent().toUtf8());
- request.setRawHeader("Client-Id", getUUID().toUtf8());
- request.setUrl(QString(prefs.cloud_base_url) + TEAPOT);
QNetworkAccessManager *mgr = new QNetworkAccessManager();
- reply = mgr->get(request);
- connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
- connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
- connect(reply, &QNetworkReply::sslErrors, this, &CheckCloudConnection::sslErrors);
- for (int seconds = 1; seconds <= prefs.cloud_timeout; seconds++) {
- timer.start(1000); // wait the given number of seconds (default 5)
- loop.exec();
- if (timer.isActive()) {
- // didn't time out, did we get the right response?
- timer.stop();
- if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_I_AM_A_TEAPOT &&
- reply->readAll() == QByteArray(MILK)) {
- reply->deleteLater();
- mgr->deleteLater();
- if (verbose > 1)
- qWarning() << "Cloud storage: successfully checked connection to cloud server";
- return true;
+ do {
+ QNetworkRequest request;
+ request.setRawHeader("Accept", "text/plain");
+ request.setRawHeader("User-Agent", getUserAgent().toUtf8());
+ request.setRawHeader("Client-Id", getUUID().toUtf8());
+ request.setUrl(QString(prefs.cloud_base_url) + TEAPOT);
+ reply = mgr->get(request);
+ QTimer timer;
+ timer.setSingleShot(true);
+ connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
+ connect(reply, &QNetworkReply::sslErrors, this, &CheckCloudConnection::sslErrors);
+ for (int seconds = 1; seconds <= prefs.cloud_timeout; seconds++) {
+ timer.start(1000); // wait the given number of seconds (default 5)
+ loop.exec();
+ if (timer.isActive()) {
+ // didn't time out, did we get the right response?
+ timer.stop();
+ if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_I_AM_A_TEAPOT &&
+ reply->readAll() == QByteArray(MILK)) {
+ reply->deleteLater();
+ mgr->deleteLater();
+ if (verbose)
+ qWarning() << "Cloud storage: successfully checked connection to cloud server";
+ return true;
+ }
+ } else if (seconds < prefs.cloud_timeout) {
+ QString text = tr("Waiting for cloud connection (%n second(s) passed)", "", seconds);
+ git_storage_update_progress(qPrintable(text));
+ } else {
+ disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
+ reply->abort();
}
- } else if (seconds < prefs.cloud_timeout) {
- QString text = tr("Waiting for cloud connection (%n second(s) passed)", "", seconds);
- git_storage_update_progress(qPrintable(text));
- } else {
- disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
- reply->abort();
}
- }
+ if (verbose)
+ qDebug() << "connection test to cloud server" << prefs.cloud_base_url << "failed" <<
+ reply->error() << reply->errorString() <<
+ reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() <<
+ reply->readAll();
+ } while (nextServer());
+ // if none of the servers was reachable, update the user and switch to git_local_only
git_storage_update_progress(qPrintable(tr("Cloud connection failed")));
git_local_only = true;
- if (verbose)
- qDebug() << "connection test to cloud server failed" <<
- reply->error() << reply->errorString() <<
- reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() <<
- reply->readAll();
reply->deleteLater();
mgr->deleteLater();
if (verbose)
@@ -91,6 +94,38 @@ void CheckCloudConnection::sslErrors(const QList<QSslError> &errorList)
qDebug() << err.errorString();
}
+bool CheckCloudConnection::nextServer()
+{
+ struct serverTried {
+ const char *server;
+ bool tried;
+ };
+ static struct serverTried cloudServers[] = {
+ { CLOUD_HOST_EU, false },
+ { CLOUD_HOST_US, false }
+ };
+ const char *server = nullptr;
+ for (int i = 0; i < CLOUD_NUM_HOSTS; i++) {
+ if (strstr(prefs.cloud_base_url, cloudServers[i].server))
+ cloudServers[i].tried = true;
+ else if (cloudServers[i].tried == false)
+ server = cloudServers[i].server;
+ }
+ if (server) {
+ int s = strlen(server);
+ char *baseurl = (char *)malloc(10 + s);
+ strcpy(baseurl, "https://");
+ strncat(baseurl, server, s);
+ strcat(baseurl, "/");
+ qDebug() << "failed to connect to" << prefs.cloud_base_url << "next server to try: " << baseurl;
+ prefs.cloud_base_url = baseurl;
+ git_storage_update_progress(qPrintable(tr("Trying different cloud server...")));
+ return true;
+ }
+ qDebug() << "failed to connect to any of the Subsurface cloud servers, giving up";
+ return false;
+}
+
void CheckCloudConnection::pickServer()
{
QNetworkRequest request(QString(GET_EXTERNAL_IP_API));
diff --git a/core/checkcloudconnection.h b/core/checkcloudconnection.h
index 414ddc434..92e1b1a35 100644
--- a/core/checkcloudconnection.h
+++ b/core/checkcloudconnection.h
@@ -14,6 +14,7 @@ public:
void pickServer();
private:
QNetworkReply *reply;
+ bool nextServer();
private
slots:
void sslErrors(const QList<QSslError> &errorList);
diff --git a/core/git-access.c b/core/git-access.c
index 31ab9f1d8..c66a24a5d 100644
--- a/core/git-access.c
+++ b/core/git-access.c
@@ -716,6 +716,8 @@ int sync_with_remote(git_repository *repo, const char *remote, const char *branc
return 0;
}
+ // we know that we already checked for the cloud server, but to give a decent warning message
+ // here in case none of them are reachable, let's check one more time
if (is_subsurface_cloud && !canReachCloudServer()) {
// this is not an error, just a warning message, so return 0
SSRF_INFO("git storage: cannot connect to remote server");
@@ -723,6 +725,7 @@ int sync_with_remote(git_repository *repo, const char *remote, const char *branc
git_storage_update_progress(translate("gettextFromC", "Can't reach cloud server, working with local data"));
return 0;
}
+
if (verbose)
SSRF_INFO("git storage: fetch remote %s\n", git_remote_url(origin));
git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
@@ -1042,6 +1045,14 @@ static struct git_repository *is_remote_git_repository(char *remote, const char
* this is used to create more user friendly error message and warnings */
is_subsurface_cloud = strstr(remote, prefs.cloud_base_url) != NULL;
+ /* if we are planning to access the server, make sure it's available and try to
+ * pick one of the alternative servers if necessary */
+ if (is_subsurface_cloud && !git_local_only) {
+ // since we know that this is Subsurface cloud storage, we don't have to
+ // worry about the local directory name changing if we end up with a different
+ // cloud_base_url... the algorithm normalizes those URLs
+ (void)canReachCloudServer();
+ }
return get_remote_repo(localdir, remote, branch);
}
diff --git a/core/git-access.h b/core/git-access.h
index 210ebb2fd..0ac5294c6 100644
--- a/core/git-access.h
+++ b/core/git-access.h
@@ -15,6 +15,7 @@ extern "C" {
#include <stdbool.h>
#endif
+#define CLOUD_NUM_HOSTS 2
#define CLOUD_HOST_US "ssrf-cloud-us.subsurface-divelog.org"
#define CLOUD_HOST_EU "ssrf-cloud-eu.subsurface-divelog.org"
#define CLOUD_HOST_PATTERN "ssrf-cloud-..\\.subsurface-divelog\\.org"