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 <QtNetwork/private/qnetworkinformation_p.h> |
5 | |
6 | #include "qnetworkmanagerservice.h" |
7 | |
8 | #include <QtCore/qglobal.h> |
9 | #include <QtCore/private/qobject_p.h> |
10 | |
11 | #include <QtDBus/qdbusmessage.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM) |
15 | Q_LOGGING_CATEGORY(lcNetInfoNM, "qt.network.info.networkmanager" ); |
16 | |
17 | namespace { |
18 | QNetworkInformation::Reachability reachabilityFromNMState(QNetworkManagerInterface::NMState state) |
19 | { |
20 | switch (state) { |
21 | case QNetworkManagerInterface::NM_STATE_UNKNOWN: |
22 | case QNetworkManagerInterface::NM_STATE_ASLEEP: |
23 | case QNetworkManagerInterface::NM_STATE_CONNECTING: |
24 | return QNetworkInformation::Reachability::Unknown; |
25 | case QNetworkManagerInterface::NM_STATE_DISCONNECTING: // No point in starting new connections: |
26 | case QNetworkManagerInterface::NM_STATE_DISCONNECTED: |
27 | return QNetworkInformation::Reachability::Disconnected; |
28 | case QNetworkManagerInterface::NM_STATE_CONNECTED_LOCAL: |
29 | return QNetworkInformation::Reachability::Local; |
30 | case QNetworkManagerInterface::NM_STATE_CONNECTED_SITE: |
31 | return QNetworkInformation::Reachability::Site; |
32 | case QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL: |
33 | return QNetworkInformation::Reachability::Online; |
34 | } |
35 | return QNetworkInformation::Reachability::Unknown; |
36 | } |
37 | |
38 | QNetworkInformation::TransportMedium |
39 | transportMediumFromDeviceType(QNetworkManagerInterface::NMDeviceType type) |
40 | { |
41 | switch (type) { |
42 | case QNetworkManagerInterface::NM_DEVICE_TYPE_ETHERNET: |
43 | return QNetworkInformation::TransportMedium::Ethernet; |
44 | case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI: |
45 | return QNetworkInformation::TransportMedium::WiFi; |
46 | case QNetworkManagerInterface::NM_DEVICE_TYPE_BT: |
47 | return QNetworkInformation::TransportMedium::Bluetooth; |
48 | case QNetworkManagerInterface::NM_DEVICE_TYPE_MODEM: |
49 | return QNetworkInformation::TransportMedium::Cellular; |
50 | |
51 | case QNetworkManagerInterface::NM_DEVICE_TYPE_UNKNOWN: |
52 | case QNetworkManagerInterface::NM_DEVICE_TYPE_GENERIC: |
53 | case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED1: |
54 | case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED2: |
55 | case QNetworkManagerInterface::NM_DEVICE_TYPE_OLPC_MESH: |
56 | case QNetworkManagerInterface::NM_DEVICE_TYPE_WIMAX: |
57 | case QNetworkManagerInterface::NM_DEVICE_TYPE_INFINIBAND: |
58 | case QNetworkManagerInterface::NM_DEVICE_TYPE_BOND: |
59 | case QNetworkManagerInterface::NM_DEVICE_TYPE_VLAN: |
60 | case QNetworkManagerInterface::NM_DEVICE_TYPE_ADSL: |
61 | case QNetworkManagerInterface::NM_DEVICE_TYPE_BRIDGE: |
62 | case QNetworkManagerInterface::NM_DEVICE_TYPE_TEAM: |
63 | case QNetworkManagerInterface::NM_DEVICE_TYPE_TUN: |
64 | case QNetworkManagerInterface::NM_DEVICE_TYPE_IP_TUNNEL: |
65 | case QNetworkManagerInterface::NM_DEVICE_TYPE_MACVLAN: |
66 | case QNetworkManagerInterface::NM_DEVICE_TYPE_VXLAN: |
67 | case QNetworkManagerInterface::NM_DEVICE_TYPE_VETH: |
68 | case QNetworkManagerInterface::NM_DEVICE_TYPE_MACSEC: |
69 | case QNetworkManagerInterface::NM_DEVICE_TYPE_DUMMY: |
70 | case QNetworkManagerInterface::NM_DEVICE_TYPE_PPP: |
71 | case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_INTERFACE: |
72 | case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_PORT: |
73 | case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_BRIDGE: |
74 | case QNetworkManagerInterface::NM_DEVICE_TYPE_WPAN: |
75 | case QNetworkManagerInterface::NM_DEVICE_TYPE_6LOWPAN: |
76 | case QNetworkManagerInterface::NM_DEVICE_TYPE_WIREGUARD: |
77 | case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI_P2P: |
78 | case QNetworkManagerInterface::NM_DEVICE_TYPE_VRF: |
79 | break; |
80 | } |
81 | // While the list is exhaustive of the enum there can be additional |
82 | // entries added in NetworkManager that isn't listed here |
83 | return QNetworkInformation::TransportMedium::Unknown; |
84 | } |
85 | |
86 | bool isMeteredFromNMMetered(QNetworkManagerInterface::NMMetered metered) |
87 | { |
88 | switch (metered) { |
89 | case QNetworkManagerInterface::NM_METERED_YES: |
90 | case QNetworkManagerInterface::NM_METERED_GUESS_YES: |
91 | return true; |
92 | case QNetworkManagerInterface::NM_METERED_NO: |
93 | case QNetworkManagerInterface::NM_METERED_GUESS_NO: |
94 | case QNetworkManagerInterface::NM_METERED_UNKNOWN: |
95 | return false; |
96 | } |
97 | Q_UNREACHABLE_RETURN(false); |
98 | } |
99 | } // unnamed namespace |
100 | |
101 | static QString backendName() |
102 | { |
103 | return QString::fromUtf16(QNetworkInformationBackend::PluginNames |
104 | [QNetworkInformationBackend::PluginNamesLinuxIndex]); |
105 | } |
106 | |
107 | class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend |
108 | { |
109 | Q_OBJECT |
110 | public: |
111 | QNetworkManagerNetworkInformationBackend(); |
112 | ~QNetworkManagerNetworkInformationBackend() = default; |
113 | |
114 | QString name() const override { return backendName(); } |
115 | QNetworkInformation::Features featuresSupported() const override |
116 | { |
117 | if (!isValid()) |
118 | return {}; |
119 | return featuresSupportedStatic(); |
120 | } |
121 | |
122 | static QNetworkInformation::Features featuresSupportedStatic() |
123 | { |
124 | using Feature = QNetworkInformation::Feature; |
125 | return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal |
126 | | Feature::TransportMedium | Feature::Metered); |
127 | } |
128 | |
129 | bool isValid() const { return iface.isValid(); } |
130 | |
131 | private: |
132 | Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend) |
133 | |
134 | QNetworkManagerInterface iface; |
135 | }; |
136 | |
137 | class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory |
138 | { |
139 | Q_OBJECT |
140 | Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid) |
141 | Q_INTERFACES(QNetworkInformationBackendFactory) |
142 | public: |
143 | QNetworkManagerNetworkInformationBackendFactory() = default; |
144 | ~QNetworkManagerNetworkInformationBackendFactory() = default; |
145 | QString name() const override { return backendName(); } |
146 | QNetworkInformation::Features featuresSupported() const override |
147 | { |
148 | if (!QNetworkManagerInterfaceBase::networkManagerAvailable()) |
149 | return {}; |
150 | return QNetworkManagerNetworkInformationBackend::featuresSupportedStatic(); |
151 | } |
152 | |
153 | QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override |
154 | { |
155 | if ((requiredFeatures & featuresSupported()) != requiredFeatures) |
156 | return nullptr; |
157 | if (!QNetworkManagerInterfaceBase::networkManagerAvailable()) |
158 | return nullptr; |
159 | auto backend = new QNetworkManagerNetworkInformationBackend(); |
160 | if (!backend->isValid()) |
161 | delete std::exchange(obj&: backend, new_val: nullptr); |
162 | return backend; |
163 | } |
164 | private: |
165 | Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackendFactory) |
166 | }; |
167 | |
168 | QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend() |
169 | { |
170 | auto updateReachability = [this](QNetworkManagerInterface::NMState newState) { |
171 | setReachability(reachabilityFromNMState(state: newState)); |
172 | }; |
173 | updateReachability(iface.state()); |
174 | connect(sender: &iface, signal: &QNetworkManagerInterface::stateChanged, context: this, slot: std::move(updateReachability)); |
175 | |
176 | auto updateBehindCaptivePortal = [this](QNetworkManagerInterface::NMConnectivityState state) { |
177 | const bool behindPortal = (state == QNetworkManagerInterface::NM_CONNECTIVITY_PORTAL); |
178 | setBehindCaptivePortal(behindPortal); |
179 | }; |
180 | updateBehindCaptivePortal(iface.connectivityState()); |
181 | connect(sender: &iface, signal: &QNetworkManagerInterface::connectivityChanged, context: this, |
182 | slot: std::move(updateBehindCaptivePortal)); |
183 | |
184 | auto updateTransportMedium = [this](QNetworkManagerInterface::NMDeviceType newDevice) { |
185 | setTransportMedium(transportMediumFromDeviceType(type: newDevice)); |
186 | }; |
187 | updateTransportMedium(iface.deviceType()); |
188 | connect(sender: &iface, signal: &QNetworkManagerInterface::deviceTypeChanged, context: this, |
189 | slot: std::move(updateTransportMedium)); |
190 | |
191 | auto updateMetered = [this](QNetworkManagerInterface::NMMetered metered) { |
192 | setMetered(isMeteredFromNMMetered(metered)); |
193 | }; |
194 | updateMetered(iface.meteredState()); |
195 | connect(sender: &iface, signal: &QNetworkManagerInterface::meteredChanged, context: this, slot: std::move(updateMetered)); |
196 | } |
197 | |
198 | QT_END_NAMESPACE |
199 | |
200 | #include "qnetworkmanagernetworkinformationbackend.moc" |
201 | |