diff options
Diffstat (limited to 'src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp')
-rw-r--r-- | src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp | 288 |
1 files changed, 34 insertions, 254 deletions
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp index d37f83832b..766648486e 100644 --- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp +++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp @@ -1,80 +1,28 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <QtNetwork/private/qnetworkinformation_p.h> +#include "qnetworklistmanagerevents.h" + #include <QtCore/qglobal.h> #include <QtCore/private/qobject_p.h> #include <QtCore/qscopeguard.h> -#include <objbase.h> -#include <netlistmgr.h> -#include <wrl/client.h> -#include <wrl/wrappers/corewrappers.h> -#include <comdef.h> -#include <iphlpapi.h> -using namespace Microsoft::WRL; +#include <QtCore/private/qfunctions_win_p.h> QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM) -Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager"); - -static const QString backendName = QStringLiteral("networklistmanager"); -namespace { -QString errorStringFromHResult(HRESULT hr) -{ - _com_error error(hr); - return QString::fromWCharArray(error.ErrorMessage()); -} +// Declared in qnetworklistmanagerevents.h +Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager"); -template<typename T> -bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject) +static QString backendName() { - if (riid == __uuidof(T)) { - *ppvObject = static_cast<T *>(from); - from->AddRef(); - return true; - } - return false; + return QString::fromUtf16(QNetworkInformationBackend::PluginNames + [QNetworkInformationBackend::PluginNamesWindowsIndex]); } +namespace { bool testCONNECTIVITY(NLM_CONNECTIVITY connectivity, NLM_CONNECTIVITY flag) { return (connectivity & flag) == flag; @@ -105,7 +53,6 @@ QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIV } } -class QNetworkListManagerEvents; class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend { Q_OBJECT @@ -113,7 +60,7 @@ public: QNetworkListManagerNetworkInformationBackend(); ~QNetworkListManagerNetworkInformationBackend(); - QString name() const override { return backendName; } + QString name() const override { return backendName(); } QNetworkInformation::Features featuresSupported() const override { return featuresSupportedStatic(); @@ -122,25 +69,29 @@ public: static QNetworkInformation::Features featuresSupportedStatic() { return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability - | QNetworkInformation::Feature::CaptivePortal); + | QNetworkInformation::Feature::CaptivePortal +#if QT_CONFIG(cpp_winrt) + | QNetworkInformation::Feature::TransportMedium + | QNetworkInformation::Feature::Metered +#endif + ); } [[nodiscard]] bool start(); void stop(); private: - friend class QNetworkListManagerEvents; - bool event(QEvent *event) override; void setConnectivity(NLM_CONNECTIVITY newConnectivity); void checkCaptivePortal(); + QComHelper comHelper; + ComPtr<QNetworkListManagerEvents> managerEvents; NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED; bool monitoring = false; - bool comInitFailed = false; }; class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory @@ -151,7 +102,7 @@ class QNetworkListManagerNetworkInformationBackendFactory : public QNetworkInfor public: QNetworkListManagerNetworkInformationBackendFactory() = default; ~QNetworkListManagerNetworkInformationBackendFactory() = default; - QString name() const override { return backendName; } + QString name() const override { return backendName(); } QNetworkInformation::Features featuresSupported() const override { return QNetworkListManagerNetworkInformationBackend::featuresSupportedStatic(); @@ -172,182 +123,24 @@ public: } }; -class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents -{ - Q_OBJECT -public: - QNetworkListManagerEvents(); - virtual ~QNetworkListManagerEvents(); - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override; - - ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; } - ULONG STDMETHODCALLTYPE Release() override - { - if (--ref == 0) { - delete this; - return 0; - } - return ref; - } - - HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override; - - [[nodiscard]] bool start(); - bool stop(); - - [[nodiscard]] bool checkBehindCaptivePortal(); - -signals: - void connectivityChanged(NLM_CONNECTIVITY); - -private: - ComPtr<INetworkListManager> networkListManager = nullptr; - ComPtr<IConnectionPoint> connectionPoint = nullptr; - - QAtomicInteger<ULONG> ref = 0; - DWORD cookie = 0; -}; - -QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr) -{ - auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER, - IID_INetworkListManager, &networkListManager); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:" - << errorStringFromHResult(hr); - return; - } - - ComPtr<IConnectionPointContainer> connectionPointContainer; - hr = networkListManager.As(&connectionPointContainer); - if (SUCCEEDED(hr)) { - hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents, - &connectionPoint); - } - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:" - << errorStringFromHResult(hr); - } -} - -QNetworkListManagerEvents::~QNetworkListManagerEvents() -{ - Q_ASSERT(ref == 0); -} - -HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject) -{ - if (!ppvObject) - return E_INVALIDARG; - - return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject) - || QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject) - ? S_OK - : E_NOINTERFACE; -} - -HRESULT STDMETHODCALLTYPE -QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) -{ - // This function is run on a different thread than 'monitor' is created on, so we need to run - // it on that thread - connectivityChanged(newConnectivity); - return S_OK; -} - -bool QNetworkListManagerEvents::start() -{ - if (!connectionPoint) { - qCWarning(lcNetInfoNLM, "Initialization failed, can't start!"); - return false; - } - auto hr = connectionPoint->Advise(this, &cookie); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:" - << errorStringFromHResult(hr); - return false; - } - - // Update connectivity since it might have changed since this class was constructed - NLM_CONNECTIVITY connectivity; - hr = networkListManager->GetConnectivity(&connectivity); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Could not get connectivity:" << errorStringFromHResult(hr); - } else { - emit connectivityChanged(connectivity); - } - return true; -} - -bool QNetworkListManagerEvents::stop() -{ - Q_ASSERT(connectionPoint); - auto hr = connectionPoint->Unadvise(cookie); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:" - << errorStringFromHResult(hr); - return false; - } - cookie = 0; - return true; -} - -bool QNetworkListManagerEvents::checkBehindCaptivePortal() -{ - if (!networkListManager) - return false; - ComPtr<IEnumNetworks> networks; - HRESULT hr = - networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf()); - if (FAILED(hr) || networks == nullptr) - return false; - - // @note: This checks all connected networks, but that might not be necessary - ComPtr<INetwork> network; - hr = networks->Next(1, network.GetAddressOf(), nullptr); - while (SUCCEEDED(hr) && network != nullptr) { - ComPtr<IPropertyBag> propertyBag; - hr = network.As(&propertyBag); - if (SUCCEEDED(hr) && propertyBag != nullptr) { - VARIANT variant; - VariantInit(&variant); - const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); }); - - const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 }; - for (const auto version : versions) { - hr = propertyBag->Read(version, &variant, nullptr); - if (SUCCEEDED(hr) - && (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK) - == NLM_INTERNET_CONNECTIVITY_WEBHIJACK) { - return true; - } - } - } - - hr = networks->Next(1, network.GetAddressOf(), nullptr); - } - - return false; -} - QNetworkListManagerNetworkInformationBackend::QNetworkListManagerNetworkInformationBackend() { - auto hr = CoInitialize(nullptr); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Failed to initialize COM:" << errorStringFromHResult(hr); - comInitFailed = true; + if (!comHelper.isValid()) return; - } + managerEvents = new QNetworkListManagerEvents(); connect(managerEvents.Get(), &QNetworkListManagerEvents::connectivityChanged, this, &QNetworkListManagerNetworkInformationBackend::setConnectivity); + + connect(managerEvents.Get(), &QNetworkListManagerEvents::transportMediumChanged, this, + &QNetworkListManagerNetworkInformationBackend::setTransportMedium); + + connect(managerEvents.Get(), &QNetworkListManagerEvents::isMeteredChanged, this, + &QNetworkListManagerNetworkInformationBackend::setMetered); } QNetworkListManagerNetworkInformationBackend::~QNetworkListManagerNetworkInformationBackend() { - if (comInitFailed) - return; stop(); } @@ -370,11 +163,8 @@ void QNetworkListManagerNetworkInformationBackend::checkCaptivePortal() bool QNetworkListManagerNetworkInformationBackend::event(QEvent *event) { - if (event->type() == QEvent::ThreadChange && monitoring) { - stop(); - QMetaObject::invokeMethod(this, &QNetworkListManagerNetworkInformationBackend::start, - Qt::QueuedConnection); - } + if (event->type() == QEvent::ThreadChange) + qFatal("Moving QNetworkListManagerNetworkInformationBackend to different thread is not supported"); return QObject::event(event); } @@ -383,15 +173,9 @@ bool QNetworkListManagerNetworkInformationBackend::start() { Q_ASSERT(!monitoring); - if (comInitFailed) { - auto hr = CoInitialize(nullptr); - if (FAILED(hr)) { - qCWarning(lcNetInfoNLM) << "Failed to initialize COM:" << errorStringFromHResult(hr); - comInitFailed = true; - return false; - } - comInitFailed = false; - } + if (!comHelper.isValid()) + return false; + if (!managerEvents) managerEvents = new QNetworkListManagerEvents(); @@ -404,14 +188,10 @@ void QNetworkListManagerNetworkInformationBackend::stop() { if (monitoring) { Q_ASSERT(managerEvents); - // Can return false but realistically shouldn't since that would break everything: managerEvents->stop(); monitoring = false; managerEvents.Reset(); } - - CoUninitialize(); - comInitFailed = true; // we check this value in start() to see if we need to re-initialize } QT_END_NAMESPACE |