summaryrefslogtreecommitdiffstats
path: root/src/plugins/networkinformation
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/networkinformation')
-rw-r--r--src/plugins/networkinformation/CMakeLists.txt7
-rw-r--r--src/plugins/networkinformation/android/CMakeLists.txt9
-rw-r--r--src/plugins/networkinformation/android/jar/.gitignore6
-rw-r--r--src/plugins/networkinformation/android/jar/build.gradle51
-rw-r--r--src/plugins/networkinformation/android/jar/settings.gradle1
-rw-r--r--src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java116
-rw-r--r--src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp125
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp129
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h65
-rw-r--r--src/plugins/networkinformation/glib/CMakeLists.txt17
-rw-r--r--src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp137
-rw-r--r--src/plugins/networkinformation/networklistmanager/CMakeLists.txt14
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp268
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h79
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp288
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt4
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp184
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h60
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp224
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h123
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt3
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm99
22 files changed, 1266 insertions, 743 deletions
diff --git a/src/plugins/networkinformation/CMakeLists.txt b/src/plugins/networkinformation/CMakeLists.txt
index 142031c62a..04da816264 100644
--- a/src/plugins/networkinformation/CMakeLists.txt
+++ b/src/plugins/networkinformation/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(WIN32 AND QT_FEATURE_networklistmanager)
add_subdirectory(networklistmanager)
endif()
@@ -13,3 +16,7 @@ endif()
if(ANDROID)
add_subdirectory(android)
endif()
+
+if(QT_FEATURE_glib AND TARGET GLIB2::GOBJECT AND TARGET GLIB2::GIO)
+ add_subdirectory(glib)
+endif()
diff --git a/src/plugins/networkinformation/android/CMakeLists.txt b/src/plugins/networkinformation/android/CMakeLists.txt
index 0883ec74e2..07d9201bbb 100644
--- a/src/plugins/networkinformation/android/CMakeLists.txt
+++ b/src/plugins/networkinformation/android/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
set(java_sources
jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
@@ -9,8 +12,10 @@ qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
OUTPUT_DIR "${QT_BUILD_DIR}/jar"
)
+qt_path_join(destination ${INSTALL_DATADIR} "jar")
+
install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
- DESTINATION jar
+ DESTINATION ${destination}
COMPONENT Devel
)
@@ -24,8 +29,6 @@ qt_internal_add_plugin(QAndroidNetworkInformationPlugin
wrapper/androidconnectivitymanager.cpp wrapper/androidconnectivitymanager.h
LIBRARIES
Qt::NetworkPrivate
- DEFINES
- QT_USE_QSTRINGBUILDER
)
set_property(
diff --git a/src/plugins/networkinformation/android/jar/.gitignore b/src/plugins/networkinformation/android/jar/.gitignore
new file mode 100644
index 0000000000..364420a59a
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/.gitignore
@@ -0,0 +1,6 @@
+.gradle/
+build/
+gradle/
+gradlew
+gradlew.bat
+local.properties
diff --git a/src/plugins/networkinformation/android/jar/build.gradle b/src/plugins/networkinformation/android/jar/build.gradle
new file mode 100644
index 0000000000..68a9381ad2
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/build.gradle
@@ -0,0 +1,51 @@
+// This is mainly used to allow Android Studio to easily read this folder as an android project.
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.0.2'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+}
+
+repositories {
+ google()
+ mavenCentral()
+}
+
+android {
+ compileSdk 34
+
+ defaultConfig {
+ minSdkVersion 23
+ }
+
+ sourceSets {
+ main {
+ java.srcDir 'src/'
+ resources.srcDir 'libs/'
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res/']
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ android {
+ lintOptions {
+ abortOnError true
+ }
+ }
+}
diff --git a/src/plugins/networkinformation/android/jar/settings.gradle b/src/plugins/networkinformation/android/jar/settings.gradle
new file mode 100644
index 0000000000..cbb1ff361b
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "QtAndroidNetworkInformationBackend"
diff --git a/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
index 0e89d23ab4..6a56c506b0 100644
--- a/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
+++ b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
@@ -1,69 +1,47 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android.networkinformation;
-import android.content.BroadcastReceiver;
+import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.NetworkRequest;
import android.net.NetworkCapabilities;
import android.net.Network;
+import android.os.Build;
public class QtAndroidNetworkInformation {
private static final String LOG_TAG = "QtAndroidNetworkInformation";
- private static native void connectivityChanged();
- private static native void behindCaptivePortalChanged(boolean state);
+ private static native void networkConnectivityChanged(int connectivity);
+ private static native void genericInfoChanged(boolean captivePortal, boolean metered);
+ private static native void transportMediumChanged(int transportMedium);
private static QtNetworkInformationCallback m_callback = null;
private static final Object m_lock = new Object();
+ // Keep synchronized with AndroidConnectivity in androidconnectivitymanager.h
enum AndroidConnectivity {
Connected, Unknown, Disconnected
}
+ // Keep synchronized with AndroidTransport in androidconnectivitymanager.h
+ enum Transport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ }
+
private static class QtNetworkInformationCallback extends NetworkCallback {
public AndroidConnectivity previousState = null;
+ public Transport previousTransport = null;
QtNetworkInformationCallback() {
}
@@ -77,17 +55,55 @@ public class QtAndroidNetworkInformation {
s = AndroidConnectivity.Connected;
else
s = AndroidConnectivity.Unknown; // = we _may_ have Internet access
+
+ final Transport transport = getTransport(capabilities);
+ if (transport == Transport.Unknown) // If we don't have any transport media: override
+ s = AndroidConnectivity.Unknown;
+
setState(s);
+ setTransportMedium(transport);
final boolean captive
= capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
- behindCaptivePortalChanged(captive);
+ final boolean metered
+ = !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ genericInfoChanged(captive, metered);
+ }
+
+ private Transport getTransport(NetworkCapabilities capabilities)
+ {
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return Transport.WiFi;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return Transport.Cellular;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
+ return Transport.Bluetooth;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
+ return Transport.Ethernet;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
+ // Build.VERSION_CODES.O
+ return Transport.WiFiAware;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
+ // Build.VERSION_CODES.O_MR1
+ return Transport.LoWPAN;
+ }/* else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
+ // Build.VERSION_CODES.S
+ return Transport.Usb;
+ }*/ // @todo: Uncomment once we can use SDK 31
+ return Transport.Unknown;
}
private void setState(AndroidConnectivity s) {
if (previousState != s) {
previousState = s;
- connectivityChanged();
+ networkConnectivityChanged(s.ordinal());
+ }
+ }
+
+ private void setTransportMedium(Transport t) {
+ if (previousTransport != t) {
+ previousTransport = t;
+ transportMediumChanged(t.ordinal());
}
}
@@ -106,16 +122,24 @@ public class QtAndroidNetworkInformation {
return AndroidConnectivity.Unknown;
}
+ @SuppressLint("MissingPermission")
public static void registerReceiver(final Context context) {
synchronized (m_lock) {
if (m_callback == null) {
ConnectivityManager manager = getConnectivityManager(context);
m_callback = new QtNetworkInformationCallback();
NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+ builder = builder.clearCapabilities();
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND);
+ }
NetworkRequest request = builder.build();
+
+ // Can't use registerDefaultNetworkCallback because it doesn't let us know when
+ // the network disconnects!
manager.registerNetworkCallback(request, m_callback);
}
}
diff --git a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
index 9eef471989..44e4d447d2 100644
--- a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qnetworkinformation_p.h>
@@ -47,7 +11,10 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcNetInfoAndroid)
Q_LOGGING_CATEGORY(lcNetInfoAndroid, "qt.network.info.android");
-static const QString backendName = QStringLiteral("android");
+static QString backendName() {
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesAndroidIndex]);
+}
class QAndroidNetworkInformationBackend : public QNetworkInformationBackend
{
@@ -56,7 +23,7 @@ public:
QAndroidNetworkInformationBackend();
~QAndroidNetworkInformationBackend() { m_valid = false; }
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return featuresSupportedStatic();
@@ -65,13 +32,18 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
using Feature = QNetworkInformation::Feature;
- return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium);
}
bool isValid() { return m_valid; }
private:
Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackend);
+
+ void updateConnectivity(AndroidConnectivityManager::AndroidConnectivity connectivity);
+ void updateTransportMedium(AndroidConnectivityManager::AndroidTransport transport);
+
bool m_valid = false;
};
@@ -83,7 +55,7 @@ class QAndroidNetworkInformationBackendFactory : public QNetworkInformationBacke
public:
QAndroidNetworkInformationBackendFactory() = default;
~QAndroidNetworkInformationBackendFactory() = default;
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return QAndroidNetworkInformationBackend::featuresSupportedStatic();
@@ -111,24 +83,63 @@ QAndroidNetworkInformationBackend::QAndroidNetworkInformationBackend()
return;
m_valid = true;
setReachability(QNetworkInformation::Reachability::Unknown);
- connect(conman, &AndroidConnectivityManager::connectivityChanged, this, [this, conman]() {
- static const auto mapState = [](AndroidConnectivityManager::AndroidConnectivity state) {
- switch (state) {
- case AndroidConnectivityManager::AndroidConnectivity::Connected:
- return QNetworkInformation::Reachability::Online;
- case AndroidConnectivityManager::AndroidConnectivity::Disconnected:
- return QNetworkInformation::Reachability::Disconnected;
- case AndroidConnectivityManager::AndroidConnectivity::Unknown:
- default:
- return QNetworkInformation::Reachability::Unknown;
- }
- };
-
- setReachability(mapState(conman->networkConnectivity()));
- });
+ connect(conman, &AndroidConnectivityManager::connectivityChanged, this,
+ &QAndroidNetworkInformationBackend::updateConnectivity);
connect(conman, &AndroidConnectivityManager::captivePortalChanged, this,
&QAndroidNetworkInformationBackend::setBehindCaptivePortal);
+
+ connect(conman, &AndroidConnectivityManager::transportMediumChanged, this,
+ &QAndroidNetworkInformationBackend::updateTransportMedium);
+
+ connect(conman, &AndroidConnectivityManager::meteredChanged, this,
+ &QAndroidNetworkInformationBackend::setMetered);
+}
+
+void QAndroidNetworkInformationBackend::updateConnectivity(
+ AndroidConnectivityManager::AndroidConnectivity connectivity)
+{
+ using AndroidConnectivity = AndroidConnectivityManager::AndroidConnectivity;
+ static const auto mapState = [](AndroidConnectivity state) {
+ switch (state) {
+ case AndroidConnectivity::Connected:
+ return QNetworkInformation::Reachability::Online;
+ case AndroidConnectivity::Disconnected:
+ return QNetworkInformation::Reachability::Disconnected;
+ case AndroidConnectivity::Unknown:
+ default:
+ return QNetworkInformation::Reachability::Unknown;
+ }
+ };
+
+ setReachability(mapState(connectivity));
+}
+
+void QAndroidNetworkInformationBackend::updateTransportMedium(
+ AndroidConnectivityManager::AndroidTransport transport)
+{
+ using AndroidTransport = AndroidConnectivityManager::AndroidTransport;
+ using TransportMedium = QNetworkInformation::TransportMedium;
+ static const auto mapTransport = [](AndroidTransport state) -> TransportMedium {
+ switch (state) {
+ case AndroidTransport::Cellular:
+ return TransportMedium::Cellular;
+ case AndroidTransport::WiFi:
+ return TransportMedium::WiFi;
+ case AndroidTransport::Bluetooth:
+ return TransportMedium::Bluetooth;
+ case AndroidTransport::Ethernet:
+ return TransportMedium::Ethernet;
+ // These are not covered yet (but may be in the future)
+ case AndroidTransport::Usb:
+ case AndroidTransport::LoWPAN:
+ case AndroidTransport::WiFiAware:
+ case AndroidTransport::Unknown:
+ return TransportMedium::Unknown;
+ }
+ };
+
+ setTransportMedium(mapTransport(transport));
}
QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
index e88fe7d955..3c9f952968 100644
--- a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "androidconnectivitymanager.h"
@@ -56,34 +20,43 @@ Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
static const char networkInformationClass[] =
"org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation";
-static void networkConnectivityChanged(JNIEnv *env, jobject obj)
+static void networkConnectivityChanged(JNIEnv *env, jobject obj, jint enumValue)
{
Q_UNUSED(env);
Q_UNUSED(obj);
- Q_EMIT androidConnManagerInstance->connManager->connectivityChanged();
+ const auto connectivity =
+ static_cast<AndroidConnectivityManager::AndroidConnectivity>(enumValue);
+ Q_EMIT androidConnManagerInstance->connManager->connectivityChanged(connectivity);
}
+Q_DECLARE_JNI_NATIVE_METHOD(networkConnectivityChanged)
-static void behindCaptivePortalChanged(JNIEnv *env, jobject obj, jboolean state)
+static void genericInfoChanged(JNIEnv *env, jobject obj, jboolean captivePortal, jboolean metered)
{
Q_UNUSED(env);
Q_UNUSED(obj);
- Q_EMIT androidConnManagerInstance->connManager->captivePortalChanged(state);
+ Q_EMIT androidConnManagerInstance->connManager->captivePortalChanged(captivePortal);
+ Q_EMIT androidConnManagerInstance->connManager->meteredChanged(metered);
}
+Q_DECLARE_JNI_NATIVE_METHOD(genericInfoChanged)
+
+static void transportMediumChanged(JNIEnv *env, jobject obj, jint enumValue)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ const auto transport = static_cast<AndroidConnectivityManager::AndroidTransport>(enumValue);
+ emit androidConnManagerInstance->connManager->transportMediumChanged(transport);
+}
+Q_DECLARE_JNI_NATIVE_METHOD(transportMediumChanged)
+
+Q_DECLARE_JNI_CLASS(ConnectivityManager, "android/net/ConnectivityManager")
AndroidConnectivityManager::AndroidConnectivityManager()
{
if (!registerNatives())
return;
- m_connectivityManager = QJniObject::callStaticObjectMethod(
- networkInformationClass, "getConnectivityManager",
- "(Landroid/content/Context;)Landroid/net/ConnectivityManager;",
- QAndroidApplication::context());
- if (!m_connectivityManager.isValid())
- return;
-
QJniObject::callStaticMethod<void>(networkInformationClass, "registerReceiver",
- "(Landroid/content/Context;)V", QAndroidApplication::context());
+ QAndroidApplication::context());
}
AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
@@ -95,52 +68,30 @@ AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
: nullptr;
}
-AndroidConnectivityManager::~AndroidConnectivityManager()
+bool AndroidConnectivityManager::isValid() const
{
- QJniObject::callStaticMethod<void>(networkInformationClass, "unregisterReceiver",
- "(Landroid/content/Context;)V", QAndroidApplication::context());
+ return registerNatives();
}
-AndroidConnectivityManager::AndroidConnectivity AndroidConnectivityManager::networkConnectivity()
+AndroidConnectivityManager::~AndroidConnectivityManager()
{
- QJniEnvironment env;
- QJniObject networkReceiver(networkInformationClass);
- jclass clazz = env->GetObjectClass(networkReceiver.object());
- static const QByteArray functionSignature =
- QByteArray(QByteArray("()L") + networkInformationClass + "$AndroidConnectivity;");
- QJniObject enumObject =
- QJniObject::callStaticObjectMethod(clazz, "state", functionSignature.data());
- if (!enumObject.isValid())
- return AndroidConnectivityManager::AndroidConnectivity::Unknown;
-
- QJniObject enumName = enumObject.callObjectMethod<jstring>("name");
- if (!enumName.isValid())
- return AndroidConnectivityManager::AndroidConnectivity::Unknown;
-
- QString name = enumName.toString();
- if (name == u"Connected")
- return AndroidConnectivity::Connected;
- if (name == u"Disconnected")
- return AndroidConnectivity::Disconnected;
- return AndroidConnectivity::Unknown;
+ QJniObject::callStaticMethod<void>(networkInformationClass, "unregisterReceiver",
+ QAndroidApplication::context());
}
-bool AndroidConnectivityManager::registerNatives()
+bool AndroidConnectivityManager::registerNatives() const
{
- QJniEnvironment env;
- QJniObject networkReceiver(networkInformationClass);
- if (!networkReceiver.isValid())
- return false;
-
- jclass clazz = env->GetObjectClass(networkReceiver.object());
- static JNINativeMethod methods[] = {
- { "connectivityChanged", "()V", reinterpret_cast<void *>(networkConnectivityChanged) },
- { "behindCaptivePortalChanged", "(Z)V",
- reinterpret_cast<void *>(behindCaptivePortalChanged) }
- };
- const bool ret = (env->RegisterNatives(clazz, methods, std::size(methods)) == JNI_OK);
- env->DeleteLocalRef(clazz);
- return ret;
+ static const bool registered = []() {
+ QJniEnvironment env;
+ return env.registerNativeMethods(networkInformationClass, {
+ Q_JNI_NATIVE_METHOD(networkConnectivityChanged),
+ Q_JNI_NATIVE_METHOD(genericInfoChanged),
+ Q_JNI_NATIVE_METHOD(transportMediumChanged),
+ });
+ }();
+ return registered;
}
QT_END_NAMESPACE
+
+#include "moc_androidconnectivitymanager.cpp"
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
index 14f5aa9b57..d15faf0e8e 100644
--- a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDCONNECTIVITYMANAGER_H
#define ANDROIDCONNECTIVITYMANAGER_H
@@ -49,23 +13,38 @@ class AndroidConnectivityManager : public QObject
{
Q_OBJECT
public:
+ // Keep synchronized with AndroidConnectivity in QtAndroidNetworkInformation.java
enum class AndroidConnectivity { Connected, Unknown, Disconnected };
Q_ENUM(AndroidConnectivity);
+
+ // Keep synchronized with Transport in QtAndroidNetworkInformation.java
+ enum class AndroidTransport {
+ Unknown,
+ Bluetooth,
+ Cellular,
+ Ethernet,
+ LoWPAN,
+ Usb,
+ WiFi,
+ WiFiAware,
+ };
+ Q_ENUM(AndroidTransport);
+
static AndroidConnectivityManager *getInstance();
~AndroidConnectivityManager();
- AndroidConnectivity networkConnectivity();
- inline bool isValid() const { return m_connectivityManager.isValid(); }
+ inline bool isValid() const;
Q_SIGNALS:
- void connectivityChanged();
+ void connectivityChanged(AndroidConnectivity connectivity);
void captivePortalChanged(bool state);
+ void transportMediumChanged(AndroidTransport transport);
+ void meteredChanged(bool state);
private:
friend struct AndroidConnectivityManagerInstance;
AndroidConnectivityManager();
- bool registerNatives();
- QJniObject m_connectivityManager;
+ bool registerNatives() const;
Q_DISABLE_COPY_MOVE(AndroidConnectivityManager);
};
diff --git a/src/plugins/networkinformation/glib/CMakeLists.txt b/src/plugins/networkinformation/glib/CMakeLists.txt
new file mode 100644
index 0000000000..019f4f1358
--- /dev/null
+++ b/src/plugins/networkinformation/glib/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_plugin(QGlibNetworkInformationPlugin
+ OUTPUT_NAME qglib
+ CLASS_NAME QGlibNetworkInformationBackendFactory
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF LINUX
+ SOURCES
+ qglibnetworkinformationbackend.cpp
+ LIBRARIES
+ Qt::NetworkPrivate
+ GLIB2::GOBJECT
+ GLIB2::GIO
+ DEFINES
+ QT_NO_SIGNALS_SLOTS_KEYWORDS
+)
diff --git a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
new file mode 100644
index 0000000000..0b45eb9ce3
--- /dev/null
+++ b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2021 Ilya Fedin <fedin-ilja2010@ya.ru>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <gio/gio.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoGlib)
+Q_LOGGING_CATEGORY(lcNetInfoGlib, "qt.network.info.glib");
+
+namespace {
+QNetworkInformation::Reachability reachabilityFromGNetworkConnectivity(GNetworkConnectivity connectivity)
+{
+ switch (connectivity) {
+ case G_NETWORK_CONNECTIVITY_LOCAL:
+ return QNetworkInformation::Reachability::Disconnected;
+ case G_NETWORK_CONNECTIVITY_LIMITED:
+ case G_NETWORK_CONNECTIVITY_PORTAL:
+ return QNetworkInformation::Reachability::Site;
+ case G_NETWORK_CONNECTIVITY_FULL:
+ return QNetworkInformation::Reachability::Online;
+ }
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+static QString backendName = QStringLiteral("glib");
+
+class QGlibNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QGlibNetworkInformationBackend();
+ ~QGlibNetworkInformationBackend();
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::Metered);
+ }
+
+ bool isValid() const;
+
+private:
+ Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackend)
+
+ static void updateConnectivity(QGlibNetworkInformationBackend *backend);
+ static void updateMetered(QGlibNetworkInformationBackend *backend);
+
+ GNetworkMonitor *networkMonitor = nullptr;
+ gulong connectivityHandlerId = 0;
+ gulong meteredHandlerId = 0;
+};
+
+class QGlibNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QGlibNetworkInformationBackendFactory() = default;
+ ~QGlibNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QGlibNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QGlibNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+private:
+ Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackendFactory)
+};
+
+QGlibNetworkInformationBackend::QGlibNetworkInformationBackend()
+: networkMonitor(g_network_monitor_get_default())
+{
+ updateConnectivity(this);
+ updateMetered(this);
+
+ connectivityHandlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity",
+ G_CALLBACK(updateConnectivity), this);
+
+ meteredHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-metered",
+ G_CALLBACK(updateMetered), this);
+}
+
+QGlibNetworkInformationBackend::~QGlibNetworkInformationBackend()
+{
+ g_signal_handler_disconnect(networkMonitor, meteredHandlerId);
+ g_signal_handler_disconnect(networkMonitor, connectivityHandlerId);
+}
+
+bool QGlibNetworkInformationBackend::isValid() const
+{
+ return QLatin1StringView(G_OBJECT_TYPE_NAME(networkMonitor)) != "GNetworkMonitorBase"_L1;
+}
+
+void QGlibNetworkInformationBackend::updateConnectivity(QGlibNetworkInformationBackend *backend)
+{
+ const auto connectivityState = g_network_monitor_get_connectivity(backend->networkMonitor);
+ const bool behindPortal = (connectivityState == G_NETWORK_CONNECTIVITY_PORTAL);
+ backend->setReachability(reachabilityFromGNetworkConnectivity(connectivityState));
+ backend->setBehindCaptivePortal(behindPortal);
+}
+
+void QGlibNetworkInformationBackend::updateMetered(QGlibNetworkInformationBackend *backend)
+{
+ backend->setMetered(g_network_monitor_get_network_metered(backend->networkMonitor));
+}
+
+QT_END_NAMESPACE
+
+#include "qglibnetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
index 170bce0f7b..acd3754f4e 100644
--- a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
@@ -1,13 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_internal_add_plugin(QNLMNIPlugin
OUTPUT_NAME qnetworklistmanager
CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory
PLUGIN_TYPE networkinformation
DEFAULT_IF WIN32 AND QT_FEATURE_networklistmanager
- SOURCES qnetworklistmanagernetworkinformationbackend.cpp
+ EXCEPTIONS
+ SOURCES
+ qnetworklistmanagernetworkinformationbackend.cpp
+ qnetworklistmanagerevents.h qnetworklistmanagerevents.cpp
LIBRARIES
Qt::NetworkPrivate
)
+qt_internal_extend_target(QNLMNIPlugin CONDITION WIN32
+ LIBRARIES
+ runtimeobject
+ oleaut32
+)
+
# Don't repeat the target name in AUTOGEN_BUILD_DIR to work around issues with overlong paths.
set_property(TARGET QNLMNIPlugin PROPERTY
AUTOGEN_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/autogen")
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
new file mode 100644
index 0000000000..caa5046751
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
@@ -0,0 +1,268 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworklistmanagerevents.h"
+#include <QtCore/private/qsystemerror_p.h>
+
+#include <QtCore/qpointer.h>
+
+#include <mutex>
+
+#if QT_CONFIG(cpp_winrt)
+#include <QtCore/private/qt_winrtbase_p.h>
+
+#include <winrt/Windows.Networking.Connectivity.h>
+#endif // QT_CONFIG(cpp_winrt)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+template<typename T>
+bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
+{
+ if (riid == __uuidof(T)) {
+ *ppvObject = static_cast<T *>(from);
+ from->AddRef();
+ return true;
+ }
+ return false;
+}
+}
+
+QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr)
+{
+ auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
+ IID_INetworkListManager, &networkListManager);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:"
+ << QSystemError::windowsComString(hr);
+ return;
+ }
+
+ ComPtr<IConnectionPointContainer> connectionPointContainer;
+ hr = networkListManager.As(&connectionPointContainer);
+ if (SUCCEEDED(hr)) {
+ hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
+ &connectionPoint);
+ }
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:"
+ << QSystemError::windowsComString(hr);
+ }
+}
+
+QNetworkListManagerEvents::~QNetworkListManagerEvents()
+{
+ Q_ASSERT(ref == 0);
+}
+
+HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject)
+ return E_INVALIDARG;
+
+ return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
+ || QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
+ ? S_OK
+ : E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE
+QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
+{
+ // This function is run on a different thread than 'monitor' is created on, so we need to run
+ // it on that thread
+ emit connectivityChanged(newConnectivity);
+ return S_OK;
+}
+
+bool QNetworkListManagerEvents::start()
+{
+ if (!connectionPoint) {
+ qCWarning(lcNetInfoNLM, "Initialization failed, can't start!");
+ return false;
+ }
+ auto hr = connectionPoint->Advise(this, &cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:"
+ << QSystemError::windowsComString(hr);
+ return false;
+ }
+
+ // Update connectivity since it might have changed since this class was constructed
+ NLM_CONNECTIVITY connectivity;
+ hr = networkListManager->GetConnectivity(&connectivity);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Could not get connectivity:"
+ << QSystemError::windowsComString(hr);
+ } else {
+ emit connectivityChanged(connectivity);
+ }
+
+#if QT_CONFIG(cpp_winrt)
+ using namespace winrt::Windows::Networking::Connectivity;
+ using winrt::Windows::Foundation::IInspectable;
+ try {
+ // Register for changes in the network and store a token to unregister later:
+ token = NetworkInformation::NetworkStatusChanged(
+ [owner = QPointer(this)](const IInspectable sender) {
+ Q_UNUSED(sender);
+ if (owner) {
+ std::scoped_lock locker(owner->winrtLock);
+ if (owner->token)
+ owner->emitWinRTUpdates();
+ }
+ });
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to register network status changed callback:"
+ << QSystemError::windowsComString(ex.code());
+ }
+
+ // Emit initial state
+ emitWinRTUpdates();
+#endif
+
+ return true;
+}
+
+void QNetworkListManagerEvents::stop()
+{
+ Q_ASSERT(connectionPoint);
+ auto hr = connectionPoint->Unadvise(cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:"
+ << QSystemError::windowsComString(hr);
+ } else {
+ cookie = 0;
+ }
+ // Even if we fail we should still try to unregister from winrt events:
+
+#if QT_CONFIG(cpp_winrt)
+ // Try to synchronize unregistering with potentially in-progress callbacks
+ std::scoped_lock locker(winrtLock);
+ if (token) {
+ using namespace winrt::Windows::Networking::Connectivity;
+ // Pass the token we stored earlier to unregister:
+ NetworkInformation::NetworkStatusChanged(token);
+ token = {};
+ }
+#endif
+}
+
+bool QNetworkListManagerEvents::checkBehindCaptivePortal()
+{
+ if (!networkListManager)
+ return false;
+ ComPtr<IEnumNetworks> networks;
+ HRESULT hr =
+ networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf());
+ if (FAILED(hr) || networks == nullptr)
+ return false;
+
+ // @note: This checks all connected networks, but that might not be necessary
+ ComPtr<INetwork> network;
+ hr = networks->Next(1, network.GetAddressOf(), nullptr);
+ while (SUCCEEDED(hr) && network != nullptr) {
+ ComPtr<IPropertyBag> propertyBag;
+ hr = network.As(&propertyBag);
+ if (SUCCEEDED(hr) && propertyBag != nullptr) {
+ VARIANT variant;
+ VariantInit(&variant);
+ const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
+
+ const wchar_t *versions[] = { L"NA_InternetConnectivityV6", L"NA_InternetConnectivityV4" };
+ for (const auto version : versions) {
+ hr = propertyBag->Read(version, &variant, nullptr);
+ if (SUCCEEDED(hr)
+ && (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
+ == NLM_INTERNET_CONNECTIVITY_WEBHIJACK) {
+ return true;
+ }
+ }
+ }
+
+ hr = networks->Next(1, network.GetAddressOf(), nullptr);
+ }
+
+ return false;
+}
+
+#if QT_CONFIG(cpp_winrt)
+namespace {
+using namespace winrt::Windows::Networking::Connectivity;
+// NB: this isn't part of "network list manager", but sadly NLM doesn't have an
+// equivalent API (at least not that I've found...)!
+[[nodiscard]]
+QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile &profile)
+{
+ if (profile.IsWwanConnectionProfile())
+ return QNetworkInformation::TransportMedium::Cellular;
+ if (profile.IsWlanConnectionProfile())
+ return QNetworkInformation::TransportMedium::WiFi;
+
+ NetworkAdapter adapter(nullptr);
+ try {
+ adapter = profile.NetworkAdapter();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain network adapter:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we will return Unknown anyway
+ }
+ if (adapter == nullptr)
+ return QNetworkInformation::TransportMedium::Unknown;
+
+ // Note: Bluetooth is given an iana iftype of 6, which is the same as Ethernet.
+ // In Windows itself there is clearly a distinction between a Bluetooth PAN
+ // and an Ethernet LAN, though it is not clear how they make this distinction.
+ auto fromIanaId = [](quint32 ianaId) -> QNetworkInformation::TransportMedium {
+ // https://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib
+ switch (ianaId) {
+ case 6:
+ return QNetworkInformation::TransportMedium::Ethernet;
+ case 71: // Should be handled before entering this lambda
+ return QNetworkInformation::TransportMedium::WiFi;
+ }
+ return QNetworkInformation::TransportMedium::Unknown;
+ };
+
+ return fromIanaId(adapter.IanaInterfaceType());
+}
+
+[[nodiscard]] bool getMetered(const ConnectionProfile &profile)
+{
+ ConnectionCost cost(nullptr);
+ try {
+ cost = profile.GetConnectionCost();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection cost:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we return false if we get an empty object back anyway
+ }
+ if (cost == nullptr)
+ return false;
+ NetworkCostType type = cost.NetworkCostType();
+ return type == NetworkCostType::Fixed || type == NetworkCostType::Variable;
+}
+} // unnamed namespace
+
+void QNetworkListManagerEvents::emitWinRTUpdates()
+{
+ using namespace winrt::Windows::Networking::Connectivity;
+ ConnectionProfile profile = nullptr;
+ try {
+ profile = NetworkInformation::GetInternetConnectionProfile();
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection profile:"
+ << QSystemError::windowsComString(ex.code());
+ // pass, we would just return early if we get an empty object back anyway
+ }
+ if (profile == nullptr)
+ return;
+ emit transportMediumChanged(getTransportMedium(profile));
+ emit isMeteredChanged(getMetered(profile));
+}
+#endif // QT_CONFIG(cpp_winrt)
+
+QT_END_NAMESPACE
+
+#include "moc_qnetworklistmanagerevents.cpp"
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
new file mode 100644
index 0000000000..d91cd8a4cc
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h
@@ -0,0 +1,79 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKLISTMANAGEREVENTS_H
+#define QNETWORKLISTMANAGEREVENTS_H
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qnetworkinformation.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmutex.h>
+
+#include <objbase.h>
+#include <ocidl.h>
+#include <netlistmgr.h>
+#include <wrl/client.h>
+#include <wrl/wrappers/corewrappers.h>
+
+#if QT_CONFIG(cpp_winrt)
+#include <QtCore/private/qt_winrtbase_p.h>
+#endif
+
+using namespace Microsoft::WRL;
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
+
+class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents
+{
+ Q_OBJECT
+public:
+ QNetworkListManagerEvents();
+ virtual ~QNetworkListManagerEvents();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
+
+ ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
+ ULONG STDMETHODCALLTYPE Release() override
+ {
+ if (--ref == 0) {
+ delete this;
+ return 0;
+ }
+ return ref;
+ }
+
+ HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
+
+ [[nodiscard]] bool start();
+ void stop();
+
+ [[nodiscard]] bool checkBehindCaptivePortal();
+
+signals:
+ void connectivityChanged(NLM_CONNECTIVITY);
+ void transportMediumChanged(QNetworkInformation::TransportMedium);
+ void isMeteredChanged(bool);
+
+private:
+ ComPtr<INetworkListManager> networkListManager = nullptr;
+ ComPtr<IConnectionPoint> connectionPoint = nullptr;
+
+#if QT_CONFIG(cpp_winrt)
+ void emitWinRTUpdates();
+
+ winrt::event_token token;
+ QMutex winrtLock;
+#endif
+
+ QAtomicInteger<ULONG> ref = 0;
+ DWORD cookie = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKLISTMANAGEREVENTS_H
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
index d37f83832b..766648486e 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
@@ -1,80 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qnetworkinformation_p.h>
+#include "qnetworklistmanagerevents.h"
+
#include <QtCore/qglobal.h>
#include <QtCore/private/qobject_p.h>
#include <QtCore/qscopeguard.h>
-#include <objbase.h>
-#include <netlistmgr.h>
-#include <wrl/client.h>
-#include <wrl/wrappers/corewrappers.h>
-#include <comdef.h>
-#include <iphlpapi.h>
-using namespace Microsoft::WRL;
+#include <QtCore/private/qfunctions_win_p.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
-Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager");
-
-static const QString backendName = QStringLiteral("networklistmanager");
-namespace {
-QString errorStringFromHResult(HRESULT hr)
-{
- _com_error error(hr);
- return QString::fromWCharArray(error.ErrorMessage());
-}
+// Declared in qnetworklistmanagerevents.h
+Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager");
-template<typename T>
-bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
+static QString backendName()
{
- if (riid == __uuidof(T)) {
- *ppvObject = static_cast<T *>(from);
- from->AddRef();
- return true;
- }
- return false;
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesWindowsIndex]);
}
+namespace {
bool testCONNECTIVITY(NLM_CONNECTIVITY connectivity, NLM_CONNECTIVITY flag)
{
return (connectivity & flag) == flag;
@@ -105,7 +53,6 @@ QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIV
}
}
-class QNetworkListManagerEvents;
class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend
{
Q_OBJECT
@@ -113,7 +60,7 @@ public:
QNetworkListManagerNetworkInformationBackend();
~QNetworkListManagerNetworkInformationBackend();
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return featuresSupportedStatic();
@@ -122,25 +69,29 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
- | QNetworkInformation::Feature::CaptivePortal);
+ | QNetworkInformation::Feature::CaptivePortal
+#if QT_CONFIG(cpp_winrt)
+ | QNetworkInformation::Feature::TransportMedium
+ | QNetworkInformation::Feature::Metered
+#endif
+ );
}
[[nodiscard]] bool start();
void stop();
private:
- friend class QNetworkListManagerEvents;
-
bool event(QEvent *event) override;
void setConnectivity(NLM_CONNECTIVITY newConnectivity);
void checkCaptivePortal();
+ QComHelper comHelper;
+
ComPtr<QNetworkListManagerEvents> managerEvents;
NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED;
bool monitoring = false;
- bool comInitFailed = false;
};
class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
@@ -151,7 +102,7 @@ class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInfor
public:
QNetworkListManagerNetworkInformationBackendFactory() = default;
~QNetworkListManagerNetworkInformationBackendFactory() = default;
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return QNetworkListManagerNetworkInformationBackend::featuresSupportedStatic();
@@ -172,182 +123,24 @@ public:
}
};
-class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents
-{
- Q_OBJECT
-public:
- QNetworkListManagerEvents();
- virtual ~QNetworkListManagerEvents();
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
-
- ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
- ULONG STDMETHODCALLTYPE Release() override
- {
- if (--ref == 0) {
- delete this;
- return 0;
- }
- return ref;
- }
-
- HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
-
- [[nodiscard]] bool start();
- bool stop();
-
- [[nodiscard]] bool checkBehindCaptivePortal();
-
-signals:
- void connectivityChanged(NLM_CONNECTIVITY);
-
-private:
- ComPtr<INetworkListManager> networkListManager = nullptr;
- ComPtr<IConnectionPoint> connectionPoint = nullptr;
-
- QAtomicInteger<ULONG> ref = 0;
- DWORD cookie = 0;
-};
-
-QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr)
-{
- auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
- IID_INetworkListManager, &networkListManager);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:"
- << errorStringFromHResult(hr);
- return;
- }
-
- ComPtr<IConnectionPointContainer> connectionPointContainer;
- hr = networkListManager.As(&connectionPointContainer);
- if (SUCCEEDED(hr)) {
- hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
- &connectionPoint);
- }
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:"
- << errorStringFromHResult(hr);
- }
-}
-
-QNetworkListManagerEvents::~QNetworkListManagerEvents()
-{
- Q_ASSERT(ref == 0);
-}
-
-HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
-{
- if (!ppvObject)
- return E_INVALIDARG;
-
- return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
- || QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
- ? S_OK
- : E_NOINTERFACE;
-}
-
-HRESULT STDMETHODCALLTYPE
-QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
-{
- // This function is run on a different thread than 'monitor' is created on, so we need to run
- // it on that thread
- connectivityChanged(newConnectivity);
- return S_OK;
-}
-
-bool QNetworkListManagerEvents::start()
-{
- if (!connectionPoint) {
- qCWarning(lcNetInfoNLM, "Initialization failed, can't start!");
- return false;
- }
- auto hr = connectionPoint->Advise(this, &cookie);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:"
- << errorStringFromHResult(hr);
- return false;
- }
-
- // Update connectivity since it might have changed since this class was constructed
- NLM_CONNECTIVITY connectivity;
- hr = networkListManager->GetConnectivity(&connectivity);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Could not get connectivity:" << errorStringFromHResult(hr);
- } else {
- emit connectivityChanged(connectivity);
- }
- return true;
-}
-
-bool QNetworkListManagerEvents::stop()
-{
- Q_ASSERT(connectionPoint);
- auto hr = connectionPoint->Unadvise(cookie);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:"
- << errorStringFromHResult(hr);
- return false;
- }
- cookie = 0;
- return true;
-}
-
-bool QNetworkListManagerEvents::checkBehindCaptivePortal()
-{
- if (!networkListManager)
- return false;
- ComPtr<IEnumNetworks> networks;
- HRESULT hr =
- networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf());
- if (FAILED(hr) || networks == nullptr)
- return false;
-
- // @note: This checks all connected networks, but that might not be necessary
- ComPtr<INetwork> network;
- hr = networks->Next(1, network.GetAddressOf(), nullptr);
- while (SUCCEEDED(hr) && network != nullptr) {
- ComPtr<IPropertyBag> propertyBag;
- hr = network.As(&propertyBag);
- if (SUCCEEDED(hr) && propertyBag != nullptr) {
- VARIANT variant;
- VariantInit(&variant);
- const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
-
- const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 };
- for (const auto version : versions) {
- hr = propertyBag->Read(version, &variant, nullptr);
- if (SUCCEEDED(hr)
- && (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
- == NLM_INTERNET_CONNECTIVITY_WEBHIJACK) {
- return true;
- }
- }
- }
-
- hr = networks->Next(1, network.GetAddressOf(), nullptr);
- }
-
- return false;
-}
-
QNetworkListManagerNetworkInformationBackend::QNetworkListManagerNetworkInformationBackend()
{
- auto hr = CoInitialize(nullptr);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Failed to initialize COM:" << errorStringFromHResult(hr);
- comInitFailed = true;
+ if (!comHelper.isValid())
return;
- }
+
managerEvents = new QNetworkListManagerEvents();
connect(managerEvents.Get(), &QNetworkListManagerEvents::connectivityChanged, this,
&QNetworkListManagerNetworkInformationBackend::setConnectivity);
+
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::transportMediumChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setTransportMedium);
+
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::isMeteredChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setMetered);
}
QNetworkListManagerNetworkInformationBackend::~QNetworkListManagerNetworkInformationBackend()
{
- if (comInitFailed)
- return;
stop();
}
@@ -370,11 +163,8 @@ void QNetworkListManagerNetworkInformationBackend::checkCaptivePortal()
bool QNetworkListManagerNetworkInformationBackend::event(QEvent *event)
{
- if (event->type() == QEvent::ThreadChange && monitoring) {
- stop();
- QMetaObject::invokeMethod(this, &QNetworkListManagerNetworkInformationBackend::start,
- Qt::QueuedConnection);
- }
+ if (event->type() == QEvent::ThreadChange)
+ qFatal("Moving QNetworkListManagerNetworkInformationBackend to different thread is not supported");
return QObject::event(event);
}
@@ -383,15 +173,9 @@ bool QNetworkListManagerNetworkInformationBackend::start()
{
Q_ASSERT(!monitoring);
- if (comInitFailed) {
- auto hr = CoInitialize(nullptr);
- if (FAILED(hr)) {
- qCWarning(lcNetInfoNLM) << "Failed to initialize COM:" << errorStringFromHResult(hr);
- comInitFailed = true;
- return false;
- }
- comInitFailed = false;
- }
+ if (!comHelper.isValid())
+ return false;
+
if (!managerEvents)
managerEvents = new QNetworkListManagerEvents();
@@ -404,14 +188,10 @@ void QNetworkListManagerNetworkInformationBackend::stop()
{
if (monitoring) {
Q_ASSERT(managerEvents);
- // Can return false but realistically shouldn't since that would break everything:
managerEvents->stop();
monitoring = false;
managerEvents.Reset();
}
-
- CoUninitialize();
- comInitFailed = true; // we check this value in start() to see if we need to re-initialize
}
QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
index 5fc69f2d55..9d76dbe7b4 100644
--- a/src/plugins/networkinformation/networkmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -1,9 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
OUTPUT_NAME qnetworkmanager
CLASS_NAME QNetworkManagerNetworkInformationBackendFactory
PLUGIN_TYPE networkinformation
DEFAULT_IF LINUX
SOURCES
+ qnetworkmanagernetworkinformationbackend.h
qnetworkmanagernetworkinformationbackend.cpp
qnetworkmanagerservice.h
qnetworkmanagerservice.cpp
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
index bfb04ae4a6..f583d1dcf6 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
@@ -1,45 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtNetwork/private/qnetworkinformation_p.h>
-
-#include "qnetworkmanagerservice.h"
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworkmanagernetworkinformationbackend.h"
#include <QtCore/qglobal.h>
#include <QtCore/private/qobject_p.h>
@@ -70,38 +32,80 @@ QNetworkInformation::Reachability reachabilityFromNMState(QNetworkManagerInterfa
}
return QNetworkInformation::Reachability::Unknown;
}
-}
-static QString backendName = QStringLiteral("networkmanager");
-
-class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+QNetworkInformation::TransportMedium
+transportMediumFromDeviceType(QNetworkManagerInterface::NMDeviceType type)
{
- Q_OBJECT
-public:
- QNetworkManagerNetworkInformationBackend();
- ~QNetworkManagerNetworkInformationBackend() = default;
-
- QString name() const override { return backendName; }
- QNetworkInformation::Features featuresSupported() const override
- {
- if (!isValid())
- return {};
- return featuresSupportedStatic();
+ switch (type) {
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_ETHERNET:
+ return QNetworkInformation::TransportMedium::Ethernet;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI:
+ return QNetworkInformation::TransportMedium::WiFi;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BT:
+ return QNetworkInformation::TransportMedium::Bluetooth;
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MODEM:
+ return QNetworkInformation::TransportMedium::Cellular;
+
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNKNOWN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_GENERIC:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED1:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_UNUSED2:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OLPC_MESH:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIMAX:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_INFINIBAND:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BOND:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_ADSL:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_BRIDGE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_TEAM:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_TUN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_IP_TUNNEL:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MACVLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VXLAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VETH:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_MACSEC:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_DUMMY:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_PPP:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_INTERFACE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_PORT:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_OVS_BRIDGE:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WPAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_6LOWPAN:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIREGUARD:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_WIFI_P2P:
+ case QNetworkManagerInterface::NM_DEVICE_TYPE_VRF:
+ break;
}
+ // While the list is exhaustive of the enum there can be additional
+ // entries added in NetworkManager that isn't listed here
+ return QNetworkInformation::TransportMedium::Unknown;
+}
- static QNetworkInformation::Features featuresSupportedStatic()
- {
- using Feature = QNetworkInformation::Feature;
- return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+bool isMeteredFromNMMetered(QNetworkManagerInterface::NMMetered metered)
+{
+ switch (metered) {
+ case QNetworkManagerInterface::NM_METERED_YES:
+ case QNetworkManagerInterface::NM_METERED_GUESS_YES:
+ return true;
+ case QNetworkManagerInterface::NM_METERED_NO:
+ case QNetworkManagerInterface::NM_METERED_GUESS_NO:
+ case QNetworkManagerInterface::NM_METERED_UNKNOWN:
+ return false;
}
+ Q_UNREACHABLE_RETURN(false);
+}
+} // unnamed namespace
- bool isValid() const { return iface.isValid(); }
-
-private:
- Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+static QString backendName()
+{
+ return QStringView(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesLinuxIndex]).toString();
+}
- QNetworkManagerInterface iface;
-};
+QString QNetworkManagerNetworkInformationBackend::name() const
+{
+ return backendName();
+}
class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
{
@@ -111,7 +115,7 @@ class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformati
public:
QNetworkManagerNetworkInformationBackendFactory() = default;
~QNetworkManagerNetworkInformationBackendFactory() = default;
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
@@ -136,26 +140,42 @@ private:
QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend()
{
- using NMState = QNetworkManagerInterface::NMState;
- setReachability(reachabilityFromNMState(iface.state()));
- connect(&iface, &QNetworkManagerInterface::stateChanged, this,
- [this](NMState newState) {
- setReachability(reachabilityFromNMState(newState));
- });
+ if (!iface.isValid())
+ return;
+ iface.setBackend(this);
+ onStateChanged(iface.state());
+ onConnectivityChanged(iface.connectivityState());
+ onDeviceTypeChanged(iface.deviceType());
+ onMeteredChanged(iface.meteredState());
+}
- using ConnectivityState = QNetworkManagerInterface::NMConnectivityState;
+void QNetworkManagerNetworkInformationBackend::onStateChanged(
+ QNetworkManagerInterface::NMState newState)
+{
+ setReachability(reachabilityFromNMState(newState));
+}
- const auto connectivityState = iface.connectivityState();
- const bool behindPortal = (connectivityState == ConnectivityState::NM_CONNECTIVITY_PORTAL);
+void QNetworkManagerNetworkInformationBackend::onConnectivityChanged(
+ QNetworkManagerInterface::NMConnectivityState connectivityState)
+{
+ const bool behindPortal =
+ (connectivityState == QNetworkManagerInterface::NM_CONNECTIVITY_PORTAL);
setBehindCaptivePortal(behindPortal);
+}
- connect(&iface, &QNetworkManagerInterface::connectivityChanged, this,
- [this](ConnectivityState state) {
- const bool behindPortal = (state == ConnectivityState::NM_CONNECTIVITY_PORTAL);
- setBehindCaptivePortal(behindPortal);
- });
+void QNetworkManagerNetworkInformationBackend::onDeviceTypeChanged(
+ QNetworkManagerInterface::NMDeviceType newDevice)
+{
+ setTransportMedium(transportMediumFromDeviceType(newDevice));
}
+void QNetworkManagerNetworkInformationBackend::onMeteredChanged(
+ QNetworkManagerInterface::NMMetered metered)
+{
+ setMetered(isMeteredFromNMMetered(metered));
+};
+
QT_END_NAMESPACE
#include "qnetworkmanagernetworkinformationbackend.moc"
+#include "moc_qnetworkmanagernetworkinformationbackend.cpp"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
new file mode 100644
index 0000000000..3b60f0949c
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKMANAGERINFORMATIONBACKEND_H
+#define QNETWORKMANAGERINFORMATIONBACKEND_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qnetworkinformation_p.h>
+#include "qnetworkmanagerservice.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkManagerNetworkInformationBackend();
+ ~QNetworkManagerNetworkInformationBackend() = default;
+
+ QString name() const override;
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium | Feature::Metered);
+ }
+
+ bool isValid() const { return iface.isValid(); }
+
+ void onStateChanged(QNetworkManagerInterface::NMState state);
+ void onConnectivityChanged(QNetworkManagerInterface::NMConnectivityState connectivityState);
+ void onDeviceTypeChanged(QNetworkManagerInterface::NMDeviceType deviceType);
+ void onMeteredChanged(QNetworkManagerInterface::NMMetered metered);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+
+ QNetworkManagerInterface iface;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
index 764507fd4b..c055555cac 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkmanagerservice.h"
+#include "qnetworkmanagernetworkinformationbackend.h"
#include <QObject>
#include <QList>
@@ -50,12 +15,40 @@
#include <QtDBus/QDBusObjectPath>
#include <QtDBus/QDBusPendingCall>
-#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"_L1
+
+#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+#define NM_DBUS_SERVICE NM_DBUS_INTERFACE ""_L1
+
+#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"_L1
+#define NM_CONNECTION_DBUS_INTERFACE NM_DBUS_SERVICE ".Connection.Active"_L1
+#define NM_DEVICE_DBUS_INTERFACE NM_DBUS_SERVICE ".Device"_L1
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+namespace {
+constexpr QLatin1StringView propertiesChangedKey = "PropertiesChanged"_L1;
+const QString &stateKey()
+{
+ static auto key = u"State"_s;
+ return key;
+}
+const QString &connectivityKey()
+{
+ static auto key = u"Connectivity"_s;
+ return key;
+}
+const QString &primaryConnectionKey()
+{
+ static auto key = u"PrimaryConnection"_s;
+ return key;
+}
+}
+
QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
- : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ : QDBusAbstractInterface(NM_DBUS_SERVICE, NM_DBUS_PATH,
NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
{
}
@@ -68,75 +61,160 @@ bool QNetworkManagerInterfaceBase::networkManagerAvailable()
QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
: QNetworkManagerInterfaceBase(parent)
{
- if (!isValid())
+ if (!QDBusAbstractInterface::isValid())
return;
PropertiesDBusInterface managerPropertiesInterface(
- QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), DBUS_PROPERTIES_INTERFACE,
+ NM_DBUS_SERVICE, NM_DBUS_PATH, DBUS_PROPERTIES_INTERFACE,
QDBusConnection::systemBus());
QList<QVariant> argumentList;
- argumentList << QLatin1String(NM_DBUS_INTERFACE);
+ argumentList << NM_DBUS_SERVICE;
QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
- QDBus::Block, QLatin1String("GetAll"), argumentList);
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- } else {
- qWarning() << "propsReply" << propsReply.error().message();
+ QDBus::Block, "GetAll"_L1, argumentList);
+ if (propsReply.isError()) {
+ validDBusConnection = false;
+ if (auto error = propsReply.error(); error.type() != QDBusError::AccessDenied)
+ qWarning() << "Failed to query NetworkManager properties:" << error.message();
+ return;
}
+ propertyMap = propsReply.value();
- QDBusConnection::systemBus().connect(
- QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), this,
- SLOT(setProperties(QMap<QString, QVariant>)));
+ validDBusConnection = QDBusConnection::systemBus().connect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
}
QNetworkManagerInterface::~QNetworkManagerInterface()
{
- QDBusConnection::systemBus().disconnect(
- QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
- QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), this,
- SLOT(setProperties(QMap<QString, QVariant>)));
+ QDBusConnection::systemBus().disconnect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
}
QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
{
- if (propertyMap.contains("State"))
- return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt());
+ auto it = propertyMap.constFind(stateKey());
+ if (it != propertyMap.cend())
+ return static_cast<QNetworkManagerInterface::NMState>(it->toUInt());
return QNetworkManagerInterface::NM_STATE_UNKNOWN;
}
QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
{
- if (propertyMap.contains("Connectivity"))
- return static_cast<NMConnectivityState>(propertyMap.value("Connectivity").toUInt());
+ auto it = propertyMap.constFind(connectivityKey());
+ if (it != propertyMap.cend())
+ return static_cast<NMConnectivityState>(it->toUInt());
return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
}
-void QNetworkManagerInterface::setProperties(const QMap<QString, QVariant> &map)
+static std::optional<QDBusInterface> getPrimaryDevice(const QDBusObjectPath &devicePath)
+{
+ const QDBusInterface connection(NM_DBUS_SERVICE, devicePath.path(),
+ NM_CONNECTION_DBUS_INTERFACE, QDBusConnection::systemBus());
+ if (!connection.isValid())
+ return std::nullopt;
+
+ const auto devicePaths = connection.property("Devices").value<QList<QDBusObjectPath>>();
+ if (devicePaths.isEmpty())
+ return std::nullopt;
+
+ const QDBusObjectPath primaryDevicePath = devicePaths.front();
+ return std::make_optional<QDBusInterface>(NM_DBUS_SERVICE, primaryDevicePath.path(),
+ NM_DEVICE_DBUS_INTERFACE,
+ QDBusConnection::systemBus());
+}
+
+std::optional<QDBusObjectPath> QNetworkManagerInterface::primaryConnectionDevicePath() const
+{
+ auto it = propertyMap.constFind(primaryConnectionKey());
+ if (it != propertyMap.cend())
+ return it->value<QDBusObjectPath>();
+ return std::nullopt;
+}
+
+auto QNetworkManagerInterface::deviceType() const -> NMDeviceType
{
+ if (const auto path = primaryConnectionDevicePath())
+ return extractDeviceType(*path);
+ return NM_DEVICE_TYPE_UNKNOWN;
+}
+
+auto QNetworkManagerInterface::meteredState() const -> NMMetered
+{
+ if (const auto path = primaryConnectionDevicePath())
+ return extractDeviceMetered(*path);
+ return NM_METERED_UNKNOWN;
+}
+
+auto QNetworkManagerInterface::extractDeviceType(const QDBusObjectPath &devicePath) const
+ -> NMDeviceType
+{
+ const auto primaryDevice = getPrimaryDevice(devicePath);
+ if (!primaryDevice)
+ return NM_DEVICE_TYPE_UNKNOWN;
+ if (!primaryDevice->isValid())
+ return NM_DEVICE_TYPE_UNKNOWN;
+ const QVariant deviceType = primaryDevice->property("DeviceType");
+ if (!deviceType.isValid())
+ return NM_DEVICE_TYPE_UNKNOWN;
+ return static_cast<NMDeviceType>(deviceType.toUInt());
+}
+
+auto QNetworkManagerInterface::extractDeviceMetered(const QDBusObjectPath &devicePath) const
+ -> NMMetered
+{
+ const auto primaryDevice = getPrimaryDevice(devicePath);
+ if (!primaryDevice)
+ return NM_METERED_UNKNOWN;
+ if (!primaryDevice->isValid())
+ return NM_METERED_UNKNOWN;
+ const QVariant metered = primaryDevice->property("Metered");
+ if (!metered.isValid())
+ return NM_METERED_UNKNOWN;
+ return static_cast<NMMetered>(metered.toUInt());
+}
+
+void QNetworkManagerInterface::setBackend(QNetworkManagerNetworkInformationBackend *ourBackend)
+{
+ backend = ourBackend;
+}
+
+void QNetworkManagerInterface::setProperties(const QString &interfaceName,
+ const QMap<QString, QVariant> &map,
+ const QStringList &invalidatedProperties)
+{
+ Q_UNUSED(interfaceName);
+ Q_UNUSED(invalidatedProperties);
+
for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) {
- const bool isState = i.key() == QLatin1String("State");
- const bool isConnectivity = i.key() == QLatin1String("Connectivity");
- bool stateUpdate = isState;
- bool connectivityUpdate = isConnectivity;
+ bool valueChanged = true;
auto it = propertyMap.lowerBound(i.key());
if (it != propertyMap.end() && it.key() == i.key()) {
- stateUpdate &= (it.value() != i.value());
- connectivityUpdate &= (it.value() != i.value());
+ valueChanged = (it.value() != i.value());
*it = *i;
} else {
propertyMap.insert(it, i.key(), i.value());
}
- if (stateUpdate) {
- quint32 state = i.value().toUInt();
- Q_EMIT stateChanged(static_cast<NMState>(state));
- } else if (connectivityUpdate) {
- quint32 state = i.value().toUInt();
- Q_EMIT connectivityChanged(static_cast<NMConnectivityState>(state));
+ if (valueChanged) {
+ if (i.key() == stateKey()) {
+ quint32 state = i.value().toUInt();
+ backend->onStateChanged(static_cast<NMState>(state));
+ } else if (i.key() == connectivityKey()) {
+ quint32 state = i.value().toUInt();
+ backend->onConnectivityChanged(static_cast<NMConnectivityState>(state));
+ } else if (i.key() == primaryConnectionKey()) {
+ const QDBusObjectPath devicePath = i->value<QDBusObjectPath>();
+ backend->onDeviceTypeChanged(extractDeviceType(devicePath));
+ backend->onMeteredChanged(extractDeviceMetered(devicePath));
+ } else if (i.key() == "Metered"_L1) {
+ backend->onMeteredChanged(static_cast<NMMetered>(i->toUInt()));
+ }
}
}
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkmanagerservice.cpp"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
index 57c5aed763..5201e8485b 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKMANAGERSERVICE_H
#define QNETWORKMANAGERSERVICE_H
@@ -51,14 +15,11 @@
// We mean it.
//
-#include <QtDBus/QDBusAbstractInterface>
-#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtDBus/QDBusObjectPath>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
+#include <QtDBus/qdbusabstractinterface.h>
-#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
-
-#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
-#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+#include <optional>
// Matches 'NMDeviceState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
enum NMDeviceState {
@@ -77,13 +38,16 @@ enum NMDeviceState {
QT_BEGIN_NAMESPACE
+class QDBusObjectPath;
+class QNetworkManagerNetworkInformationBackend;
+
// This tiny class exists for the purpose of seeing if NetworkManager is available without
// initializing everything the derived/full class needs.
class QNetworkManagerInterfaceBase : public QDBusAbstractInterface
{
Q_OBJECT
public:
- QNetworkManagerInterfaceBase(QObject *parent = nullptr);
+ explicit QNetworkManagerInterfaceBase(QObject *parent = nullptr);
~QNetworkManagerInterfaceBase() = default;
static bool networkManagerAvailable();
@@ -119,31 +83,86 @@ public:
NM_CONNECTIVITY_FULL = 4,
};
Q_ENUM(NMConnectivityState);
+ // Matches 'NMDeviceType' from
+ // https://developer-old.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMDeviceType
+ enum NMDeviceType {
+ NM_DEVICE_TYPE_UNKNOWN = 0,
+ NM_DEVICE_TYPE_GENERIC = 14,
+ NM_DEVICE_TYPE_ETHERNET = 1,
+ NM_DEVICE_TYPE_WIFI = 2,
+ NM_DEVICE_TYPE_UNUSED1 = 3,
+ NM_DEVICE_TYPE_UNUSED2 = 4,
+ NM_DEVICE_TYPE_BT = 5,
+ NM_DEVICE_TYPE_OLPC_MESH = 6,
+ NM_DEVICE_TYPE_WIMAX = 7,
+ NM_DEVICE_TYPE_MODEM = 8,
+ NM_DEVICE_TYPE_INFINIBAND = 9,
+ NM_DEVICE_TYPE_BOND = 10,
+ NM_DEVICE_TYPE_VLAN = 11,
+ NM_DEVICE_TYPE_ADSL = 12,
+ NM_DEVICE_TYPE_BRIDGE = 13,
+ NM_DEVICE_TYPE_TEAM = 15,
+ NM_DEVICE_TYPE_TUN = 16,
+ NM_DEVICE_TYPE_IP_TUNNEL = 17,
+ NM_DEVICE_TYPE_MACVLAN = 18,
+ NM_DEVICE_TYPE_VXLAN = 19,
+ NM_DEVICE_TYPE_VETH = 20,
+ NM_DEVICE_TYPE_MACSEC = 21,
+ NM_DEVICE_TYPE_DUMMY = 22,
+ NM_DEVICE_TYPE_PPP = 23,
+ NM_DEVICE_TYPE_OVS_INTERFACE = 24,
+ NM_DEVICE_TYPE_OVS_PORT = 25,
+ NM_DEVICE_TYPE_OVS_BRIDGE = 26,
+ NM_DEVICE_TYPE_WPAN = 27,
+ NM_DEVICE_TYPE_6LOWPAN = 28,
+ NM_DEVICE_TYPE_WIREGUARD = 29,
+ NM_DEVICE_TYPE_WIFI_P2P = 30,
+ NM_DEVICE_TYPE_VRF = 31,
+ };
+ // Matches 'NMMetered' from
+ // https://developer-old.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMMetered
+ enum NMMetered {
+ NM_METERED_UNKNOWN,
+ NM_METERED_YES,
+ NM_METERED_NO,
+ NM_METERED_GUESS_YES,
+ NM_METERED_GUESS_NO,
+ };
- QNetworkManagerInterface(QObject *parent = nullptr);
+ explicit QNetworkManagerInterface(QObject *parent = nullptr);
~QNetworkManagerInterface();
+ void setBackend(QNetworkManagerNetworkInformationBackend *ourBackend);
+
NMState state() const;
NMConnectivityState connectivityState() const;
+ NMDeviceType deviceType() const;
+ NMMetered meteredState() const;
-Q_SIGNALS:
- void stateChanged(NMState);
- void connectivityChanged(NMConnectivityState);
+ bool isValid() const { return QDBusAbstractInterface::isValid() && validDBusConnection; }
private Q_SLOTS:
- void setProperties(const QMap<QString, QVariant> &map);
+ void setProperties(const QString &interfaceName, const QMap<QString, QVariant> &map,
+ const QStringList &invalidatedProperties);
private:
Q_DISABLE_COPY_MOVE(QNetworkManagerInterface)
+ NMDeviceType extractDeviceType(const QDBusObjectPath &devicePath) const;
+ NMMetered extractDeviceMetered(const QDBusObjectPath &devicePath) const;
+
+ std::optional<QDBusObjectPath> primaryConnectionDevicePath() const;
+
QVariantMap propertyMap;
+ QNetworkManagerNetworkInformationBackend *backend = nullptr;
+ bool validDBusConnection = true;
};
class PropertiesDBusInterface : public QDBusAbstractInterface
{
public:
PropertiesDBusInterface(const QString &service, const QString &path, const QString &interface,
- const QDBusConnection &connection, QObject *parent = 0)
+ const QDBusConnection &connection, QObject *parent = nullptr)
: QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
{
}
diff --git a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
index c9ee7d9a42..a939ab4405 100644
--- a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
+++ b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_internal_add_plugin(QSCNetworkReachabilityNetworkInformationPlugin
OUTPUT_NAME qscnetworkreachability
CLASS_NAME QSCNetworkReachabilityNetworkInformationBackendFactory
diff --git a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
index c732afc012..d1f3cb41d4 100644
--- a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
+++ b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qnetworkinformation_p.h>
@@ -48,8 +12,11 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcNetInfoSCR)
Q_LOGGING_CATEGORY(lcNetInfoSCR, "qt.network.info.scnetworkreachability");
-
-static QString backendName = QStringLiteral("scnetworkreachability");
+static QString backendName()
+{
+ return QString::fromUtf16(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesAppleIndex]);
+}
class QSCNetworkReachabilityNetworkInformationBackend : public QNetworkInformationBackend
{
@@ -58,7 +25,7 @@ public:
QSCNetworkReachabilityNetworkInformationBackend();
~QSCNetworkReachabilityNetworkInformationBackend();
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return featuresSupportedStatic();
@@ -66,12 +33,20 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
- return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability);
+ return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
+#ifdef QT_PLATFORM_UIKIT
+ | QNetworkInformation::Feature::TransportMedium
+#endif
+ );
}
private Q_SLOTS:
void reachabilityChanged(bool isOnline);
+#ifdef QT_PLATFORM_UIKIT
+ void isWwanChanged(bool isOnline);
+#endif
+
private:
Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackend);
@@ -87,7 +62,7 @@ class QSCNetworkReachabilityNetworkInformationBackendFactory : public QNetworkIn
public:
QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
~QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
- QString name() const override { return backendName; }
+ QString name() const override { return backendName(); }
QNetworkInformation::Features featuresSupported() const override
{
return QSCNetworkReachabilityNetworkInformationBackend::featuresSupportedStatic();
@@ -107,10 +82,16 @@ private:
QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkInformationBackend()
{
bool isOnline = false;
+#ifdef QT_PLATFORM_UIKIT
+ bool isWwan = false;
+#endif
if (ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
// We manage to create SCNetworkReachabilityRef for IPv4, let's
// read the last known state then!
isOnline |= ipv4Probe.isReachable();
+#ifdef QT_PLATFORM_UIKIT
+ isWwan |= ipv4Probe.isWwan();
+#endif
ipv4Probe.startMonitoring();
}
@@ -118,9 +99,15 @@ QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkIn
// We manage to create SCNetworkReachability ref for IPv6, let's
// read the last known state then!
isOnline |= ipv6Probe.isReachable();
+#ifdef QT_PLATFORM_UIKIT
+ isWwan |= ipv6Probe.isWwan();
+#endif
ipv6Probe.startMonitoring();
}
reachabilityChanged(isOnline);
+#ifdef QT_PLATFORM_UIKIT
+ isWwanChanged(isWwan);
+#endif
connect(&ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
@@ -128,6 +115,15 @@ QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkIn
connect(&ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
Qt::QueuedConnection);
+
+#ifdef QT_PLATFORM_UIKIT
+ connect(&ipv4Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
+ Qt::QueuedConnection);
+ connect(&ipv6Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
+ Qt::QueuedConnection);
+#endif
}
QSCNetworkReachabilityNetworkInformationBackend::~QSCNetworkReachabilityNetworkInformationBackend()
@@ -140,6 +136,23 @@ void QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged(bool i
: QNetworkInformation::Reachability::Disconnected);
}
+#ifdef QT_PLATFORM_UIKIT
+void QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged(bool isWwan)
+{
+ // The reachability API from Apple only has one entry regarding transport medium: "IsWWAN"[0].
+ // This is _serviceable_ on iOS where the only other credible options are "WLAN" or
+ // "Disconnected". But on macOS you could be connected by Ethernet as well, so how would that be
+ // reported? It doesn't matter anyway since "IsWWAN" is not available on macOS.
+ // [0]: https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityflags/kscnetworkreachabilityflagsiswwan?language=objc
+ if (reachability() == QNetworkInformation::Reachability::Disconnected) {
+ setTransportMedium(QNetworkInformation::TransportMedium::Unknown);
+ } else {
+ setTransportMedium(isWwan ? QNetworkInformation::TransportMedium::Cellular
+ : QNetworkInformation::TransportMedium::WiFi);
+ }
+}
+#endif
+
QT_END_NAMESPACE
#include "qscnetworkreachabilitynetworkinformationbackend.moc"