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

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