diff options
author | Mårten Nordheim <marten.nordheim@qt.io> | 2021-09-29 16:00:38 +0200 |
---|---|---|
committer | Mårten Nordheim <marten.nordheim@qt.io> | 2021-10-07 19:08:47 +0200 |
commit | 1834fcad33181cb38916746c7029456c800ec23b (patch) | |
tree | 42eb10ebd3434886df01b39c9682576ec4513af1 /src/plugins | |
parent | 5d941c76604a534712f58ff9467f3c27083bf50c (diff) | |
download | qtbase-1834fcad33181cb38916746c7029456c800ec23b.tar.gz |
QNI: NetworkListManager: Extract the Events class
Moving the class out makes it easier to navigate the code
Change-Id: I8de67641512a7dbbf6446cdca9d8dea79a63c217
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/plugins')
4 files changed, 285 insertions, 186 deletions
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt index 170bce0f7b..b5cf60b62c 100644 --- a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt +++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt @@ -3,7 +3,9 @@ qt_internal_add_plugin(QNLMNIPlugin CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory PLUGIN_TYPE networkinformation DEFAULT_IF WIN32 AND QT_FEATURE_networklistmanager - SOURCES qnetworklistmanagernetworkinformationbackend.cpp + SOURCES + qnetworklistmanagernetworkinformationbackend.cpp + qnetworklistmanagerevents.h qnetworklistmanagerevents.cpp LIBRARIES Qt::NetworkPrivate ) diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp new file mode 100644 index 0000000000..bac5c1f339 --- /dev/null +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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 "qnetworklistmanagerevents.h" + +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:" + << 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 + 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:" + << 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; +} + +QT_END_NAMESPACE diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h new file mode 100644 index 0000000000..60a2367e4f --- /dev/null +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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/qtnetworkglobal_p.h> + +#include <QtCore/qstring.h> +#include <QtCore/qobject.h> +#include <QtCore/qloggingcategory.h> + +#include <objbase.h> +#include <netlistmgr.h> +#include <wrl/client.h> +#include <wrl/wrappers/corewrappers.h> +#include <comdef.h> + +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 +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; +}; + +QT_END_NAMESPACE diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp index 5157b778b9..02b4c48be8 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp @@ -39,42 +39,20 @@ #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; - QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM) + +// Declared in qnetworklistmanagerevents.h 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; @@ -105,7 +83,6 @@ QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIV } } -class QNetworkListManagerEvents; class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend { Q_OBJECT @@ -172,164 +149,6 @@ 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 - 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:" - << 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); |