From 1299aaa231b1ce989c8aedcfed372bde0e1e3a0e Mon Sep 17 00:00:00 2001 From: Evgen Pervenenko Date: Sat, 23 Nov 2024 11:02:34 +0300 Subject: [PATCH] QNCM[Mac]: Update from SCNetworkReachability to Network framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since SCNetworkReachability is deprecated, the implementation is now updated to use the Network framework. [ChangeLog][QNetworkInformation] Replace deprecated SCNetworkReachability implementation with Network framework (iOS, macOS) Fixes: QTBUG-132103 Change-Id: Iff4a667fd07002451b7d49cc8fd069945d426aab Reviewed-by: Juha Vuolle Reviewed-by: Mårten Nordheim Reviewed-by: Vladimir Belyavsky Reviewed-by: Tor Arne Vestbø Reviewed-by: Øystein Heskestad --- cmake/QtFrameworkHelpers.cmake | 1 + src/network/CMakeLists.txt | 2 +- src/network/kernel/qnetconmonitor_darwin.mm | 321 ++++++------------ src/network/kernel/qnetconmonitor_p.h | 20 +- src/network/kernel/qnetworkinformation.cpp | 2 +- src/network/kernel/qnetworkinformation_p.h | 4 +- src/plugins/networkinformation/CMakeLists.txt | 2 +- .../networkinformation/apple/CMakeLists.txt | 14 + .../apple/qapplenetworkinformationbackend.mm | 123 +++++++ .../scnetworkreachability/CMakeLists.txt | 14 - ...rkreachabilitynetworkinformationbackend.mm | 158 --------- 11 files changed, 266 insertions(+), 395 deletions(-) create mode 100644 src/plugins/networkinformation/apple/CMakeLists.txt create mode 100644 src/plugins/networkinformation/apple/qapplenetworkinformationbackend.mm delete mode 100644 src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt delete mode 100644 src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake index 0f776ec0dbb..95954d5e0db 100644 --- a/cmake/QtFrameworkHelpers.cmake +++ b/cmake/QtFrameworkHelpers.cmake @@ -38,6 +38,7 @@ macro(qt_find_apple_system_frameworks) qt_internal_find_apple_system_framework(FWEventKit EventKit) qt_internal_find_apple_system_framework(FWHealthKit HealthKit) qt_internal_find_apple_system_framework(FWUniformTypeIdentifiers UniformTypeIdentifiers) + qt_internal_find_apple_system_framework(FWNetwork Network) endif() endmacro() diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 80892eda265..cf2c8cf98d6 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -255,7 +255,7 @@ qt_internal_extend_target(Network CONDITION APPLE SOURCES kernel/qnetconmonitor_darwin.mm LIBRARIES - ${FWSystemConfiguration} + ${FWNetwork} ) qt_internal_extend_target(Network CONDITION QT_FEATURE_networklistmanager AND NOT IOS AND NOT MACOS diff --git a/src/network/kernel/qnetconmonitor_darwin.mm b/src/network/kernel/qnetconmonitor_darwin.mm index 0bb4329cac7..28a61d9016d 100644 --- a/src/network/kernel/qnetconmonitor_darwin.mm +++ b/src/network/kernel/qnetconmonitor_darwin.mm @@ -1,20 +1,13 @@ // Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include "private/qnativesocketengine_p_p.h" #include "private/qnetconmonitor_p.h" #include "private/qobject_p.h" -#include -#include +#include -#include - -#include -#include - -#include +#include QT_BEGIN_NAMESPACE @@ -55,147 +48,140 @@ dispatch_queue_t qt_reachability_queue() return reachabilityQueue.data(); } -qt_sockaddr qt_hostaddress_to_sockaddr(const QHostAddress &src) -{ - if (src.isNull()) - return {}; - - qt_sockaddr dst; - if (src.protocol() == QAbstractSocket::IPv4Protocol) { - dst.a4 = sockaddr_in{}; - dst.a4.sin_family = AF_INET; - dst.a4.sin_addr.s_addr = htonl(src.toIPv4Address()); - dst.a4.sin_len = sizeof(sockaddr_in); - } else if (src.protocol() == QAbstractSocket::IPv6Protocol) { - dst.a6 = sockaddr_in6{}; - dst.a6.sin6_family = AF_INET6; - dst.a6.sin6_len = sizeof(sockaddr_in6); - const Q_IPV6ADDR ipv6 = src.toIPv6Address(); - std::memcpy(&dst.a6.sin6_addr, &ipv6, sizeof ipv6); - } else { - Q_UNREACHABLE(); - } - - return dst; -} - } // unnamed namespace class QNetworkConnectionMonitorPrivate : public QObjectPrivate { public: - SCNetworkReachabilityRef probe = nullptr; - SCNetworkReachabilityFlags state = kSCNetworkReachabilityFlagsIsLocalAddress; - bool scheduled = false; + nw_path_status_t status = nw_path_status_invalid; + mutable QReadWriteLock monitorLock; + nw_path_monitor_t monitor = nullptr; + using InterfaceType = QNetworkConnectionMonitor::InterfaceType; + InterfaceType interface = InterfaceType::Unknown; - QWaitCondition refCounterWaitCondition; - QMutex refCounterMutex; - quint32 refCounter = 0; - - void updateState(SCNetworkReachabilityFlags newState); + void updateState(nw_path_t newState); void reset(); bool isReachable() const; -#ifdef QT_PLATFORM_UIKIT - bool isWwan() const; -#endif + QNetworkConnectionMonitor::InterfaceType getInterfaceType() const; - void retain() - { - QMutexLocker locker(&refCounterMutex); - ++refCounter; - } - - void release() - { - QMutexLocker locker(&refCounterMutex); - if (--refCounter == 0) - refCounterWaitCondition.wakeAll(); - } - - void waitForRefCountZero() - { - QMutexLocker locker(&refCounterMutex); - while (refCounter > 0) { - refCounterWaitCondition.wait(&refCounterMutex); - } - } - - static void probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info); - static const void *retainInfo(const void* info); - static void releaseInfo(const void* info); + bool startMonitoring(); + void stopMonitoring(); + bool isMonitoring() const; Q_DECLARE_PUBLIC(QNetworkConnectionMonitor) }; -void QNetworkConnectionMonitorPrivate::updateState(SCNetworkReachabilityFlags newState) +void QNetworkConnectionMonitorPrivate::updateState(nw_path_t state) { + QReadLocker lock(&monitorLock); + if (monitor == nullptr) + return; + // To be executed only on the reachability queue. Q_Q(QNetworkConnectionMonitor); - // NETMONTODO: for now, 'online' for us means kSCNetworkReachabilityFlagsReachable + // NETMONTODO: for now, 'online' for us means nw_path_status_satisfied // is set. There are more possible flags that require more tests/some special // setup. So in future this part and related can change/be extended. const bool wasReachable = isReachable(); + const QNetworkConnectionMonitor::InterfaceType hadInterfaceType = interface; + const nw_path_status_t previousStatus = status; -#ifdef QT_PLATFORM_UIKIT - const bool hadWwan = isWwan(); -#endif - - state = newState; - if (wasReachable != isReachable()) + status = nw_path_get_status(state); + if (wasReachable != isReachable() || previousStatus == nw_path_status_invalid) emit q->reachabilityChanged(isReachable()); -#ifdef QT_PLATFORM_UIKIT - if (hadWwan != isWwan()) - emit q->isWwanChanged(isWwan()); -#endif + nw_path_enumerate_interfaces(state, ^(nw_interface_t nwInterface) { + if (nw_path_uses_interface_type(state, nw_interface_get_type(nwInterface))) { + const nw_interface_type_t type = nw_interface_get_type(nwInterface); + + switch (type) { + case nw_interface_type_wifi: + interface = QNetworkConnectionMonitor::InterfaceType::WiFi; + break; + case nw_interface_type_cellular: + interface = QNetworkConnectionMonitor::InterfaceType::Cellular; + break; + case nw_interface_type_wired: + interface = QNetworkConnectionMonitor::InterfaceType::Ethernet; + break; + default: + interface = QNetworkConnectionMonitor::InterfaceType::Unknown; + break; + } + + return false; + } + + return true; + }); + + if (hadInterfaceType != interface) + emit q->interfaceTypeChanged(interface); } void QNetworkConnectionMonitorPrivate::reset() { - if (probe) { - CFRelease(probe); - probe = nullptr; - } - - state = kSCNetworkReachabilityFlagsIsLocalAddress; - scheduled = false; - waitForRefCountZero(); + stopMonitoring(); + status = nw_path_status_invalid; } bool QNetworkConnectionMonitorPrivate::isReachable() const { - return !!(state & kSCNetworkReachabilityFlagsReachable); + return status == nw_path_status_satisfied; } -#ifdef QT_PLATFORM_UIKIT // The IsWWAN flag is not available on macOS -bool QNetworkConnectionMonitorPrivate::isWwan() const +QNetworkConnectionMonitor::InterfaceType QNetworkConnectionMonitorPrivate::getInterfaceType() const { - return !!(state & kSCNetworkReachabilityFlagsIsWWAN); + return interface; } -#endif -void QNetworkConnectionMonitorPrivate::probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info) +bool QNetworkConnectionMonitorPrivate::startMonitoring() { - // To be executed only on the reachability queue. - Q_UNUSED(probe); + QWriteLocker lock(&monitorLock); + monitor = nw_path_monitor_create(); + if (monitor == nullptr) { + qCWarning(lcNetMon, "Failed to create a path monitor, cannot determine current reachability."); + return false; + } + + nw_path_monitor_set_update_handler(monitor, [this](nw_path_t path){ + updateState(path); + }); + + auto queue = qt_reachability_queue(); + if (!queue) { + qCWarning(lcNetMon, "Failed to create a dispatch queue to schedule a probe on"); + nw_release(monitor); + monitor = nullptr; + return false; + } - auto monitorPrivate = static_cast(info); - Q_ASSERT(monitorPrivate); - monitorPrivate->updateState(flags); + nw_path_monitor_set_queue(monitor, queue); + nw_path_monitor_start(monitor); + return true; } -const void *QNetworkConnectionMonitorPrivate::retainInfo(const void *info) +void QNetworkConnectionMonitorPrivate::stopMonitoring() { - auto monitorPrivate = static_cast(const_cast(info)); - monitorPrivate->retain(); - return info; + QWriteLocker lock(&monitorLock); + if (monitor != nullptr) { + nw_path_monitor_cancel(monitor); + nw_release(monitor); + monitor = nullptr; + } } -void QNetworkConnectionMonitorPrivate::releaseInfo(const void *info) +void QNetworkConnectionMonitor::stopMonitoring() { - auto monitorPrivate = static_cast(const_cast(info)); - monitorPrivate->release(); + Q_D(QNetworkConnectionMonitor); + d->stopMonitoring(); +} + +bool QNetworkConnectionMonitorPrivate::isMonitoring() const +{ + QReadLocker lock(&monitorLock); + return monitor != nullptr; } QNetworkConnectionMonitor::QNetworkConnectionMonitor() @@ -203,115 +189,32 @@ void waitForRefCountZero() { } -QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote) - : QObject(*new QNetworkConnectionMonitorPrivate) +QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &/*local*/, const QHostAddress &/*remote*/) + : QNetworkConnectionMonitor() { - setTargets(local, remote); } QNetworkConnectionMonitor::~QNetworkConnectionMonitor() { Q_D(QNetworkConnectionMonitor); - - stopMonitoring(); d->reset(); } -bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote) +bool QNetworkConnectionMonitor::setTargets(const QHostAddress &/*local*/, const QHostAddress &/*remote*/) { - Q_D(QNetworkConnectionMonitor); - - if (isMonitoring()) { - qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first"); - return false; - } - - if (local.isNull()) { - qCWarning(lcNetMon, "Invalid (null) local address, cannot create a reachability target"); - return false; - } - - // Clear the old target if needed: - d->reset(); - - qt_sockaddr client = qt_hostaddress_to_sockaddr(local); - if (remote.isNull()) { - // That's a special case our QNetworkInformation backend is using (AnyIpv4/6 address to check an overall status). - d->probe = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, reinterpret_cast(&client)); - } else { - qt_sockaddr target = qt_hostaddress_to_sockaddr(remote); - d->probe = SCNetworkReachabilityCreateWithAddressPair(kCFAllocatorDefault, - reinterpret_cast(&client), - reinterpret_cast(&target)); - } - - if (d->probe) { - // Let's read the initial state so that callback coming later can - // see a difference. Ignore errors though. - SCNetworkReachabilityGetFlags(d->probe, &d->state); - }else { - qCWarning(lcNetMon, "Failed to create network reachability probe"); - return false; - } - - return true; + return false; } bool QNetworkConnectionMonitor::startMonitoring() { Q_D(QNetworkConnectionMonitor); - if (isMonitoring()) { + if (d->isMonitoring()) { qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first"); return false; } - if (!d->probe) { - qCWarning(lcNetMon, "Can not start monitoring, set targets first"); - return false; - } - - auto queue = qt_reachability_queue(); - if (!queue) { - qCWarning(lcNetMon, "Failed to create a dispatch queue to schedule a probe on"); - return false; - } - - SCNetworkReachabilityContext context = {}; - context.info = d; - context.retain = QNetworkConnectionMonitorPrivate::retainInfo; - context.release = QNetworkConnectionMonitorPrivate::releaseInfo; - if (!SCNetworkReachabilitySetCallback(d->probe, QNetworkConnectionMonitorPrivate::probeCallback, &context)) { - qCWarning(lcNetMon, "Failed to set a reachability callback"); - return false; - } - - - if (!SCNetworkReachabilitySetDispatchQueue(d->probe, queue)) { - qCWarning(lcNetMon, "Failed to schedule a reachability callback on a queue"); - return false; - } - - return d->scheduled = true; -} - -bool QNetworkConnectionMonitor::isMonitoring() const -{ - Q_D(const QNetworkConnectionMonitor); - - return d->scheduled; -} - -void QNetworkConnectionMonitor::stopMonitoring() -{ - Q_D(QNetworkConnectionMonitor); - - if (d->scheduled) { - Q_ASSERT(d->probe); - SCNetworkReachabilitySetDispatchQueue(d->probe, nullptr); - SCNetworkReachabilitySetCallback(d->probe, nullptr, nullptr); - d->scheduled = false; - } + return d->startMonitoring(); } bool QNetworkConnectionMonitor::isReachable() @@ -323,36 +226,30 @@ void waitForRefCountZero() return false; } - if (!d->probe) { - qCWarning(lcNetMon, "Reachability is unknown, set the target first"); - return false; - } - return d->isReachable(); } -#ifdef QT_PLATFORM_UIKIT -bool QNetworkConnectionMonitor::isWwan() const +QNetworkConnectionMonitor::InterfaceType QNetworkConnectionMonitor::getInterfaceType() const { Q_D(const QNetworkConnectionMonitor); - if (isMonitoring()) { - qCWarning(lcNetMon, "Calling isWwan() is unsafe after the monitoring started"); - return false; + if (d->isMonitoring()) { + qCWarning(lcNetMon, "Calling getInterfaceType() is unsafe after the monitoring started"); + return QNetworkConnectionMonitor::InterfaceType::Unknown; } - if (!d->probe) { - qCWarning(lcNetMon, "Medium is unknown, set the target first"); - return false; - } - - return d->isWwan(); + return d->getInterfaceType(); } -#endif bool QNetworkConnectionMonitor::isEnabled() { return true; } +bool QNetworkConnectionMonitor::isMonitoring() const +{ + Q_D(const QNetworkConnectionMonitor); + return d->isMonitoring(); +} + QT_END_NAMESPACE diff --git a/src/network/kernel/qnetconmonitor_p.h b/src/network/kernel/qnetconmonitor_p.h index 40d4b955ddf..bb11f50bd27 100644 --- a/src/network/kernel/qnetconmonitor_p.h +++ b/src/network/kernel/qnetconmonitor_p.h @@ -29,15 +29,24 @@ class Q_NETWORK_EXPORT QNetworkConnectionMonitor : public QObject Q_OBJECT public: +#ifdef Q_OS_APPLE + enum class InterfaceType { + Unknown, + Ethernet, + Cellular, + WiFi, + }; + Q_ENUM(InterfaceType) +#endif + QNetworkConnectionMonitor(); QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote = {}); ~QNetworkConnectionMonitor(); bool setTargets(const QHostAddress &local, const QHostAddress &remote); bool isReachable(); - -#ifdef QT_PLATFORM_UIKIT - bool isWwan() const; +#ifdef Q_OS_APPLE + InterfaceType getInterfaceType() const; #endif // Important: on Darwin you should not call isReachable/isWwan() after @@ -53,9 +62,8 @@ class Q_NETWORK_EXPORT QNetworkConnectionMonitor : public QObject // Important: connect to this using QueuedConnection. On Darwin // callback is coming on a special dispatch queue. void reachabilityChanged(bool isOnline); - -#ifdef QT_PLATFORM_UIKIT - void isWwanChanged(bool isWwan); +#ifdef Q_OS_APPLE + void interfaceTypeChanged(InterfaceType type); #endif private: diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp index 5115372b207..2c95f5e615e 100644 --- a/src/network/kernel/qnetworkinformation.cpp +++ b/src/network/kernel/qnetworkinformation.cpp @@ -646,7 +646,7 @@ QNetworkInformation::Features QNetworkInformation::supportedFeatures() const \li networklistmanager \row \li Apple (macOS/iOS) - \li scnetworkreachability + \li applenetworkinformation \row \li Android \li android diff --git a/src/network/kernel/qnetworkinformation_p.h b/src/network/kernel/qnetworkinformation_p.h index 76b2937cedc..291b87a2548 100644 --- a/src/network/kernel/qnetworkinformation_p.h +++ b/src/network/kernel/qnetworkinformation_p.h @@ -32,9 +32,9 @@ class Q_NETWORK_EXPORT QNetworkInformationBackend : public QObject using TransportMedium = QNetworkInformation::TransportMedium; public: - static inline const char16_t PluginNames[4][22] = { + static inline const char16_t PluginNames[4][24] = { { u"networklistmanager" }, - { u"scnetworkreachability" }, + { u"applenetworkinformation" }, { u"android" }, { u"networkmanager" }, }; diff --git a/src/plugins/networkinformation/CMakeLists.txt b/src/plugins/networkinformation/CMakeLists.txt index 04da816264a..49c8ae5918a 100644 --- a/src/plugins/networkinformation/CMakeLists.txt +++ b/src/plugins/networkinformation/CMakeLists.txt @@ -10,7 +10,7 @@ if(LINUX AND TARGET Qt::DBus) endif() if(APPLE) - add_subdirectory(scnetworkreachability) + add_subdirectory(apple) endif() if(ANDROID) diff --git a/src/plugins/networkinformation/apple/CMakeLists.txt b/src/plugins/networkinformation/apple/CMakeLists.txt new file mode 100644 index 00000000000..546eb919c58 --- /dev/null +++ b/src/plugins/networkinformation/apple/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(QAppleNetworkInformationPlugin + OUTPUT_NAME qapplenetworkinformation + CLASS_NAME QAppleNetworkInformationBackendFactory + PLUGIN_TYPE networkinformation + DEFAULT_IF APPLE + SOURCES + qapplenetworkinformationbackend.mm + LIBRARIES + Qt::NetworkPrivate + ${FWNetwork} +) diff --git a/src/plugins/networkinformation/apple/qapplenetworkinformationbackend.mm b/src/plugins/networkinformation/apple/qapplenetworkinformationbackend.mm new file mode 100644 index 00000000000..fa01829d2c0 --- /dev/null +++ b/src/plugins/networkinformation/apple/qapplenetworkinformationbackend.mm @@ -0,0 +1,123 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcNetInfoSCR) +Q_LOGGING_CATEGORY(lcNetInfoSCR, "qt.network.info.applenetworkinfo"); + +static QString backendName() +{ + return QString::fromUtf16(QNetworkInformationBackend::PluginNames + [QNetworkInformationBackend::PluginNamesAppleIndex]); +} + +class QAppleNetworkInformationBackend : public QNetworkInformationBackend +{ + Q_OBJECT +public: + QAppleNetworkInformationBackend(); + ~QAppleNetworkInformationBackend(); + + QString name() const override { return backendName(); } + QNetworkInformation::Features featuresSupported() const override + { + return featuresSupportedStatic(); + } + + static QNetworkInformation::Features featuresSupportedStatic() + { + return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability + | QNetworkInformation::Feature::TransportMedium); + } + +private Q_SLOTS: + void reachabilityChanged(bool isOnline); + void interfaceTypeChanged(QNetworkConnectionMonitor::InterfaceType type); + +private: + Q_DISABLE_COPY_MOVE(QAppleNetworkInformationBackend) + + QNetworkConnectionMonitor probe; +}; + +class QAppleNetworkInformationBackendFactory : public QNetworkInformationBackendFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid) + Q_INTERFACES(QNetworkInformationBackendFactory) +public: + QAppleNetworkInformationBackendFactory() = default; + ~QAppleNetworkInformationBackendFactory() = default; + QString name() const override { return backendName(); } + QNetworkInformation::Features featuresSupported() const override + { + return QAppleNetworkInformationBackend::featuresSupportedStatic(); + } + + QNetworkInformationBackend *create( + QNetworkInformation::Features requiredFeatures) const override + { + if ((requiredFeatures & featuresSupported()) != requiredFeatures) + return nullptr; + return new QAppleNetworkInformationBackend(); + } + +private: + Q_DISABLE_COPY_MOVE(QAppleNetworkInformationBackendFactory) +}; + +QAppleNetworkInformationBackend::QAppleNetworkInformationBackend() +{ + connect(&probe, &QNetworkConnectionMonitor::reachabilityChanged, this, + &QAppleNetworkInformationBackend::reachabilityChanged, + Qt::QueuedConnection); + connect(&probe, &QNetworkConnectionMonitor::interfaceTypeChanged, this, + &QAppleNetworkInformationBackend::interfaceTypeChanged, + Qt::QueuedConnection); + probe.startMonitoring(); +} + +QAppleNetworkInformationBackend::~QAppleNetworkInformationBackend() +{ +} + +void QAppleNetworkInformationBackend::reachabilityChanged(bool isOnline) +{ + setReachability(isOnline ? QNetworkInformation::Reachability::Online + : QNetworkInformation::Reachability::Disconnected); +} + +void QAppleNetworkInformationBackend::interfaceTypeChanged( + QNetworkConnectionMonitor::InterfaceType type) +{ + + if (reachability() == QNetworkInformation::Reachability::Disconnected) { + setTransportMedium(QNetworkInformation::TransportMedium::Unknown); + } else { + switch (type) { + case QNetworkConnectionMonitor::InterfaceType::Ethernet: + setTransportMedium(QNetworkInformation::TransportMedium::Ethernet); + break; + case QNetworkConnectionMonitor::InterfaceType::Cellular: + setTransportMedium(QNetworkInformation::TransportMedium::Cellular); + break; + case QNetworkConnectionMonitor::InterfaceType::WiFi: + setTransportMedium(QNetworkInformation::TransportMedium::WiFi); + break; + case QNetworkConnectionMonitor::InterfaceType::Unknown: + setTransportMedium(QNetworkInformation::TransportMedium::Unknown); + break; + } + } +} + +QT_END_NAMESPACE + +#include "qapplenetworkinformationbackend.moc" diff --git a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt deleted file mode 100644 index a939ab44058..00000000000 --- a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -qt_internal_add_plugin(QSCNetworkReachabilityNetworkInformationPlugin - OUTPUT_NAME qscnetworkreachability - CLASS_NAME QSCNetworkReachabilityNetworkInformationBackendFactory - PLUGIN_TYPE networkinformation - DEFAULT_IF APPLE - SOURCES - qscnetworkreachabilitynetworkinformationbackend.mm - LIBRARIES - Qt::NetworkPrivate - ${FWSystemConfiguration} -) diff --git a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm deleted file mode 100644 index d1f3cb41d4e..00000000000 --- a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include - -#include - -#include -#include - -QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcNetInfoSCR) -Q_LOGGING_CATEGORY(lcNetInfoSCR, "qt.network.info.scnetworkreachability"); - -static QString backendName() -{ - return QString::fromUtf16(QNetworkInformationBackend::PluginNames - [QNetworkInformationBackend::PluginNamesAppleIndex]); -} - -class QSCNetworkReachabilityNetworkInformationBackend : public QNetworkInformationBackend -{ - Q_OBJECT -public: - QSCNetworkReachabilityNetworkInformationBackend(); - ~QSCNetworkReachabilityNetworkInformationBackend(); - - QString name() const override { return backendName(); } - QNetworkInformation::Features featuresSupported() const override - { - return featuresSupportedStatic(); - } - - static QNetworkInformation::Features featuresSupportedStatic() - { - return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability -#ifdef QT_PLATFORM_UIKIT - | QNetworkInformation::Feature::TransportMedium -#endif - ); - } - -private Q_SLOTS: - void reachabilityChanged(bool isOnline); - -#ifdef QT_PLATFORM_UIKIT - void isWwanChanged(bool isOnline); -#endif - -private: - Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackend); - - QNetworkConnectionMonitor ipv4Probe; - QNetworkConnectionMonitor ipv6Probe; -}; - -class QSCNetworkReachabilityNetworkInformationBackendFactory : public QNetworkInformationBackendFactory -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid) - Q_INTERFACES(QNetworkInformationBackendFactory) -public: - QSCNetworkReachabilityNetworkInformationBackendFactory() = default; - ~QSCNetworkReachabilityNetworkInformationBackendFactory() = default; - QString name() const override { return backendName(); } - QNetworkInformation::Features featuresSupported() const override - { - return QSCNetworkReachabilityNetworkInformationBackend::featuresSupportedStatic(); - } - - QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override - { - if ((requiredFeatures & featuresSupported()) != requiredFeatures) - return nullptr; - return new QSCNetworkReachabilityNetworkInformationBackend(); - } - -private: - Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackendFactory); -}; - -QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkInformationBackend() -{ - bool isOnline = false; -#ifdef QT_PLATFORM_UIKIT - bool isWwan = false; -#endif - if (ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) { - // We manage to create SCNetworkReachabilityRef for IPv4, let's - // read the last known state then! - isOnline |= ipv4Probe.isReachable(); -#ifdef QT_PLATFORM_UIKIT - isWwan |= ipv4Probe.isWwan(); -#endif - ipv4Probe.startMonitoring(); - } - - if (ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) { - // We manage to create SCNetworkReachability ref for IPv6, let's - // read the last known state then! - isOnline |= ipv6Probe.isReachable(); -#ifdef QT_PLATFORM_UIKIT - isWwan |= ipv6Probe.isWwan(); -#endif - ipv6Probe.startMonitoring(); - } - reachabilityChanged(isOnline); -#ifdef QT_PLATFORM_UIKIT - isWwanChanged(isWwan); -#endif - - connect(&ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this, - &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged, - Qt::QueuedConnection); - connect(&ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this, - &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged, - Qt::QueuedConnection); - -#ifdef QT_PLATFORM_UIKIT - connect(&ipv4Probe, &QNetworkConnectionMonitor::isWwanChanged, this, - &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged, - Qt::QueuedConnection); - connect(&ipv6Probe, &QNetworkConnectionMonitor::isWwanChanged, this, - &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged, - Qt::QueuedConnection); -#endif -} - -QSCNetworkReachabilityNetworkInformationBackend::~QSCNetworkReachabilityNetworkInformationBackend() -{ -} - -void QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged(bool isOnline) -{ - setReachability(isOnline ? QNetworkInformation::Reachability::Online - : QNetworkInformation::Reachability::Disconnected); -} - -#ifdef QT_PLATFORM_UIKIT -void QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged(bool isWwan) -{ - // The reachability API from Apple only has one entry regarding transport medium: "IsWWAN"[0]. - // This is _serviceable_ on iOS where the only other credible options are "WLAN" or - // "Disconnected". But on macOS you could be connected by Ethernet as well, so how would that be - // reported? It doesn't matter anyway since "IsWWAN" is not available on macOS. - // [0]: https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityflags/kscnetworkreachabilityflagsiswwan?language=objc - if (reachability() == QNetworkInformation::Reachability::Disconnected) { - setTransportMedium(QNetworkInformation::TransportMedium::Unknown); - } else { - setTransportMedium(isWwan ? QNetworkInformation::TransportMedium::Cellular - : QNetworkInformation::TransportMedium::WiFi); - } -} -#endif - -QT_END_NAMESPACE - -#include "qscnetworkreachabilitynetworkinformationbackend.moc"