1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qnetworkmanagerservice.h"
5#include "qnetworkmanagernetworkinformationbackend.h"
6
7#include <QObject>
8#include <QList>
9#include <QtDBus/QDBusConnection>
10#include <QtDBus/QDBusError>
11#include <QtDBus/QDBusInterface>
12#include <QtDBus/QDBusMessage>
13#include <QtDBus/QDBusReply>
14#include <QtDBus/QDBusPendingCallWatcher>
15#include <QtDBus/QDBusObjectPath>
16#include <QtDBus/QDBusPendingCall>
17
18#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"_L1
19
20#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
21#define NM_DBUS_SERVICE NM_DBUS_INTERFACE ""_L1
22
23#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"_L1
24#define NM_CONNECTION_DBUS_INTERFACE NM_DBUS_SERVICE ".Connection.Active"_L1
25#define NM_DEVICE_DBUS_INTERFACE NM_DBUS_SERVICE ".Device"_L1
26
27QT_BEGIN_NAMESPACE
28
29using namespace Qt::StringLiterals;
30
31namespace {
32constexpr QLatin1StringView propertiesChangedKey = "PropertiesChanged"_L1;
33const QString &stateKey()
34{
35 static auto key = u"State"_s;
36 return key;
37}
38const QString &connectivityKey()
39{
40 static auto key = u"Connectivity"_s;
41 return key;
42}
43const QString &primaryConnectionKey()
44{
45 static auto key = u"PrimaryConnection"_s;
46 return key;
47}
48}
49
50QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
51 : QDBusAbstractInterface(NM_DBUS_SERVICE, NM_DBUS_PATH,
52 NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
53{
54}
55
56bool QNetworkManagerInterfaceBase::networkManagerAvailable()
57{
58 return QNetworkManagerInterfaceBase().isValid();
59}
60
61QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
62 : QNetworkManagerInterfaceBase(parent)
63{
64 if (!QDBusAbstractInterface::isValid())
65 return;
66
67 PropertiesDBusInterface managerPropertiesInterface(
68 NM_DBUS_SERVICE, NM_DBUS_PATH, DBUS_PROPERTIES_INTERFACE,
69 QDBusConnection::systemBus());
70 QList<QVariant> argumentList;
71 argumentList << NM_DBUS_SERVICE;
72 QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
73 mode: QDBus::Block, method: "GetAll"_L1, args: argumentList);
74 if (propsReply.isError()) {
75 validDBusConnection = false;
76 if (auto error = propsReply.error(); error.type() != QDBusError::AccessDenied)
77 qWarning() << "Failed to query NetworkManager properties:" << error.message();
78 return;
79 }
80 propertyMap = propsReply.value();
81
82 validDBusConnection = QDBusConnection::systemBus().connect(NM_DBUS_SERVICE, NM_DBUS_PATH,
83 DBUS_PROPERTIES_INTERFACE, name: propertiesChangedKey, receiver: this,
84 SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
85}
86
87QNetworkManagerInterface::~QNetworkManagerInterface()
88{
89 QDBusConnection::systemBus().disconnect(NM_DBUS_SERVICE, NM_DBUS_PATH,
90 DBUS_PROPERTIES_INTERFACE, name: propertiesChangedKey, receiver: this,
91 SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
92}
93
94QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
95{
96 auto it = propertyMap.constFind(key: stateKey());
97 if (it != propertyMap.cend())
98 return static_cast<QNetworkManagerInterface::NMState>(it->toUInt());
99 return QNetworkManagerInterface::NM_STATE_UNKNOWN;
100}
101
102QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
103{
104 auto it = propertyMap.constFind(key: connectivityKey());
105 if (it != propertyMap.cend())
106 return static_cast<NMConnectivityState>(it->toUInt());
107 return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
108}
109
110static std::optional<QDBusInterface> getPrimaryDevice(const QDBusObjectPath &devicePath)
111{
112 const QDBusInterface connection(NM_DBUS_SERVICE, devicePath.path(),
113 NM_CONNECTION_DBUS_INTERFACE, QDBusConnection::systemBus());
114 if (!connection.isValid())
115 return std::nullopt;
116
117 const auto devicePaths = connection.property(name: "Devices").value<QList<QDBusObjectPath>>();
118 if (devicePaths.isEmpty())
119 return std::nullopt;
120
121 const QDBusObjectPath primaryDevicePath = devicePaths.front();
122 return std::make_optional<QDBusInterface>(NM_DBUS_SERVICE, args: primaryDevicePath.path(),
123 NM_DEVICE_DBUS_INTERFACE,
124 args: QDBusConnection::systemBus());
125}
126
127std::optional<QDBusObjectPath> QNetworkManagerInterface::primaryConnectionDevicePath() const
128{
129 auto it = propertyMap.constFind(key: primaryConnectionKey());
130 if (it != propertyMap.cend())
131 return it->value<QDBusObjectPath>();
132 return std::nullopt;
133}
134
135auto QNetworkManagerInterface::deviceType() const -> NMDeviceType
136{
137 if (const auto path = primaryConnectionDevicePath())
138 return extractDeviceType(devicePath: *path);
139 return NM_DEVICE_TYPE_UNKNOWN;
140}
141
142auto QNetworkManagerInterface::meteredState() const -> NMMetered
143{
144 if (const auto path = primaryConnectionDevicePath())
145 return extractDeviceMetered(devicePath: *path);
146 return NM_METERED_UNKNOWN;
147}
148
149auto QNetworkManagerInterface::extractDeviceType(const QDBusObjectPath &devicePath) const
150 -> NMDeviceType
151{
152 const auto primaryDevice = getPrimaryDevice(devicePath);
153 if (!primaryDevice)
154 return NM_DEVICE_TYPE_UNKNOWN;
155 if (!primaryDevice->isValid())
156 return NM_DEVICE_TYPE_UNKNOWN;
157 const QVariant deviceType = primaryDevice->property(name: "DeviceType");
158 if (!deviceType.isValid())
159 return NM_DEVICE_TYPE_UNKNOWN;
160 return static_cast<NMDeviceType>(deviceType.toUInt());
161}
162
163auto QNetworkManagerInterface::extractDeviceMetered(const QDBusObjectPath &devicePath) const
164 -> NMMetered
165{
166 const auto primaryDevice = getPrimaryDevice(devicePath);
167 if (!primaryDevice)
168 return NM_METERED_UNKNOWN;
169 if (!primaryDevice->isValid())
170 return NM_METERED_UNKNOWN;
171 const QVariant metered = primaryDevice->property(name: "Metered");
172 if (!metered.isValid())
173 return NM_METERED_UNKNOWN;
174 return static_cast<NMMetered>(metered.toUInt());
175}
176
177void QNetworkManagerInterface::setBackend(QNetworkManagerNetworkInformationBackend *ourBackend)
178{
179 backend = ourBackend;
180}
181
182void QNetworkManagerInterface::setProperties(const QString &interfaceName,
183 const QMap<QString, QVariant> &map,
184 const QStringList &invalidatedProperties)
185{
186 Q_UNUSED(interfaceName);
187 Q_UNUSED(invalidatedProperties);
188
189 for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
190 bool valueChanged = true;
191
192 auto it = propertyMap.lowerBound(key: i.key());
193 if (it != propertyMap.end() && it.key() == i.key()) {
194 valueChanged = (it.value() != i.value());
195 *it = *i;
196 } else {
197 propertyMap.insert(pos: it, key: i.key(), value: i.value());
198 }
199
200 if (valueChanged) {
201 if (i.key() == stateKey()) {
202 quint32 state = i.value().toUInt();
203 backend->onStateChanged(state: static_cast<NMState>(state));
204 } else if (i.key() == connectivityKey()) {
205 quint32 state = i.value().toUInt();
206 backend->onConnectivityChanged(connectivityState: static_cast<NMConnectivityState>(state));
207 } else if (i.key() == primaryConnectionKey()) {
208 const QDBusObjectPath devicePath = i->value<QDBusObjectPath>();
209 backend->onDeviceTypeChanged(deviceType: extractDeviceType(devicePath));
210 backend->onMeteredChanged(metered: extractDeviceMetered(devicePath));
211 } else if (i.key() == "Metered"_L1) {
212 backend->onMeteredChanged(metered: static_cast<NMMetered>(i->toUInt()));
213 }
214 }
215 }
216}
217
218QT_END_NAMESPACE
219
220#include "moc_qnetworkmanagerservice.cpp"
221

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp