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