summaryrefslogtreecommitdiffstats
path: root/src/plugins/networkinformation/networkmanager
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/networkinformation/networkmanager')
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt13
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp161
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp142
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h154
4 files changed, 470 insertions, 0 deletions
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
new file mode 100644
index 0000000000..900364c32f
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
+ OUTPUT_NAME networkmanager
+ CLASS_NAME QNetworkManagerNetworkInformationBackendFactory
+ TYPE networkinformation
+ DEFAULT_IF LINUX
+ SOURCES
+ qnetworkmanagernetworkinformationbackend.cpp
+ qnetworkmanagerservice.h
+ qnetworkmanagerservice.cpp
+ PUBLIC_LIBRARIES
+ Qt::DBus
+ Qt::NetworkPrivate
+)
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
new file mode 100644
index 0000000000..bfb04ae4a6
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include "qnetworkmanagerservice.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <QtDBus/qdbusmessage.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
+Q_LOGGING_CATEGORY(lcNetInfoNM, "qt.network.info.networkmanager");
+
+namespace {
+QNetworkInformation::Reachability reachabilityFromNMState(QNetworkManagerInterface::NMState state)
+{
+ switch (state) {
+ case QNetworkManagerInterface::NM_STATE_UNKNOWN:
+ case QNetworkManagerInterface::NM_STATE_ASLEEP:
+ case QNetworkManagerInterface::NM_STATE_CONNECTING:
+ return QNetworkInformation::Reachability::Unknown;
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTING: // No point in starting new connections:
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTED:
+ return QNetworkInformation::Reachability::Disconnected;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_LOCAL:
+ return QNetworkInformation::Reachability::Local;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_SITE:
+ return QNetworkInformation::Reachability::Site;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL:
+ return QNetworkInformation::Reachability::Online;
+ }
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+static QString backendName = QStringLiteral("networkmanager");
+
+class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkManagerNetworkInformationBackend();
+ ~QNetworkManagerNetworkInformationBackend() = default;
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+ }
+
+ bool isValid() const { return iface.isValid(); }
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+
+ QNetworkManagerInterface iface;
+};
+
+class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QNetworkManagerNetworkInformationBackendFactory() = default;
+ ~QNetworkManagerNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return {};
+ return QNetworkManagerNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return nullptr;
+ auto backend = new QNetworkManagerNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackendFactory)
+};
+
+QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend()
+{
+ using NMState = QNetworkManagerInterface::NMState;
+ setReachability(reachabilityFromNMState(iface.state()));
+ connect(&iface, &QNetworkManagerInterface::stateChanged, this,
+ [this](NMState newState) {
+ setReachability(reachabilityFromNMState(newState));
+ });
+
+ using ConnectivityState = QNetworkManagerInterface::NMConnectivityState;
+
+ const auto connectivityState = iface.connectivityState();
+ const bool behindPortal = (connectivityState == ConnectivityState::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+
+ connect(&iface, &QNetworkManagerInterface::connectivityChanged, this,
+ [this](ConnectivityState state) {
+ const bool behindPortal = (state == ConnectivityState::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+ });
+}
+
+QT_END_NAMESPACE
+
+#include "qnetworkmanagernetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
new file mode 100644
index 0000000000..764507fd4b
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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$
+**
+****************************************************************************/
+
+#include "qnetworkmanagerservice.h"
+
+#include <QObject>
+#include <QList>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusError>
+#include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusReply>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusObjectPath>
+#include <QtDBus/QDBusPendingCall>
+
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+
+QT_BEGIN_NAMESPACE
+
+QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
+ : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
+{
+}
+
+bool QNetworkManagerInterfaceBase::networkManagerAvailable()
+{
+ return QNetworkManagerInterfaceBase().isValid();
+}
+
+QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
+ : QNetworkManagerInterfaceBase(parent)
+{
+ if (!isValid())
+ return;
+
+ PropertiesDBusInterface managerPropertiesInterface(
+ QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), DBUS_PROPERTIES_INTERFACE,
+ QDBusConnection::systemBus());
+ QList<QVariant> argumentList;
+ argumentList << QLatin1String(NM_DBUS_INTERFACE);
+ QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
+ QDBus::Block, QLatin1String("GetAll"), argumentList);
+ if (!propsReply.isError()) {
+ propertyMap = propsReply.value();
+ } else {
+ qWarning() << "propsReply" << propsReply.error().message();
+ }
+
+ QDBusConnection::systemBus().connect(
+ QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), this,
+ SLOT(setProperties(QMap<QString, QVariant>)));
+}
+
+QNetworkManagerInterface::~QNetworkManagerInterface()
+{
+ QDBusConnection::systemBus().disconnect(
+ QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), this,
+ SLOT(setProperties(QMap<QString, QVariant>)));
+}
+
+QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
+{
+ if (propertyMap.contains("State"))
+ return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt());
+ return QNetworkManagerInterface::NM_STATE_UNKNOWN;
+}
+
+QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
+{
+ if (propertyMap.contains("Connectivity"))
+ return static_cast<NMConnectivityState>(propertyMap.value("Connectivity").toUInt());
+ return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
+}
+
+void QNetworkManagerInterface::setProperties(const QMap<QString, QVariant> &map)
+{
+ for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
+ const bool isState = i.key() == QLatin1String("State");
+ const bool isConnectivity = i.key() == QLatin1String("Connectivity");
+ bool stateUpdate = isState;
+ bool connectivityUpdate = isConnectivity;
+
+ auto it = propertyMap.lowerBound(i.key());
+ if (it != propertyMap.end() && it.key() == i.key()) {
+ stateUpdate &= (it.value() != i.value());
+ connectivityUpdate &= (it.value() != i.value());
+ *it = *i;
+ } else {
+ propertyMap.insert(it, i.key(), i.value());
+ }
+
+ if (stateUpdate) {
+ quint32 state = i.value().toUInt();
+ Q_EMIT stateChanged(static_cast<NMState>(state));
+ } else if (connectivityUpdate) {
+ quint32 state = i.value().toUInt();
+ Q_EMIT connectivityChanged(static_cast<NMConnectivityState>(state));
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
new file mode 100644
index 0000000000..57c5aed763
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKMANAGERSERVICE_H
+#define QNETWORKMANAGERSERVICE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtDBus/QDBusAbstractInterface>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusObjectPath>
+
+#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
+
+#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
+#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+
+// Matches 'NMDeviceState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+enum NMDeviceState {
+ NM_DEVICE_STATE_UNKNOWN = 0,
+ NM_DEVICE_STATE_UNMANAGED = 10,
+ NM_DEVICE_STATE_UNAVAILABLE = 20,
+ NM_DEVICE_STATE_DISCONNECTED = 30,
+ NM_DEVICE_STATE_PREPARE = 40,
+ NM_DEVICE_STATE_CONFIG = 50,
+ NM_DEVICE_STATE_NEED_AUTH = 60,
+ NM_DEVICE_STATE_IP_CONFIG = 70,
+ NM_DEVICE_STATE_ACTIVATED = 100,
+ NM_DEVICE_STATE_DEACTIVATING = 110,
+ NM_DEVICE_STATE_FAILED = 120
+};
+
+QT_BEGIN_NAMESPACE
+
+// This tiny class exists for the purpose of seeing if NetworkManager is available without
+// initializing everything the derived/full class needs.
+class QNetworkManagerInterfaceBase : public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ QNetworkManagerInterfaceBase(QObject *parent = nullptr);
+ ~QNetworkManagerInterfaceBase() = default;
+
+ static bool networkManagerAvailable();
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterfaceBase)
+};
+
+class QNetworkManagerInterface final : public QNetworkManagerInterfaceBase
+{
+ Q_OBJECT
+
+public:
+ // Matches 'NMState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+ enum NMState {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70
+ };
+ Q_ENUM(NMState);
+ // Matches 'NMConnectivityState' from
+ // https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMConnectivityState
+ enum NMConnectivityState {
+ NM_CONNECTIVITY_UNKNOWN = 0,
+ NM_CONNECTIVITY_NONE = 1,
+ NM_CONNECTIVITY_PORTAL = 2,
+ NM_CONNECTIVITY_LIMITED = 3,
+ NM_CONNECTIVITY_FULL = 4,
+ };
+ Q_ENUM(NMConnectivityState);
+
+ QNetworkManagerInterface(QObject *parent = nullptr);
+ ~QNetworkManagerInterface();
+
+ NMState state() const;
+ NMConnectivityState connectivityState() const;
+
+Q_SIGNALS:
+ void stateChanged(NMState);
+ void connectivityChanged(NMConnectivityState);
+
+private Q_SLOTS:
+ void setProperties(const QMap<QString, QVariant> &map);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterface)
+
+ QVariantMap propertyMap;
+};
+
+class PropertiesDBusInterface : public QDBusAbstractInterface
+{
+public:
+ PropertiesDBusInterface(const QString &service, const QString &path, const QString &interface,
+ const QDBusConnection &connection, QObject *parent = 0)
+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
+ {
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif