summaryrefslogtreecommitdiffstats
path: root/src/plugins/networkinformation
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2021-06-03 15:51:07 +0200
committerMårten Nordheim <marten.nordheim@qt.io>2021-06-11 19:23:03 +0200
commitd245e3a7883ccb2c8beabbca5094de54ec963644 (patch)
tree731cd57605802d03d3193540db147727ad38a077 /src/plugins/networkinformation
parentf6f6d06028a62fef3e0d8458903549499fced45a (diff)
QNetworkInformation: Rename the plugins and type
To better match other plugins in Qt Pick-to: 6.2 Change-Id: I6ab19603f13c80a8afe4fe69f64669559a0eea15 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Yuhang Zhao <2546789017@qq.com>
Diffstat (limited to 'src/plugins/networkinformation')
-rw-r--r--src/plugins/networkinformation/CMakeLists.txt15
-rw-r--r--src/plugins/networkinformation/android/CMakeLists.txt43
-rw-r--r--src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java136
-rw-r--r--src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp136
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp146
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h75
-rw-r--r--src/plugins/networkinformation/networklistmanager/CMakeLists.txt13
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp419
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt13
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp161
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp142
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h154
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt11
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm145
14 files changed, 1609 insertions, 0 deletions
diff --git a/src/plugins/networkinformation/CMakeLists.txt b/src/plugins/networkinformation/CMakeLists.txt
new file mode 100644
index 0000000000..142031c62a
--- /dev/null
+++ b/src/plugins/networkinformation/CMakeLists.txt
@@ -0,0 +1,15 @@
+if(WIN32 AND QT_FEATURE_networklistmanager)
+ add_subdirectory(networklistmanager)
+endif()
+
+if(LINUX AND TARGET Qt::DBus)
+ add_subdirectory(networkmanager)
+endif()
+
+if(APPLE)
+ add_subdirectory(scnetworkreachability)
+endif()
+
+if(ANDROID)
+ add_subdirectory(android)
+endif()
diff --git a/src/plugins/networkinformation/android/CMakeLists.txt b/src/plugins/networkinformation/android/CMakeLists.txt
new file mode 100644
index 0000000000..f1d260547a
--- /dev/null
+++ b/src/plugins/networkinformation/android/CMakeLists.txt
@@ -0,0 +1,43 @@
+
+set(java_sources
+ jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
+)
+
+qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
+ INCLUDE_JARS ${QT_ANDROID_JAR}
+ SOURCES ${java_sources}
+ OUTPUT_DIR "${QT_BUILD_DIR}/jar"
+)
+
+install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
+ DESTINATION jar
+ COMPONENT Devel
+)
+
+qt_internal_add_plugin(QAndroidNetworkInformationPlugin
+ OUTPUT_NAME androidnetworkinformation
+ CLASS_NAME QAndroidNetworkInformationBackendFactory
+ TYPE networkinformation
+ DEFAULT_IF ANDROID
+ SOURCES
+ qandroidnetworkinformationbackend.cpp
+ wrapper/androidconnectivitymanager.cpp wrapper/androidconnectivitymanager.h
+ LIBRARIES
+ Qt::NetworkPrivate
+ DEFINES
+ QT_USE_QSTRINGBUILDER
+)
+
+set_property(
+ TARGET
+ QAndroidNetworkInformationPlugin
+ APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ jar/Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend.jar
+)
+
+set_property(
+ TARGET
+ QAndroidNetworkInformationPlugin
+ APPEND PROPERTY QT_ANDROID_PERMISSIONS
+ android.permission.ACCESS_NETWORK_STATE
+)
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
new file mode 100644
index 0000000000..0e89d23ab4
--- /dev/null
+++ b/src/plugins/networkinformation/android/jar/src/org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation.java
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt.android.networkinformation;
+
+import android.content.BroadcastReceiver;
+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;
+
+public class QtAndroidNetworkInformation {
+ private static final String LOG_TAG = "QtAndroidNetworkInformation";
+
+ private static native void connectivityChanged();
+ private static native void behindCaptivePortalChanged(boolean state);
+
+ private static QtNetworkInformationCallback m_callback = null;
+ private static final Object m_lock = new Object();
+
+ enum AndroidConnectivity {
+ Connected, Unknown, Disconnected
+ }
+
+ private static class QtNetworkInformationCallback extends NetworkCallback {
+ public AndroidConnectivity previousState = null;
+
+ QtNetworkInformationCallback() {
+ }
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
+ AndroidConnectivity s;
+ if (!capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET))
+ s = AndroidConnectivity.Disconnected;
+ else if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
+ s = AndroidConnectivity.Connected;
+ else
+ s = AndroidConnectivity.Unknown; // = we _may_ have Internet access
+ setState(s);
+
+ final boolean captive
+ = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ behindCaptivePortalChanged(captive);
+ }
+
+ private void setState(AndroidConnectivity s) {
+ if (previousState != s) {
+ previousState = s;
+ connectivityChanged();
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ setState(AndroidConnectivity.Disconnected);
+ }
+ }
+
+ private QtAndroidNetworkInformation() {
+ }
+
+ public static AndroidConnectivity state() {
+ if (m_callback != null && m_callback.previousState != null)
+ return m_callback.previousState;
+ return AndroidConnectivity.Unknown;
+ }
+
+ 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();
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
+ builder = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND);
+ NetworkRequest request = builder.build();
+ manager.registerNetworkCallback(request, m_callback);
+ }
+ }
+ }
+
+ public static void unregisterReceiver(final Context context) {
+ synchronized (m_lock) {
+ if (m_callback != null) {
+ getConnectivityManager(context).unregisterNetworkCallback(m_callback);
+ m_callback = null;
+ }
+ }
+ }
+
+ public static ConnectivityManager getConnectivityManager(final Context context) {
+ return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+}
diff --git a/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
new file mode 100644
index 0000000000..9eef471989
--- /dev/null
+++ b/src/plugins/networkinformation/android/qandroidnetworkinformationbackend.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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 "wrapper/androidconnectivitymanager.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoAndroid)
+Q_LOGGING_CATEGORY(lcNetInfoAndroid, "qt.network.info.android");
+
+static const QString backendName = QStringLiteral("android");
+
+class QAndroidNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QAndroidNetworkInformationBackend();
+ ~QAndroidNetworkInformationBackend() { m_valid = false; }
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+ }
+
+ bool isValid() { return m_valid; }
+
+private:
+ Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackend);
+ bool m_valid = false;
+};
+
+class QAndroidNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QAndroidNetworkInformationBackendFactory() = default;
+ ~QAndroidNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QAndroidNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *
+ create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QAndroidNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+
+private:
+ Q_DISABLE_COPY_MOVE(QAndroidNetworkInformationBackendFactory);
+};
+
+QAndroidNetworkInformationBackend::QAndroidNetworkInformationBackend()
+{
+ auto conman = AndroidConnectivityManager::getInstance();
+ if (!conman)
+ 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::captivePortalChanged, this,
+ &QAndroidNetworkInformationBackend::setBehindCaptivePortal);
+}
+
+QT_END_NAMESPACE
+
+#include "qandroidnetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
new file mode 100644
index 0000000000..e88fe7d955
--- /dev/null
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "androidconnectivitymanager.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qjnienvironment.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QNativeInterface;
+
+struct AndroidConnectivityManagerInstance
+{
+ AndroidConnectivityManagerInstance() : connManager(new AndroidConnectivityManager) { }
+ std::unique_ptr<AndroidConnectivityManager> connManager = nullptr;
+};
+Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance)
+
+static const char networkInformationClass[] =
+ "org/qtproject/qt/android/networkinformation/QtAndroidNetworkInformation";
+
+static void networkConnectivityChanged(JNIEnv *env, jobject obj)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ Q_EMIT androidConnManagerInstance->connManager->connectivityChanged();
+}
+
+static void behindCaptivePortalChanged(JNIEnv *env, jobject obj, jboolean state)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(obj);
+ Q_EMIT androidConnManagerInstance->connManager->captivePortalChanged(state);
+}
+
+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());
+}
+
+AndroidConnectivityManager *AndroidConnectivityManager::getInstance()
+{
+ if (!androidConnManagerInstance())
+ return nullptr;
+ return androidConnManagerInstance->connManager->isValid()
+ ? androidConnManagerInstance->connManager.get()
+ : nullptr;
+}
+
+AndroidConnectivityManager::~AndroidConnectivityManager()
+{
+ QJniObject::callStaticMethod<void>(networkInformationClass, "unregisterReceiver",
+ "(Landroid/content/Context;)V", QAndroidApplication::context());
+}
+
+AndroidConnectivityManager::AndroidConnectivity AndroidConnectivityManager::networkConnectivity()
+{
+ 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;
+}
+
+bool AndroidConnectivityManager::registerNatives()
+{
+ 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;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
new file mode 100644
index 0000000000..14f5aa9b57
--- /dev/null
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef ANDROIDCONNECTIVITYMANAGER_H
+#define ANDROIDCONNECTIVITYMANAGER_H
+
+#include <QObject>
+#include <QtCore/qjniobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class AndroidConnectivityManager : public QObject
+{
+ Q_OBJECT
+public:
+ enum class AndroidConnectivity { Connected, Unknown, Disconnected };
+ Q_ENUM(AndroidConnectivity);
+ static AndroidConnectivityManager *getInstance();
+ ~AndroidConnectivityManager();
+
+ AndroidConnectivity networkConnectivity();
+ inline bool isValid() const { return m_connectivityManager.isValid(); }
+
+Q_SIGNALS:
+ void connectivityChanged();
+ void captivePortalChanged(bool state);
+
+private:
+ friend struct AndroidConnectivityManagerInstance;
+ AndroidConnectivityManager();
+ bool registerNatives();
+ QJniObject m_connectivityManager;
+
+ Q_DISABLE_COPY_MOVE(AndroidConnectivityManager);
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDCONNECTIVITYMANAGER_H
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
new file mode 100644
index 0000000000..52f19aefa9
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_internal_add_plugin(QNLMNIPlugin
+ OUTPUT_NAME networklistmanager
+ CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory
+ TYPE networkinformation
+ DEFAULT_IF WINDOWS AND QT_FEATURE_networklistmanager
+ SOURCES qnetworklistmanagernetworkinformationbackend.cpp
+ PUBLIC_LIBRARIES
+ Qt::NetworkPrivate
+)
+
+# 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/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
new file mode 100644
index 0000000000..d37f83832b
--- /dev/null
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
@@ -0,0 +1,419 @@
+/****************************************************************************
+**
+** 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 <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;
+
+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());
+}
+
+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;
+}
+
+bool testCONNECTIVITY(NLM_CONNECTIVITY connectivity, NLM_CONNECTIVITY flag)
+{
+ return (connectivity & flag) == flag;
+}
+
+QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIVITY connectivity)
+{
+ if (connectivity == NLM_CONNECTIVITY_DISCONNECTED)
+ return QNetworkInformation::Reachability::Disconnected;
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_INTERNET)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_INTERNET)) {
+ return QNetworkInformation::Reachability::Online;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_SUBNET)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_SUBNET)) {
+ return QNetworkInformation::Reachability::Site;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_LOCALNETWORK)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_LOCALNETWORK)) {
+ return QNetworkInformation::Reachability::Local;
+ }
+ if (testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV6_NOTRAFFIC)
+ || testCONNECTIVITY(connectivity, NLM_CONNECTIVITY_IPV4_NOTRAFFIC)) {
+ return QNetworkInformation::Reachability::Unknown;
+ }
+
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+class QNetworkListManagerEvents;
+class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkListManagerNetworkInformationBackend();
+ ~QNetworkListManagerNetworkInformationBackend();
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
+ | QNetworkInformation::Feature::CaptivePortal);
+ }
+
+ [[nodiscard]] bool start();
+ void stop();
+
+private:
+ friend class QNetworkListManagerEvents;
+
+ bool event(QEvent *event) override;
+ void setConnectivity(NLM_CONNECTIVITY newConnectivity);
+ void checkCaptivePortal();
+
+ ComPtr<QNetworkListManagerEvents> managerEvents;
+
+ NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED;
+
+ bool monitoring = false;
+ bool comInitFailed = false;
+};
+
+class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QNetworkListManagerNetworkInformationBackendFactory() = default;
+ ~QNetworkListManagerNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QNetworkListManagerNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *
+ create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ auto backend = new QNetworkListManagerNetworkInformationBackend();
+ if (!backend->start()) {
+ qCWarning(lcNetInfoNLM) << "Failed to start listening to events";
+ delete backend;
+ backend = nullptr;
+ }
+ return backend;
+ }
+};
+
+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;
+ return;
+ }
+ managerEvents = new QNetworkListManagerEvents();
+ connect(managerEvents.Get(), &QNetworkListManagerEvents::connectivityChanged, this,
+ &QNetworkListManagerNetworkInformationBackend::setConnectivity);
+}
+
+QNetworkListManagerNetworkInformationBackend::~QNetworkListManagerNetworkInformationBackend()
+{
+ if (comInitFailed)
+ return;
+ stop();
+}
+
+void QNetworkListManagerNetworkInformationBackend::setConnectivity(NLM_CONNECTIVITY newConnectivity)
+{
+ if (reachabilityFromNLM_CONNECTIVITY(connectivity)
+ != reachabilityFromNLM_CONNECTIVITY(newConnectivity)) {
+ connectivity = newConnectivity;
+ setReachability(reachabilityFromNLM_CONNECTIVITY(newConnectivity));
+
+ // @future: only check if signal is connected
+ checkCaptivePortal();
+ }
+}
+
+void QNetworkListManagerNetworkInformationBackend::checkCaptivePortal()
+{
+ setBehindCaptivePortal(managerEvents->checkBehindCaptivePortal());
+}
+
+bool QNetworkListManagerNetworkInformationBackend::event(QEvent *event)
+{
+ if (event->type() == QEvent::ThreadChange && monitoring) {
+ stop();
+ QMetaObject::invokeMethod(this, &QNetworkListManagerNetworkInformationBackend::start,
+ Qt::QueuedConnection);
+ }
+
+ return QObject::event(event);
+}
+
+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 (!managerEvents)
+ managerEvents = new QNetworkListManagerEvents();
+
+ if (managerEvents->start())
+ monitoring = true;
+ return monitoring;
+}
+
+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
+
+#include "qnetworklistmanagernetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
new file mode 100644
index 0000000000..900364c32f
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
+ OUTPUT_NAME networkmanager
+ CLASS_NAME QNetworkManagerNetworkInformationBackendFactory
+ TYPE networkinformation
+ DEFAULT_IF LINUX
+ SOURCES
+ qnetworkmanagernetworkinformationbackend.cpp
+ qnetworkmanagerservice.h
+ qnetworkmanagerservice.cpp
+ PUBLIC_LIBRARIES
+ Qt::DBus
+ Qt::NetworkPrivate
+)
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
new file mode 100644
index 0000000000..bfb04ae4a6
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <QtDBus/qdbusmessage.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
+Q_LOGGING_CATEGORY(lcNetInfoNM, "qt.network.info.networkmanager");
+
+namespace {
+QNetworkInformation::Reachability reachabilityFromNMState(QNetworkManagerInterface::NMState state)
+{
+ switch (state) {
+ case QNetworkManagerInterface::NM_STATE_UNKNOWN:
+ case QNetworkManagerInterface::NM_STATE_ASLEEP:
+ case QNetworkManagerInterface::NM_STATE_CONNECTING:
+ return QNetworkInformation::Reachability::Unknown;
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTING: // No point in starting new connections:
+ case QNetworkManagerInterface::NM_STATE_DISCONNECTED:
+ return QNetworkInformation::Reachability::Disconnected;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_LOCAL:
+ return QNetworkInformation::Reachability::Local;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_SITE:
+ return QNetworkInformation::Reachability::Site;
+ case QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL:
+ return QNetworkInformation::Reachability::Online;
+ }
+ return QNetworkInformation::Reachability::Unknown;
+}
+}
+
+static QString backendName = QStringLiteral("networkmanager");
+
+class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkManagerNetworkInformationBackend();
+ ~QNetworkManagerNetworkInformationBackend() = default;
+
+ 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);
+ }
+
+ bool isValid() const { return iface.isValid(); }
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+
+ QNetworkManagerInterface iface;
+};
+
+class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QNetworkManagerNetworkInformationBackendFactory() = default;
+ ~QNetworkManagerNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return {};
+ return QNetworkManagerNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ if (!QNetworkManagerInterfaceBase::networkManagerAvailable())
+ return nullptr;
+ auto backend = new QNetworkManagerNetworkInformationBackend();
+ if (!backend->isValid())
+ delete std::exchange(backend, nullptr);
+ return backend;
+ }
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackendFactory)
+};
+
+QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend()
+{
+ using NMState = QNetworkManagerInterface::NMState;
+ setReachability(reachabilityFromNMState(iface.state()));
+ connect(&iface, &QNetworkManagerInterface::stateChanged, this,
+ [this](NMState newState) {
+ setReachability(reachabilityFromNMState(newState));
+ });
+
+ using ConnectivityState = QNetworkManagerInterface::NMConnectivityState;
+
+ const auto connectivityState = iface.connectivityState();
+ const bool behindPortal = (connectivityState == ConnectivityState::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+
+ connect(&iface, &QNetworkManagerInterface::connectivityChanged, this,
+ [this](ConnectivityState state) {
+ const bool behindPortal = (state == ConnectivityState::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+ });
+}
+
+QT_END_NAMESPACE
+
+#include "qnetworkmanagernetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
new file mode 100644
index 0000000000..764507fd4b
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qnetworkmanagerservice.h"
+
+#include <QObject>
+#include <QList>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusError>
+#include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusReply>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusObjectPath>
+#include <QtDBus/QDBusPendingCall>
+
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+
+QT_BEGIN_NAMESPACE
+
+QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
+ : QDBusAbstractInterface(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
+{
+}
+
+bool QNetworkManagerInterfaceBase::networkManagerAvailable()
+{
+ return QNetworkManagerInterfaceBase().isValid();
+}
+
+QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
+ : QNetworkManagerInterfaceBase(parent)
+{
+ if (!isValid())
+ return;
+
+ PropertiesDBusInterface managerPropertiesInterface(
+ QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), DBUS_PROPERTIES_INTERFACE,
+ QDBusConnection::systemBus());
+ QList<QVariant> argumentList;
+ argumentList << QLatin1String(NM_DBUS_INTERFACE);
+ QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
+ QDBus::Block, QLatin1String("GetAll"), argumentList);
+ if (!propsReply.isError()) {
+ propertyMap = propsReply.value();
+ } else {
+ qWarning() << "propsReply" << propsReply.error().message();
+ }
+
+ QDBusConnection::systemBus().connect(
+ QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH),
+ QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), this,
+ SLOT(setProperties(QMap<QString, QVariant>)));
+}
+
+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>)));
+}
+
+QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
+{
+ if (propertyMap.contains("State"))
+ return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt());
+ return QNetworkManagerInterface::NM_STATE_UNKNOWN;
+}
+
+QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
+{
+ if (propertyMap.contains("Connectivity"))
+ return static_cast<NMConnectivityState>(propertyMap.value("Connectivity").toUInt());
+ return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
+}
+
+void QNetworkManagerInterface::setProperties(const QMap<QString, QVariant> &map)
+{
+ 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;
+
+ auto it = propertyMap.lowerBound(i.key());
+ if (it != propertyMap.end() && it.key() == i.key()) {
+ stateUpdate &= (it.value() != i.value());
+ connectivityUpdate &= (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));
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
new file mode 100644
index 0000000000..57c5aed763
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QNETWORKMANAGERSERVICE_H
+#define QNETWORKMANAGERSERVICE_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 <QtDBus/QDBusAbstractInterface>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusObjectPath>
+
+#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
+
+#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
+#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+
+// Matches 'NMDeviceState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+enum NMDeviceState {
+ NM_DEVICE_STATE_UNKNOWN = 0,
+ NM_DEVICE_STATE_UNMANAGED = 10,
+ NM_DEVICE_STATE_UNAVAILABLE = 20,
+ NM_DEVICE_STATE_DISCONNECTED = 30,
+ NM_DEVICE_STATE_PREPARE = 40,
+ NM_DEVICE_STATE_CONFIG = 50,
+ NM_DEVICE_STATE_NEED_AUTH = 60,
+ NM_DEVICE_STATE_IP_CONFIG = 70,
+ NM_DEVICE_STATE_ACTIVATED = 100,
+ NM_DEVICE_STATE_DEACTIVATING = 110,
+ NM_DEVICE_STATE_FAILED = 120
+};
+
+QT_BEGIN_NAMESPACE
+
+// 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);
+ ~QNetworkManagerInterfaceBase() = default;
+
+ static bool networkManagerAvailable();
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterfaceBase)
+};
+
+class QNetworkManagerInterface final : public QNetworkManagerInterfaceBase
+{
+ Q_OBJECT
+
+public:
+ // Matches 'NMState' from https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
+ enum NMState {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70
+ };
+ Q_ENUM(NMState);
+ // Matches 'NMConnectivityState' from
+ // https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMConnectivityState
+ enum NMConnectivityState {
+ NM_CONNECTIVITY_UNKNOWN = 0,
+ NM_CONNECTIVITY_NONE = 1,
+ NM_CONNECTIVITY_PORTAL = 2,
+ NM_CONNECTIVITY_LIMITED = 3,
+ NM_CONNECTIVITY_FULL = 4,
+ };
+ Q_ENUM(NMConnectivityState);
+
+ QNetworkManagerInterface(QObject *parent = nullptr);
+ ~QNetworkManagerInterface();
+
+ NMState state() const;
+ NMConnectivityState connectivityState() const;
+
+Q_SIGNALS:
+ void stateChanged(NMState);
+ void connectivityChanged(NMConnectivityState);
+
+private Q_SLOTS:
+ void setProperties(const QMap<QString, QVariant> &map);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerInterface)
+
+ QVariantMap propertyMap;
+};
+
+class PropertiesDBusInterface : public QDBusAbstractInterface
+{
+public:
+ PropertiesDBusInterface(const QString &service, const QString &path, const QString &interface,
+ const QDBusConnection &connection, QObject *parent = 0)
+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
+ {
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
new file mode 100644
index 0000000000..87ca1f0a6d
--- /dev/null
+++ b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
@@ -0,0 +1,11 @@
+qt_internal_add_plugin(QSCNetworkReachabilityNetworkInformationPlugin
+ OUTPUT_NAME scnetworkreachability
+ CLASS_NAME QSCNetworkReachabilityNetworkInformationBackendFactory
+ TYPE networkinformation
+ DEFAULT_IF APPLE
+ SOURCES
+ qscnetworkreachabilitynetworkinformationbackend.mm
+ PUBLIC_LIBRARIES
+ Qt::NetworkPrivate
+ ${FWSystemConfiguration}
+)
diff --git a/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
new file mode 100644
index 0000000000..c732afc012
--- /dev/null
+++ b/src/plugins/networkinformation/scnetworkreachability/qscnetworkreachabilitynetworkinformationbackend.mm
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** 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 <QtNetwork/private/qnetconmonitor_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfoSCR)
+Q_LOGGING_CATEGORY(lcNetInfoSCR, "qt.network.info.scnetworkreachability");
+
+
+static QString backendName = QStringLiteral("scnetworkreachability");
+
+class QSCNetworkReachabilityNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QSCNetworkReachabilityNetworkInformationBackend();
+ ~QSCNetworkReachabilityNetworkInformationBackend();
+
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability);
+ }
+
+private Q_SLOTS:
+ void reachabilityChanged(bool isOnline);
+
+private:
+ Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackend);
+
+ QNetworkConnectionMonitor ipv4Probe;
+ QNetworkConnectionMonitor ipv6Probe;
+};
+
+class QSCNetworkReachabilityNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
+ Q_INTERFACES(QNetworkInformationBackendFactory)
+public:
+ QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
+ ~QSCNetworkReachabilityNetworkInformationBackendFactory() = default;
+ QString name() const override { return backendName; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return QSCNetworkReachabilityNetworkInformationBackend::featuresSupportedStatic();
+ }
+
+ QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
+ {
+ if ((requiredFeatures & featuresSupported()) != requiredFeatures)
+ return nullptr;
+ return new QSCNetworkReachabilityNetworkInformationBackend();
+ }
+
+private:
+ Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackendFactory);
+};
+
+QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkInformationBackend()
+{
+ bool isOnline = false;
+ if (ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
+ // We manage to create SCNetworkReachabilityRef for IPv4, let's
+ // read the last known state then!
+ isOnline |= ipv4Probe.isReachable();
+ ipv4Probe.startMonitoring();
+ }
+
+ if (ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) {
+ // We manage to create SCNetworkReachability ref for IPv6, let's
+ // read the last known state then!
+ isOnline |= ipv6Probe.isReachable();
+ ipv6Probe.startMonitoring();
+ }
+ reachabilityChanged(isOnline);
+
+ connect(&ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
+ Qt::QueuedConnection);
+ connect(&ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
+ Qt::QueuedConnection);
+}
+
+QSCNetworkReachabilityNetworkInformationBackend::~QSCNetworkReachabilityNetworkInformationBackend()
+{
+}
+
+void QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged(bool isOnline)
+{
+ setReachability(isOnline ? QNetworkInformation::Reachability::Online
+ : QNetworkInformation::Reachability::Disconnected);
+}
+
+QT_END_NAMESPACE
+
+#include "qscnetworkreachabilitynetworkinformationbackend.moc"