diff options
Diffstat (limited to 'src/plugins/networkinformation/networklistmanager')
4 files changed, 116 insertions, 196 deletions
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt index d927d4af60..acd3754f4e 100644 --- a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt +++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt @@ -1,8 +1,12 @@ +# 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 + EXCEPTIONS SOURCES qnetworklistmanagernetworkinformationbackend.cpp qnetworklistmanagerevents.h qnetworklistmanagerevents.cpp @@ -10,9 +14,10 @@ qt_internal_add_plugin(QNLMNIPlugin Qt::NetworkPrivate ) -qt_internal_extend_target(QNLMNIPlugin CONDITION WIN32 AND MSVC AND NOT CLANG +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. diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp index 65824cc262..caa5046751 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp @@ -1,56 +1,18 @@ -/**************************************************************************** -** -** 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 "qnetworklistmanagerevents.h" +#include <QtCore/private/qsystemerror_p.h> -#ifdef SUPPORTS_WINRT -#include <winrt/base.h> -// Workaround for Windows SDK bug. -// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47 -namespace winrt::impl -{ - template <typename Async> - auto wait_for(Async const& async, Windows::Foundation::TimeSpan const& timeout); -} +#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 +#endif // QT_CONFIG(cpp_winrt) QT_BEGIN_NAMESPACE @@ -73,7 +35,7 @@ QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr) IID_INetworkListManager, &networkListManager); if (FAILED(hr)) { qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:" - << errorStringFromHResult(hr); + << QSystemError::windowsComString(hr); return; } @@ -85,7 +47,7 @@ QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr) } if (FAILED(hr)) { qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:" - << errorStringFromHResult(hr); + << QSystemError::windowsComString(hr); } } @@ -123,26 +85,39 @@ bool QNetworkListManagerEvents::start() auto hr = connectionPoint->Advise(this, &cookie); if (FAILED(hr)) { qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:" - << errorStringFromHResult(hr); + << 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:" << errorStringFromHResult(hr); - else + if (FAILED(hr)) { + qCWarning(lcNetInfoNLM) << "Could not get connectivity:" + << QSystemError::windowsComString(hr); + } else { emit connectivityChanged(connectivity); + } -#ifdef SUPPORTS_WINRT +#if QT_CONFIG(cpp_winrt) using namespace winrt::Windows::Networking::Connectivity; - // Register for changes in the network and store a token to unregister later: - token = NetworkInformation::NetworkStatusChanged( - [this](const winrt::Windows::Foundation::IInspectable sender) { - Q_UNUSED(sender); - emitWinRTUpdates(); - }); + 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 @@ -150,24 +125,28 @@ bool QNetworkListManagerEvents::start() return true; } -bool QNetworkListManagerEvents::stop() +void 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; + << QSystemError::windowsComString(hr); + } else { + cookie = 0; } - cookie = 0; + // Even if we fail we should still try to unregister from winrt events: -#ifdef SUPPORTS_WINRT - using namespace winrt::Windows::Networking::Connectivity; - // Pass the token we stored earlier to unregister: - NetworkInformation::NetworkStatusChanged(token); - token = {}; +#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 - return true; } bool QNetworkListManagerEvents::checkBehindCaptivePortal() @@ -191,7 +170,7 @@ bool QNetworkListManagerEvents::checkBehindCaptivePortal() VariantInit(&variant); const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); }); - const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 }; + const wchar_t *versions[] = { L"NA_InternetConnectivityV6", L"NA_InternetConnectivityV4" }; for (const auto version : versions) { hr = propertyBag->Read(version, &variant, nullptr); if (SUCCEEDED(hr) @@ -208,7 +187,7 @@ bool QNetworkListManagerEvents::checkBehindCaptivePortal() return false; } -#ifdef SUPPORTS_WINRT +#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 @@ -221,7 +200,14 @@ QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile if (profile.IsWlanConnectionProfile()) return QNetworkInformation::TransportMedium::WiFi; - NetworkAdapter adapter = profile.NetworkAdapter(); + 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; @@ -244,7 +230,16 @@ QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile [[nodiscard]] bool getMetered(const ConnectionProfile &profile) { - ConnectionCost cost = profile.GetConnectionCost(); + 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; } @@ -253,12 +248,21 @@ QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile void QNetworkListManagerEvents::emitWinRTUpdates() { using namespace winrt::Windows::Networking::Connectivity; - ConnectionProfile profile = NetworkInformation::GetInternetConnectionProfile(); + 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 +#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 index 4c4625adb5..d91cd8a4cc 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h @@ -1,41 +1,8 @@ -/**************************************************************************** -** -** 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 + +#ifndef QNETWORKLISTMANAGEREVENTS_H +#define QNETWORKLISTMANAGEREVENTS_H #include <QtNetwork/private/qtnetworkglobal_p.h> @@ -44,19 +11,16 @@ #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> -#include <comdef.h> - -#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) -#define SUPPORTS_WINRT 1 -#endif -#ifdef SUPPORTS_WINRT -#include <winrt/base.h> +#if QT_CONFIG(cpp_winrt) +#include <QtCore/private/qt_winrtbase_p.h> #endif using namespace Microsoft::WRL; @@ -64,12 +28,6 @@ using namespace Microsoft::WRL; QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM) -inline QString errorStringFromHResult(HRESULT hr) -{ - _com_error error(hr); - return QString::fromWCharArray(error.ErrorMessage()); -} - class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents { Q_OBJECT @@ -92,7 +50,7 @@ public: HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override; [[nodiscard]] bool start(); - bool stop(); + void stop(); [[nodiscard]] bool checkBehindCaptivePortal(); @@ -105,10 +63,11 @@ private: ComPtr<INetworkListManager> networkListManager = nullptr; ComPtr<IConnectionPoint> connectionPoint = nullptr; -#ifdef SUPPORTS_WINRT +#if QT_CONFIG(cpp_winrt) void emitWinRTUpdates(); winrt::event_token token; + QMutex winrtLock; #endif QAtomicInteger<ULONG> ref = 0; @@ -116,3 +75,5 @@ private: }; QT_END_NAMESPACE + +#endif // QNETWORKLISTMANAGEREVENTS_H diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp index 4cdc80cd5d..766648486e 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.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> @@ -45,6 +9,8 @@ #include <QtCore/private/qobject_p.h> #include <QtCore/qscopeguard.h> +#include <QtCore/private/qfunctions_win_p.h> + QT_BEGIN_NAMESPACE // Declared in qnetworklistmanagerevents.h @@ -104,8 +70,9 @@ public: { return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability | QNetworkInformation::Feature::CaptivePortal -#ifdef SUPPORTS_WINRT +#if QT_CONFIG(cpp_winrt) | QNetworkInformation::Feature::TransportMedium + | QNetworkInformation::Feature::Metered #endif ); } @@ -118,12 +85,13 @@ private: 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 @@ -157,12 +125,9 @@ public: 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); @@ -176,8 +141,6 @@ QNetworkListManagerNetworkInformationBackend::QNetworkListManagerNetworkInformat QNetworkListManagerNetworkInformationBackend::~QNetworkListManagerNetworkInformationBackend() { - if (comInitFailed) - return; stop(); } @@ -200,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); } @@ -213,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(); @@ -234,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 |