diff options
Diffstat (limited to 'src')
5 files changed, 435 insertions, 0 deletions
diff --git a/src/plugins/networkinformationbackends/CMakeLists.txt b/src/plugins/networkinformationbackends/CMakeLists.txt index 94a1f6baba..d1770d5eb7 100644 --- a/src/plugins/networkinformationbackends/CMakeLists.txt +++ b/src/plugins/networkinformationbackends/CMakeLists.txt @@ -1,3 +1,7 @@ if(WIN32 AND QT_FEATURE_networklistmanager) add_subdirectory(networklistmanager) endif() + +if(LINUX) + add_subdirectory(networkmanager) +endif() diff --git a/src/plugins/networkinformationbackends/networkmanager/CMakeLists.txt b/src/plugins/networkinformationbackends/networkmanager/CMakeLists.txt new file mode 100644 index 0000000000..44a6e0f38d --- /dev/null +++ b/src/plugins/networkinformationbackends/networkmanager/CMakeLists.txt @@ -0,0 +1,12 @@ +qt_internal_add_plugin(QNetworkManagerNetworkInformationBackend + OUTPUT_NAME networkmanagernetworkinformationbackend + TYPE networkinformationbackends + DEFAULT_IF LINUX + SOURCES + qnetworkmanagernetworkinformationbackend.cpp + qnetworkmanagerservice.h + qnetworkmanagerservice.cpp + PUBLIC_LIBRARIES + Qt::DBus + Qt::NetworkPrivate +) diff --git a/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagernetworkinformationbackend.cpp new file mode 100644 index 0000000000..1677f36fe1 --- /dev/null +++ b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagernetworkinformationbackend.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** 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() + { + return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability); + } + + bool isValid() const { return iface.isValid(); } + +private: + QNetworkManagerInterface iface; + QNetworkManagerInterface::NMState prevState; +}; + +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; + } +}; + +QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend() +{ + prevState = iface.state(); + setReachability(reachabilityFromNMState(prevState)); + connect(&iface, &QNetworkManagerInterface::stateChanged, this, [this]() { + auto newState = iface.state(); + if (newState != prevState) { + prevState = newState; + setReachability(reachabilityFromNMState(prevState)); + } + }); +} + +QT_END_NAMESPACE + +#include "qnetworkmanagernetworkinformationbackend.moc" diff --git a/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.cpp new file mode 100644 index 0000000000..da5ef955fa --- /dev/null +++ b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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/QtDBus> +#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() +{ + if (propertyMap.contains("State")) + return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt()); + return QNetworkManagerInterface::NM_STATE_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"); + bool stateUpdate = isState; + auto it = propertyMap.lowerBound(i.key()); + if (it != propertyMap.end() && it.key() == i.key()) { + stateUpdate &= (it.value() != i.value()); + *it = *i; + } else { + propertyMap.insert(it, i.key(), i.value()); + } + + if (stateUpdate) { + quint32 state = i.value().toUInt(); + Q_EMIT stateChanged(state); + } + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.h new file mode 100644 index 0000000000..9624eaa216 --- /dev/null +++ b/src/plugins/networkinformationbackends/networkmanager/qnetworkmanagerservice.h @@ -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$ +** +****************************************************************************/ + +#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); + + QNetworkManagerInterface(QObject *parent = nullptr); + ~QNetworkManagerInterface(); + + NMState state(); + +Q_SIGNALS: + void stateChanged(quint32); + +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 |