From c0ca56ee933b680258252c80f4f22fe3d9eb07e3 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 5 Aug 2018 00:30:15 +0200 Subject: [PATCH] Ref T295, fix for the "no network config" issue * details: https://stackoverflow.com/questions/51686943/no-qnetworkconfiguration-although-i-can-connect-to-wifi * network accessibility check can be disabled if network config looks suspicious * using QNetworkConfigurationManager --- src/blackcore/application.cpp | 111 ++++++++++++++++++++++----- src/blackcore/application.h | 10 ++- src/blackcore/db/networkwatchdog.cpp | 40 +++++++--- src/blackcore/db/networkwatchdog.h | 23 +++++- 4 files changed, 151 insertions(+), 33 deletions(-) diff --git a/src/blackcore/application.cpp b/src/blackcore/application.cpp index f9e4fbe73..a8fde5974 100644 --- a/src/blackcore/application.cpp +++ b/src/blackcore/application.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,7 @@ namespace BlackCore CApplication::CApplication(const QString &applicationName, CApplicationInfo::Application application, bool init) : CIdentifiable(this), + m_networkConfigManager(new QNetworkConfigurationManager(this)), m_accessManager(new QNetworkAccessManager(this)), m_applicationInfo(application), m_applicationName(applicationName), m_coreFacadeConfig(CCoreFacadeConfig::allEmpty()) @@ -154,26 +156,11 @@ namespace BlackCore if (translator.load("blackmisc_i18n_de", ":blackmisc/translations/")) { CLogMessage(this).debug() << "Translator loaded"; } QCoreApplication::instance()->installTranslator(&translator); - // Init network + // main app sApp = this; - Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "Need QAM"); - CNetworkWatchdog *nwWatchdog = new CNetworkWatchdog(this->isNetworkAccessible(), this); - m_networkWatchDog.reset(nwWatchdog); // not yet started - m_cookieManager = new CCookieManager({}, this); - m_cookieManager->setParent(m_accessManager); - m_accessManager->setCookieJar(m_cookieManager); - // in to watchdog - connect(m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, m_networkWatchDog.data(), &CNetworkWatchdog::setNetworkAccessibility); + this->initNetwork(); - // out from watchdog to application - connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedNetworkAccessible, this, &CApplication::onChangedNetworkAccessibility, Qt::QueuedConnection); - connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedInternetAccessibility, this, &CApplication::onChangedInternetAccessibility, Qt::QueuedConnection); - connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedSwiftDbAccessibility, this, &CApplication::onChangedSwiftDbAccessibility, Qt::QueuedConnection); - - CLogMessage::preformatted(CNetworkUtils::createNetworkReport(m_accessManager)); - m_networkWatchDog->start(QThread::LowestPriority); - m_networkWatchDog->startUpdating(10); // global setup m_setupReader.reset(new CSetupReader(this)); @@ -739,7 +726,10 @@ namespace BlackCore bool CApplication::isNetworkAccessible() const { - if (!m_accessManager) { return false; } + // skip test if there is no proper network config + if (m_networkWatchDog && m_networkWatchDog->isNetworkAccessibilityCheckDisabled()) { return true; } + + Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "no access manager"); const QNetworkAccessManager::NetworkAccessibility a = m_accessManager->networkAccessible(); if (a == QNetworkAccessManager::Accessible) { return true; } @@ -749,19 +739,16 @@ namespace BlackCore bool CApplication::isInternetAccessible() const { - if (!this->isNetworkAccessible()) { return false; } return m_networkWatchDog && m_networkWatchDog->isInternetAccessible(); } bool CApplication::isSwiftDbAccessible() const { - if (!this->isNetworkAccessible()) { return false; } return m_networkWatchDog && m_networkWatchDog->isSwiftDbAccessible(); } bool CApplication::hasWorkingSharedUrl() const { - if (!this->isNetworkAccessible()) { return false; } return m_networkWatchDog && m_networkWatchDog->hasWorkingSharedUrl(); } @@ -1104,6 +1091,88 @@ namespace BlackCore emit this->changedSwiftDbAccessibility(accessible, url); } + void CApplication::onNetworkConfigurationsUpdateCompleted() + { + const QNetworkConfiguration config = m_networkConfigManager->defaultConfiguration(); + const QList allConfigurations = m_networkConfigManager->allConfigurations(); + + /** testing only + for (const QNetworkConfiguration &config : allConfigurations) + { + const QString cs = CNetworkUtils::networkConfigurationToString(config); + CLogMessage(this).info("Network config: '%1'") << cs; + } + if (m_accessManager) + { + const QString cs = CNetworkUtils::networkConfigurationToString(m_accessManager->configuration()); + CLogMessage(this).info("Network access manager config: '%1'") << cs; + } + **/ + + if (allConfigurations.isEmpty()) + { + // this is an odd situation we cannot handle, network check will be disabled + if (!m_networkWatchDog->isNetworkAccessibilityCheckDisabled()) + { + m_networkWatchDog->disableNetworkAccessibilityCheck(true); + m_accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible); + CLogMessage(this).warning("No network configurations found, disabling network accessibility checks"); + } + } + else + { + const bool isOnline = m_networkConfigManager->isOnline(); + const bool canStartIAP = (m_networkConfigManager->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces); + m_networkWatchDog->disableNetworkAccessibilityCheck(!isOnline); + + // Is there default access point, use it + if (!config.isValid() || (!canStartIAP && config.state() != QNetworkConfiguration::Active)) + { + CLogMessage(this).error("No network access point found"); + } + } + } + + void CApplication::initNetwork() + { + if (!m_accessManager) { m_accessManager = new QNetworkAccessManager(this); } + if (!m_networkConfigManager) { m_networkConfigManager = new QNetworkConfigurationManager(this); } + + if (!m_networkWatchDog) + { + // CNetworkWatchdog *nwWatchdog = new CNetworkWatchdog(this->isNetworkAccessible(), this); + CNetworkWatchdog *nwWatchdog = new CNetworkWatchdog(true, this); // WLAN bug, default to true + m_networkWatchDog.reset(nwWatchdog); // not yet started + m_cookieManager = new CCookieManager({}, this); + m_cookieManager->setParent(m_accessManager); + m_accessManager->setCookieJar(m_cookieManager); + } + + // Init network + Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "Need QAM"); + Q_ASSERT_X(m_networkConfigManager, Q_FUNC_INFO, "Need config manager"); + + // into watchdog + connect(m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, m_networkWatchDog.data(), &CNetworkWatchdog::setNetworkAccessibility, Qt::QueuedConnection); + connect(m_networkConfigManager, &QNetworkConfigurationManager::onlineStateChanged, m_networkWatchDog.data(), &CNetworkWatchdog::setOnline, Qt::QueuedConnection); + connect(m_networkConfigManager, &QNetworkConfigurationManager::updateCompleted, m_networkWatchDog.data(), &CNetworkWatchdog::networkConfigurationsUpdateCompleted, Qt::QueuedConnection); + connect(m_networkConfigManager, &QNetworkConfigurationManager::updateCompleted, this, &CApplication::onNetworkConfigurationsUpdateCompleted, Qt::QueuedConnection); + m_networkConfigManager->updateConfigurations(); + + // out from watchdog to application + connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedNetworkAccessible, this, &CApplication::onChangedNetworkAccessibility, Qt::QueuedConnection); + connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedInternetAccessibility, this, &CApplication::onChangedInternetAccessibility, Qt::QueuedConnection); + connect(m_networkWatchDog.data(), &CNetworkWatchdog::changedSwiftDbAccessibility, this, &CApplication::onChangedSwiftDbAccessibility, Qt::QueuedConnection); + + CLogMessage::preformatted(CNetworkUtils::createNetworkReport(m_accessManager)); + m_networkWatchDog->start(QThread::LowestPriority); + m_networkWatchDog->startUpdating(10); + + // enable by setting accessible + // http://doc.qt.io/qt-5/qnetworkaccessmanager.html#setNetworkAccessible + m_accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible); + } + CStatusMessageList CApplication::asyncWebAndContextStart() { if (m_started) { return CStatusMessage(this).info("Already started "); } diff --git a/src/blackcore/application.h b/src/blackcore/application.h index 5bf92b769..3548e5513 100644 --- a/src/blackcore/application.h +++ b/src/blackcore/application.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -542,7 +543,7 @@ namespace BlackCore //! Severe issue during startup, most likely it does not make sense to continue //! \note call this here if the parsing stage is over and reaction to a runtime issue is needed - void severeStartupProblem(const BlackMisc::CStatusMessage &message); + [[ noreturn ]] void severeStartupProblem(const BlackMisc::CStatusMessage &message); //! Start the core facade //! \note does nothing when setup is not yet loaded @@ -585,6 +586,12 @@ namespace BlackCore //! Changed swift DB accessibility void onChangedSwiftDbAccessibility(bool accessible, const BlackMisc::Network::CUrl &url); + //! Network configurations update completed + void onNetworkConfigurationsUpdateCompleted(); + + //! Init network + void initNetwork(); + //! init logging system void initLogging(); @@ -620,6 +627,7 @@ namespace BlackCore //! Write meta information into the application directory so other swift versions can display them void tagApplicationDataDirectory(); + QNetworkConfigurationManager *m_networkConfigManager = nullptr; //!< configuration QNetworkAccessManager *m_accessManager = nullptr; //!< single network access manager BlackMisc::CApplicationInfo m_applicationInfo; //!< Application if specified QScopedPointer m_coreFacade; //!< core facade if any diff --git a/src/blackcore/db/networkwatchdog.cpp b/src/blackcore/db/networkwatchdog.cpp index 96207d0b9..1613a2e35 100644 --- a/src/blackcore/db/networkwatchdog.cpp +++ b/src/blackcore/db/networkwatchdog.cpp @@ -34,16 +34,12 @@ namespace BlackCore CNetworkWatchdog::CNetworkWatchdog(bool networkAccessible, QObject *parent) : CContinuousWorker(parent, "swift DB watchdog") { - Q_ASSERT_X(sApp, Q_FUNC_INFO, "Need sApp"); + Q_ASSERT_X(parent, Q_FUNC_INFO, "Need parent (normally sApp)"); + m_networkAccessible = networkAccessible; m_internetAccessible = networkAccessible; m_dbAccessible = networkAccessible && m_checkDbAccessibility; - if (networkAccessible) - { - this->initWorkingSharedUrlFromSetup(); - } - m_updateTimer.setInterval(10 * 1000); connect(&m_updateTimer, &QTimer::timeout, this, &CNetworkWatchdog::doWork); } @@ -51,7 +47,7 @@ namespace BlackCore void CNetworkWatchdog::setDbAccessibility(bool accessible) { m_dbAccessible = accessible; - m_internetAccessible = m_internetAccessible && m_networkAccessible; + m_internetAccessible = m_internetAccessible && this->isNetworkkAccessibleOrCheckDisabled(); // restart timer QPointer myself(this); @@ -64,13 +60,13 @@ namespace BlackCore bool CNetworkWatchdog::hasWorkingSharedUrl() const { - if (!m_networkAccessible) { return false; } + if (!this->isNetworkkAccessibleOrCheckDisabled()) { return false; } return !this->getWorkingSharedUrl().isEmpty(); } CUrl CNetworkWatchdog::getWorkingSharedUrl() const { - if (!m_networkAccessible) { return CUrl(); } + if (!this->isNetworkkAccessibleOrCheckDisabled()) { return CUrl(); } QReadLocker l(&m_lockUrl); return m_workingSharedUrl; } @@ -125,11 +121,18 @@ namespace BlackCore if (m_checkInProgress) { return; } m_checkInProgress = true; + // lazy init + if (!this->hasWorkingSharedUrl()) + { + this->initWorkingSharedUrlFromSetup(); + } + + // checks do { const bool wasDbAvailable = m_dbAccessible; const bool wasInternetAvailable = m_internetAccessible; - const bool networkAccessible = m_networkAccessible; + const bool networkAccessible = this->isNetworkkAccessibleOrCheckDisabled(); const CUrl testUrl(CNetworkWatchdog::dbTestUrl()); bool canConnectDb = m_checkDbAccessibility && networkAccessible && CNetworkUtils::canConnect(testUrl, CanConnectTimeMs); // running here in background worker @@ -260,6 +263,16 @@ namespace BlackCore emit this->changedNetworkAccessible(accessibility); } + void CNetworkWatchdog::networkConfigurationsUpdateCompleted() + { + // void + } + + void CNetworkWatchdog::setOnline(bool online) + { + m_online = online; + } + void CNetworkWatchdog::gracefulShutdown() { this->pingDbClientService(CGlobalSetup::PingCompleteShutdown); @@ -276,6 +289,13 @@ namespace BlackCore sApp->getFromNetwork(pingUrl, { this, &CNetworkWatchdog::replyPingClientService }); } + bool CNetworkWatchdog::disableNetworkAccessibilityCheck(bool disable) + { + if (disable == m_disableNetworkCheck) { return false; } + m_disableNetworkCheck = disable; + return true; + } + void CNetworkWatchdog::replyPingClientService(QNetworkReply *nwReply) { // init and clean up diff --git a/src/blackcore/db/networkwatchdog.h b/src/blackcore/db/networkwatchdog.h index d6370ba4a..65d79950e 100644 --- a/src/blackcore/db/networkwatchdog.h +++ b/src/blackcore/db/networkwatchdog.h @@ -42,6 +42,13 @@ namespace BlackCore //! \threadsafe void setNetworkAccessibility(QNetworkAccessManager::NetworkAccessibility accessibility); + //! Configuration updates completed as reported by QNetworkConfigurationManager::updateCompleted + void networkConfigurationsUpdateCompleted(); + + //! Set online as reported by QNetworkConfigurationManager::onlineStateChanged + //! \threadsafe + void setOnline(bool online); + //! DB available? //! \threadsafe bool isSwiftDbAccessible() const { return m_dbAccessible; } @@ -75,6 +82,9 @@ namespace BlackCore //! \threadsafe bool isInternetAccessible() const { return m_internetAccessible; } + //! Accesible or check disabled? + bool isNetworkkAccessibleOrCheckDisabled() const { return m_networkAccessible || m_disableNetworkCheck; } + //! Has working shared URL? //! \threadsafe bool hasWorkingSharedUrl() const; @@ -111,6 +121,15 @@ namespace BlackCore //! Ping the DB server, fire and forget (no feedback etc) void pingDbClientService(Data::CGlobalSetup::PingType type = Data::CGlobalSetup::PingUnspecific, bool force = false); + //! Disable the network check + //! \remark if disabled network reports always accessible + //! \threadsafe + bool disableNetworkAccessibilityCheck(bool disable); + + //! Has network check been disabled? + //! \threadsafe + bool isNetworkAccessibilityCheckDisabled() const { return m_disableNetworkCheck; } + //! URL referring to the DB //! \remark depends on BlackCore::Application::getGlobalSetup() static bool isDbUrl(const BlackMisc::Network::CUrl &url); @@ -160,6 +179,8 @@ namespace BlackCore std::atomic_bool m_logOwnMessages { true }; std::atomic_bool m_doDetailedCheck { true }; std::atomic_bool m_networkAccessible { true }; + std::atomic_bool m_disableNetworkCheck { false }; //!< if this is true, network accessible always reports true/accessible + std::atomic_bool m_online { true }; std::atomic_bool m_internetAccessible { true }; std::atomic_bool m_dbAccessible { true }; std::atomic_bool m_lastClientPingSuccess { true }; @@ -171,7 +192,7 @@ namespace BlackCore std::atomic_int m_totalBadCountDb { 0 }; //!< Total number of DB failing counts (only real responses when tried) std::atomic_int m_totalBadCountInternet { 0 }; //!< Total number of Internet failing count (only when network is accessible) std::atomic_int m_totalGoodCountDb { 0 }; - std::atomic_int m_totalGoodCountInternet { 0 }; + std::atomic_int m_totalGoodCountInternet { 0 }; std::atomic_int m_consecutivePingBadCount { 0 }; //!< Bad count of ping until a godd state is received QString m_lastPingUrl; BlackMisc::Network::CUrl m_workingSharedUrl;