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 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | using namespace Qt::StringLiterals; |
30 | |
31 | namespace { |
32 | constexpr QLatin1StringView propertiesChangedKey = "PropertiesChanged"_L1; |
33 | const QString &stateKey() |
34 | { |
35 | static auto key = u"State"_s; |
36 | return key; |
37 | } |
38 | const QString &connectivityKey() |
39 | { |
40 | static auto key = u"Connectivity"_s; |
41 | return key; |
42 | } |
43 | const QString &primaryConnectionKey() |
44 | { |
45 | static auto key = u"PrimaryConnection"_s; |
46 | return key; |
47 | } |
48 | } |
49 | |
50 | QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent) |
51 | : QDBusAbstractInterface(NM_DBUS_SERVICE, NM_DBUS_PATH, |
52 | NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent) |
53 | { |
54 | } |
55 | |
56 | bool QNetworkManagerInterfaceBase::networkManagerAvailable() |
57 | { |
58 | return QNetworkManagerInterfaceBase().isValid(); |
59 | } |
60 | |
61 | QNetworkManagerInterface::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 | |
87 | QNetworkManagerInterface::~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 | |
94 | QNetworkManagerInterface::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 | |
102 | QNetworkManagerInterface::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 | |
110 | static 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 | |
127 | std::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 | |
135 | auto QNetworkManagerInterface::deviceType() const -> NMDeviceType |
136 | { |
137 | if (const auto path = primaryConnectionDevicePath()) |
138 | return extractDeviceType(devicePath: *path); |
139 | return NM_DEVICE_TYPE_UNKNOWN; |
140 | } |
141 | |
142 | auto QNetworkManagerInterface::meteredState() const -> NMMetered |
143 | { |
144 | if (const auto path = primaryConnectionDevicePath()) |
145 | return extractDeviceMetered(devicePath: *path); |
146 | return NM_METERED_UNKNOWN; |
147 | } |
148 | |
149 | auto 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 | |
163 | auto 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 | |
177 | void QNetworkManagerInterface::setBackend(QNetworkManagerNetworkInformationBackend *ourBackend) |
178 | { |
179 | backend = ourBackend; |
180 | } |
181 | |
182 | void 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 | |
218 | QT_END_NAMESPACE |
219 | |
220 | #include "moc_qnetworkmanagerservice.cpp" |
221 |
Definitions
Learn Advanced QML with KDAB
Find out more