diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/checkcloudconnection.cpp | 107 | ||||
-rw-r--r-- | core/checkcloudconnection.h | 1 | ||||
-rw-r--r-- | core/git-access.c | 11 | ||||
-rw-r--r-- | core/git-access.h | 1 |
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" |