summaryrefslogtreecommitdiffstats
path: root/src/network/kernel/qnetworkinformation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/kernel/qnetworkinformation.cpp')
-rw-r--r--src/network/kernel/qnetworkinformation.cpp326
1 files changed, 264 insertions, 62 deletions
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
index c36b1c4698..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,9 +26,9 @@ 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("/networkinformationbackends")))
+ QStringLiteral("/networkinformation")))
struct QStaticNetworkInformationDataHolder
{
@@ -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,13 +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()); });
+ &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);
}
/*!
@@ -505,6 +549,55 @@ QNetworkInformation::Reachability QNetworkInformation::reachability() const
}
/*!
+ \property QNetworkInformation::isBehindCaptivePortal
+ \brief Lets you know if the user's device is behind a captive portal.
+ \since 6.2
+
+ This property indicates if the user's device is currently known to be
+ behind a captive portal. This functionality relies on the operating system's
+ detection of captive portals and is not supported on systems that don't
+ report this. On systems where this is not supported this will always return
+ \c{false}.
+*/
+bool QNetworkInformation::isBehindCaptivePortal() const
+{
+ return d_func()->backend->behindCaptivePortal();
+}
+
+/*!
+ \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
@@ -522,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.
*/
@@ -570,3 +768,7 @@ QNetworkInformation *QNetworkInformation::instance()
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkinformation.cpp"
+#include "moc_qnetworkinformation_p.cpp"
+#include "qnetworkinformation.moc"