// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of libnymea-app. * * libnymea-app is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * libnymea-app is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libnymea-app. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "networkreachabilitymonitor.h" #include #include Q_DECLARE_LOGGING_CATEGORY(dcNymeaConnection) NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent) : QObject{parent} { // NOTE: The Qt API is not working at all on iOS, we're using the iOS reachability API instead. // See iOS implementation in .mm file #if defined(Q_OS_IOS) setupIOS(); #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_networkInformation = QNetworkInformation::instance(); qCDebug(dcNymeaConnection()) << "Network infromation supported features:" << m_networkInformation->supportedFeatures(); qCDebug(dcNymeaConnection()) << "Network reachability:" << m_networkInformation->reachability(); qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << m_networkInformation->transportMedium(); QObject::connect(m_networkInformation, &QNetworkInformation::reachabilityChanged, this, [this](QNetworkInformation::Reachability reachability){ qCDebug(dcNymeaConnection()) << "Network reachability changed:" << reachability; updateActiveBearers(); }); QObject::connect(m_networkInformation, &QNetworkInformation::transportMediumChanged, this, [this](QNetworkInformation::TransportMedium type){ qCDebug(dcNymeaConnection()) << "Network trasport medium changed:" << type; updateActiveBearers(); }); #else m_networkConfigManager = new QNetworkConfigurationManager(this); QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){ Q_UNUSED(config) qCDebug(dcNymeaConnection()) << "Network configuration added:" << config.name() << config.bearerTypeName() << config.purpose(); updateActiveBearers(); }); QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationRemoved, this, [this](const QNetworkConfiguration &config){ Q_UNUSED(config) qCDebug(dcNymeaConnection()) << "Network configuration removed:" << config.name() << config.bearerTypeName() << config.purpose(); updateActiveBearers(); }); #endif QGuiApplication *app = static_cast(QGuiApplication::instance()); QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) { qCDebug(dcNymeaConnection()) << "Application state changed to:" << state; updateActiveBearers(); }); updateActiveBearers(); } NetworkReachabilityMonitor::~NetworkReachabilityMonitor() { #ifdef Q_OS_IOS teardownIOS(); #endif } NymeaConnection::BearerTypes NetworkReachabilityMonitor::availableBearerTypes() const { return m_availableBearerTypes; } void NetworkReachabilityMonitor::updateActiveBearers() { #if defined(Q_OS_IOS) return; #endif NymeaConnection::BearerTypes availableBearerTypes; // Note: some features are availabe since Qt 6.3.0, but the minimal Qt6 version is 6.6.0, // so we don't want so have an unhanlded gap and let the compiler warn about incompatibility #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (m_networkInformation->reachability() == QNetworkInformation::Reachability::Disconnected) { qCDebug(dcNymeaConnection()) << "No reachable network transport medium available."; } else { availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(m_networkInformation->transportMedium())); } #else QList configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active); qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count(); foreach (const QNetworkConfiguration &config, configs) { qCDebug(dcNymeaConnection()) << "Active network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName(); availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(config.bearerType())); } if (availableBearerTypes == NymeaConnection::BearerTypeNone) { // This is just debug info... On some platform bearer management seems a bit broken, so let's get some infos right away... qCDebug(dcNymeaConnection()) << "No active bearer available. Inactive bearers are:"; QList configs = m_networkConfigManager->allConfigurations(); foreach (const QNetworkConfiguration &config, configs) { qCDebug(dcNymeaConnection()) << "Inactive network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName(); } qCDebug(dcNymeaConnection()) << "Updating network manager"; m_networkConfigManager->updateConfigurations(); } #endif if (m_availableBearerTypes != availableBearerTypes) { qCInfo(dcNymeaConnection()) << "Available Bearer Types changed to:" << availableBearerTypes; m_availableBearerTypes = availableBearerTypes; emit availableBearerTypesChanged(); } else { qCDebug(dcNymeaConnection()) << "Available Bearer Types:" << availableBearerTypes; } emit availableBearerTypesUpdated(); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkInformation::TransportMedium type) { switch (type) { case QNetworkInformation::TransportMedium::Unknown: // Unable to determine the connection type. Assume it's something we can establish any connection type on return NymeaConnection::BearerTypeAll; case QNetworkInformation::TransportMedium::Ethernet: return NymeaConnection::BearerTypeEthernet; case QNetworkInformation::TransportMedium::Cellular: return NymeaConnection::BearerTypeMobileData; case QNetworkInformation::TransportMedium::WiFi: return NymeaConnection::BearerTypeWiFi; case QNetworkInformation::TransportMedium::Bluetooth: // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it. return NymeaConnection::BearerTypeBluetooth; } return NymeaConnection::BearerTypeAll; } #else NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type) { switch (type) { case QNetworkConfiguration::BearerUnknown: // Unable to determine the connection type. Assume it's something we can establish any connection type on return NymeaConnection::BearerTypeAll; case QNetworkConfiguration::BearerEthernet: return NymeaConnection::BearerTypeEthernet; case QNetworkConfiguration::BearerWLAN: return NymeaConnection::BearerTypeWiFi; case QNetworkConfiguration::Bearer2G: case QNetworkConfiguration::BearerCDMA2000: case QNetworkConfiguration::BearerWCDMA: case QNetworkConfiguration::BearerHSPA: case QNetworkConfiguration::BearerWiMAX: case QNetworkConfiguration::BearerEVDO: case QNetworkConfiguration::BearerLTE: case QNetworkConfiguration::Bearer3G: case QNetworkConfiguration::Bearer4G: return NymeaConnection::BearerTypeMobileData; case QNetworkConfiguration::BearerBluetooth: // Note: Do not confuse this with the Bluetooth transport... For Qt, this means IP over BT, not RFCOMM as we do it. return NymeaConnection::BearerTypeNone; } return NymeaConnection::BearerTypeAll; } #endif