diff options
Diffstat (limited to 'src/network/kernel/qnetworkinformation.cpp')
-rw-r--r-- | src/network/kernel/qnetworkinformation.cpp | 311 |
1 files changed, 247 insertions, 64 deletions
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp index 0dcbfde22b..10d6b89e2c 100644 --- a/src/network/kernel/qnetworkinformation.cpp +++ b/src/network/kernel/qnetworkinformation.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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 // #define DEBUG_LOADING @@ -62,7 +26,7 @@ struct QNetworkInformationDeleter void operator()(QNetworkInformation *information) { delete information; } }; -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qniLoader, (QNetworkInformationBackendFactory_iid, QStringLiteral("/networkinformation"))) @@ -83,14 +47,21 @@ static void networkInfoCleanup() if (!instance) return; - auto needsReinvoke = instance->thread() && instance->thread() != QThread::currentThread(); - if (needsReinvoke) { - QMetaObject::invokeMethod(dataHolder->instanceHolder.get(), []() { networkInfoCleanup(); }); - return; - } dataHolder->instanceHolder.reset(); } +using namespace Qt::Literals::StringLiterals; + +class QNetworkInformationDummyBackend : public QNetworkInformationBackend { + Q_OBJECT +public: + QString name() const override { return u"dummy"_s; } + QNetworkInformation::Features featuresSupported() const override + { + return {}; + } +}; + class QNetworkInformationPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QNetworkInformation) @@ -101,6 +72,7 @@ public: static QNetworkInformation *create(QNetworkInformation::Features features); static QNetworkInformation *create(QStringView name); + static QNetworkInformation *createDummy(); static QNetworkInformation *instance() { if (!dataHolder()) @@ -120,19 +92,19 @@ private: bool QNetworkInformationPrivate::initializeList() { - if (!loader()) + if (!qniLoader()) return false; if (!dataHolder()) return false; - static QBasicMutex mutex; + Q_CONSTINIT static QBasicMutex mutex; QMutexLocker initLocker(&mutex); #if QT_CONFIG(library) - loader->update(); + qniLoader->update(); #endif // Instantiates the plugins (and registers the factories) int index = 0; - while (loader->instance(index)) + while (qniLoader->instance(index)) ++index; initLocker.unlock(); @@ -223,8 +195,8 @@ QNetworkInformation *QNetworkInformationPrivate::create(QStringView name) } else { QString listNames; listNames.reserve(8 * dataHolder->factories.count()); - for (const auto *factory : qAsConst(dataHolder->factories)) - listNames += factory->name() + QStringLiteral(", "); + for (const auto *factory : std::as_const(dataHolder->factories)) + listNames += factory->name() + ", "_L1; listNames.chop(2); qDebug().nospace() << "Couldn't find " << name << " in list with names: { " << listNames << " }"; @@ -235,7 +207,7 @@ QNetworkInformation *QNetworkInformationPrivate::create(QStringView name) #ifdef DEBUG_LOADING qDebug() << "Creating instance using loader named " << (*it)->name(); #endif - QNetworkInformationBackend *backend = (*it)->create({}); + QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported()); if (!backend) return nullptr; dataHolder->instanceHolder.reset(new QNetworkInformation(backend)); @@ -266,7 +238,7 @@ QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Fea return dataHolder->instanceHolder.get(); const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) { - return factory && (factory->featuresSupported() & features) == features; + return factory && factory->featuresSupported().testFlags(features); }; for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end; @@ -279,7 +251,7 @@ QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Fea } else { QStringList names; names.reserve(dataHolder->factories.count()); - for (const auto *factory : qAsConst(dataHolder->factories)) + for (const auto *factory : std::as_const(dataHolder->factories)) names += factory->name(); qDebug() << "None of the following backends has all the requested features:" << names << features; @@ -307,6 +279,20 @@ QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Fea return nullptr; } +QNetworkInformation *QNetworkInformationPrivate::createDummy() +{ + if (!dataHolder()) + return nullptr; + + QMutexLocker locker(&dataHolder->instanceMutex); + if (dataHolder->instanceHolder) + return dataHolder->instanceHolder.get(); + + QNetworkInformationBackend *backend = new QNetworkInformationDummyBackend; + dataHolder->instanceHolder.reset(new QNetworkInformation(backend)); + return dataHolder->instanceHolder.get(); +} + /*! \class QNetworkInformationBackend \internal (Semi-private) @@ -417,6 +403,7 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() /*! \class QNetworkInformation + \inmodule QtNetwork \since 6.1 \brief QNetworkInformation exposes various network information through native backends. @@ -442,9 +429,26 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() This can be used in QNetworkInformation::load(). \value Reachability - If the plugin supports this feature then - the \c reachability property will be available. + If the plugin supports this feature then the \c reachability property + will provide useful results. Otherwise it will always return + \c{Reachability::Unknown}. See also QNetworkInformation::Reachability. + + \value CaptivePortal + If the plugin supports this feature then the \c isBehindCaptivePortal + property will provide useful results. Otherwise it will always return + \c{false}. + + \value TransportMedium + If the plugin supports this feature then the \c transportMedium + property will provide useful results. Otherwise it will always return + \c{TransportMedium::Unknown}. + See also QNetworkInformation::TransportMedium. + + \value Metered + If the plugin supports this feature then the \c isMetered + property will provide useful results. Otherwise it will always return + \c{false}. */ /*! @@ -471,16 +475,53 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() */ /*! + \enum QNetworkInformation::TransportMedium + \since 6.3 + + Lists the currently recognized media with which one can connect to the + internet. + + \value Unknown + Returned if either the OS reports no active medium, the active medium is + not recognized by Qt, or the TransportMedium feature is not supported. + \value Ethernet + Indicates that the currently active connection is using ethernet. + Note: This value may also be returned when Windows is connected to a + Bluetooth personal area network. + \value Cellular + Indicates that the currently active connection is using a cellular + network. + \value WiFi + Indicates that the currently active connection is using Wi-Fi. + \value Bluetooth + Indicates that the currently active connection is connected using + Bluetooth. + + \sa QNetworkInformation::transportMedium +*/ + +/*! \internal ctor */ QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend) : QObject(*(new QNetworkInformationPrivate(backend))) { connect(backend, &QNetworkInformationBackend::reachabilityChanged, this, - [this]() { emit reachabilityChanged(d_func()->backend->reachability()); }); - connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this, [this]() { - emit isBehindCaptivePortalChanged(d_func()->backend->behindCaptivePortal()); - }); + &QNetworkInformation::reachabilityChanged); + connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this, + &QNetworkInformation::isBehindCaptivePortalChanged); + connect(backend, &QNetworkInformationBackend::transportMediumChanged, this, + &QNetworkInformation::transportMediumChanged); + connect(backend, &QNetworkInformationBackend::isMeteredChanged, this, + &QNetworkInformation::isMeteredChanged); + + QThread *main = nullptr; + + if (QCoreApplication::instance()) + main = QCoreApplication::instance()->thread(); + + if (main && thread() != main) + moveToThread(main); } /*! @@ -524,6 +565,39 @@ bool QNetworkInformation::isBehindCaptivePortal() const } /*! + \property QNetworkInformation::transportMedium + \brief The currently active transport medium for the application + \since 6.3 + + This property returns the currently active transport medium for the + application, on operating systems where such information is available. + + When the current transport medium changes a signal is emitted, this can, + for instance, occur when a user leaves the range of a WiFi network, unplugs + their ethernet cable or enables Airplane mode. +*/ +QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const +{ + return d_func()->backend->transportMedium(); +} + +/*! + \property QNetworkInformation::isMetered + \brief Check if the current connection is metered + \since 6.3 + + This property returns whether the current connection is (known to be) + metered or not. You can use this as a guiding factor to decide whether your + application should perform certain network requests or uploads. + For instance, you may not want to upload logs or diagnostics while this + property is \c true. +*/ +bool QNetworkInformation::isMetered() const +{ + return d_func()->backend->isMetered(); +} + +/*! Returns the name of the currently loaded backend. */ QString QNetworkInformation::backendName() const @@ -541,34 +615,139 @@ bool QNetworkInformation::supports(Features features) const } /*! + \since 6.3 + + Returns all the supported features of the current backend. +*/ +QNetworkInformation::Features QNetworkInformation::supportedFeatures() const +{ + return d_func()->backend->featuresSupported(); +} + +/*! + \since 6.3 + + Attempts to load the platform-default backend. + + \note Starting with 6.7 this tries to load any backend that supports + \l{QNetworkInformation::Feature::Reachability}{Reachability} if the + platform-default backend is not available or fails to load. + If this also fails it will fall back to a backend that only returns + the default values for all properties. + + This platform-to-plugin mapping is as follows: + + \table + \header + \li Platform + \li Plugin-name + \row + \li Windows + \li networklistmanager + \row + \li Apple (macOS/iOS) + \li scnetworkreachability + \row + \li Android + \li android + \row + \li Linux + \li networkmanager + \endtable + + This function is provided for convenience where the logic earlier + is good enough. If you require a specific plugin then you should call + loadBackendByName() or loadBackendByFeatures() directly instead. + + Determines a suitable backend to load and returns \c true if this backend + is already loaded or on successful loading of it. Returns \c false if any + other backend has already been loaded, or if loading of the selected + backend fails. + + \sa instance(), load() +*/ +bool QNetworkInformation::loadDefaultBackend() +{ + int index = -1; +#ifdef Q_OS_WIN + index = QNetworkInformationBackend::PluginNamesWindowsIndex; +#elif defined(Q_OS_DARWIN) + index = QNetworkInformationBackend::PluginNamesAppleIndex; +#elif defined(Q_OS_ANDROID) + index = QNetworkInformationBackend::PluginNamesAndroidIndex; +#elif defined(Q_OS_LINUX) + index = QNetworkInformationBackend::PluginNamesLinuxIndex; +#endif + if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index])) + return true; + // We assume reachability is the most commonly wanted feature, and try to + // load the backend that advertises the most features including that: + if (loadBackendByFeatures(Feature::Reachability)) + return true; + + // Fall back to the dummy backend + return loadBackendByName(u"dummy"); +} + +/*! + \since 6.4 + Attempts to load a backend whose name matches \a backend (case insensitively). Returns \c true if it managed to load the requested backend or - if it was already loaded. Returns \c false otherwise + if it was already loaded. Returns \c false otherwise. \sa instance */ -bool QNetworkInformation::load(QStringView backend) +bool QNetworkInformation::loadBackendByName(QStringView backend) { + if (backend == u"dummy") + return QNetworkInformationPrivate::createDummy() != nullptr; + auto loadedBackend = QNetworkInformationPrivate::create(backend); - return loadedBackend && loadedBackend->backendName() == backend; + return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0; +} + +#if QT_DEPRECATED_SINCE(6,4) +/*! + \deprecated [6.4] Use loadBackendByName() instead. + + \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures() +*/ +bool QNetworkInformation::load(QStringView backend) +{ + return loadBackendByName(backend); } +#endif // QT_DEPRECATED_SINCE(6,4) /*! + \since 6.4 Load a backend which supports \a features. Returns \c true if it managed to load the requested backend or - if it was already loaded. Returns \c false otherwise + if it was already loaded. Returns \c false otherwise. \sa instance */ -bool QNetworkInformation::load(Features features) +bool QNetworkInformation::loadBackendByFeatures(Features features) { auto loadedBackend = QNetworkInformationPrivate::create(features); return loadedBackend && loadedBackend->supports(features); } +#if QT_DEPRECATED_SINCE(6,4) +/*! + \deprecated [6.4] Use loadBackendByFeatures() instead. + + \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures() +*/ +bool QNetworkInformation::load(Features features) +{ + return loadBackendByFeatures(features); +} +#endif // QT_DEPRECATED_SINCE(6,4) + /*! Returns a list of the names of all currently available backends. */ @@ -589,3 +768,7 @@ QNetworkInformation *QNetworkInformation::instance() } QT_END_NAMESPACE + +#include "moc_qnetworkinformation.cpp" +#include "moc_qnetworkinformation_p.cpp" +#include "qnetworkinformation.moc" |