6#include "private/qobject_p.h"
8#include <QtCore/quuid.h>
9#include <QtCore/qmetaobject.h>
11#include <QtCore/private/qfunctions_win_p.h>
12#include <QtCore/private/qsystemerror_p.h>
14#include <QtNetwork/qnetworkinterface.h>
17#include <netlistmgr.h>
18#include <wrl/client.h>
19#include <wrl/wrappers/corewrappers.h>
32bool QueryInterfaceImpl(IUnknown *from, REFIID
riid,
void **ppvObject)
34 if (
riid == __uuidof(T)) {
35 *ppvObject =
static_cast<T *
>(from);
45 auto it = std::find_if(
46 interfaces.cbegin(), interfaces.cend(), [&local](
const QNetworkInterface &iface) {
47 const auto &entries = iface.addressEntries();
48 return std::any_of(entries.cbegin(), entries.cend(),
49 [&local](const QNetworkAddressEntry &entry) {
50 return entry.ip().isEqual(local,
51 QHostAddress::TolerantConversion);
54 if (
it == interfaces.
cend()) {
55 qCDebug(lcNetMon,
"Could not find the interface for the local address.");
70 ULONG STDMETHODCALLTYPE
AddRef()
override {
return ++
ref; }
71 ULONG STDMETHODCALLTYPE
Release()
override
83 GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE
flags)
override;
93 ComPtr<INetworkConnection> getNetworkConnectionFromAdapterGuid(
QUuid guid);
95 QUuid currentConnectionId{};
97 ComPtr<INetworkListManager> networkListManager;
98 ComPtr<IConnectionPoint> connectionPoint;
102 QAtomicInteger<ULONG>
ref = 0;
123 QComHelper comHelper;
125 ComPtr<QNetworkConnectionEvents> connectionEvents;
128 NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY(
129 NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET
130 | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET
131 | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK
132 | NLM_CONNECTIVITY_IPV4_NOTRAFFIC | NLM_CONNECTIVITY_IPV6_NOTRAFFIC);
134 bool sameSubnet =
false;
135 bool isLinkLocal =
false;
136 bool monitoring =
false;
137 bool remoteIsIPv6 =
false;
143 auto hr = CoCreateInstance(CLSID_NetworkListManager,
nullptr, CLSCTX_INPROC_SERVER,
144 IID_INetworkListManager, &networkListManager);
146 qCDebug(lcNetMon) <<
"Could not get a NetworkListManager instance:"
147 << QSystemError::windowsComString(hr);
151 ComPtr<IConnectionPointContainer> connectionPointContainer;
152 hr = networkListManager.As(&connectionPointContainer);
154 hr = connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents,
158 qCDebug(lcNetMon) <<
"Failed to get connection point for network events:"
159 << QSystemError::windowsComString(hr);
168ComPtr<INetworkConnection> QNetworkConnectionEvents::getNetworkConnectionFromAdapterGuid(
QUuid guid)
170 if (!networkListManager) {
171 qCDebug(lcNetMon) <<
"Failed to enumerate network connections:"
172 <<
"NetworkListManager was not instantiated";
176 ComPtr<IEnumNetworkConnections> connections;
177 auto hr = networkListManager->GetNetworkConnections(connections.GetAddressOf());
179 qCDebug(lcNetMon) <<
"Failed to enumerate network connections:"
180 << QSystemError::windowsComString(hr);
183 ComPtr<INetworkConnection>
connection =
nullptr;
185 hr = connections->Next(1,
connection.GetAddressOf(),
nullptr);
187 qCDebug(lcNetMon) <<
"Failed to get next network connection in enumeration:"
188 << QSystemError::windowsComString(hr);
195 qCDebug(lcNetMon) <<
"Failed to get adapter ID from network connection:"
196 << QSystemError::windowsComString(hr);
199 if (guid == adapterId)
211 return QueryInterfaceImpl<IUnknown>(
this,
riid, ppvObject)
212 || QueryInterfaceImpl<INetworkConnectionEvents>(
this,
riid, ppvObject)
218 GUID connectionId, NLM_CONNECTIVITY newConnectivity)
223 [
this, connectionId, newConnectivity, monitor =
this->monitor]() {
224 if (connectionId == currentConnectionId)
225 monitor->setConnectivity(newConnectivity);
232 GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE
flags)
242 currentConnectionId =
QUuid{};
245 if (ConvertInterfaceIndexToLuid(iface.index(), &luid) != NO_ERROR) {
246 qCDebug(lcNetMon,
"Could not get the LUID for the interface.");
250 if (ConvertInterfaceLuidToGuid(&luid, &guid) != NO_ERROR) {
251 qCDebug(lcNetMon,
"Could not get the GUID for the interface.");
254 ComPtr<INetworkConnection>
connection = getNetworkConnectionFromAdapterGuid(guid);
256 qCDebug(lcNetMon,
"Could not get the INetworkConnection instance for the adapter GUID.");
261 qCDebug(lcNetMon) <<
"Failed to get the connection's GUID:"
262 << QSystemError::windowsComString(hr);
265 currentConnectionId = guid;
272 if (currentConnectionId.
isNull()) {
273 qCDebug(lcNetMon,
"Can not start monitoring, set targets first");
276 if (!connectionPoint) {
278 "We don't have the connection point, cannot start listening to events!");
282 auto hr = connectionPoint->Advise(
this, &cookie);
284 qCDebug(lcNetMon) <<
"Failed to subscribe to network connectivity events:"
285 << QSystemError::windowsComString(hr);
293 auto hr = connectionPoint->Unadvise(cookie);
295 qCDebug(lcNetMon) <<
"Failed to unsubscribe from network connection events:"
296 << QSystemError::windowsComString(hr);
300 currentConnectionId =
QUuid{};
306 if (!comHelper.isValid())
314 if (!comHelper.isValid())
318 connectionEvents.Reset();
324 if (!comHelper.isValid())
328 if (!iface.isValid())
330 const auto &addressEntries = iface.addressEntries();
331 auto it = std::find_if(
332 addressEntries.cbegin(), addressEntries.cend(),
335 qCDebug(lcNetMon,
"The address entry we were working with disappeared");
338 sameSubnet = remote.
isInSubnet(local,
it->prefixLength());
342 return connectionEvents->setTarget(iface);
348 const bool reachable =
q->isReachable();
349 connectivity = newConnectivity;
350 const bool newReachable =
q->isReachable();
351 if (reachable != newReachable)
352 emit q->reachabilityChanged(newReachable);
359 if (connectionEvents->startMonitoring())
368 if (connectionEvents->stopMonitoring())
389 qCDebug(lcNetMon,
"Monitor is already active, call stopMonitoring() first");
393 qCDebug(lcNetMon,
"Invalid (null) local address, cannot create a reachability target");
400 return d_func()->setTargets(local, remote);
407 qCDebug(lcNetMon,
"Monitor is already active, call stopMonitoring() first");
410 return d->startMonitoring();
415 return d_func()->monitoring;
422 qCDebug(lcNetMon,
"stopMonitoring was called when not monitoring!");
432 const NLM_CONNECTIVITY RequiredSameSubnetIPv6 =
433 NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV6_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK
434 | NLM_CONNECTIVITY_IPV6_INTERNET);
435 const NLM_CONNECTIVITY RequiredSameSubnetIPv4 =
436 NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV4_LOCALNETWORK
437 | NLM_CONNECTIVITY_IPV4_INTERNET);
439 NLM_CONNECTIVITY required;
440 if (
d->isLinkLocal) {
441 required = NLM_CONNECTIVITY(
442 d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_NOTRAFFIC | RequiredSameSubnetIPv6
443 : NLM_CONNECTIVITY_IPV4_NOTRAFFIC | RequiredSameSubnetIPv4);
444 }
else if (
d->sameSubnet) {
446 NLM_CONNECTIVITY(
d->remoteIsIPv6 ? RequiredSameSubnetIPv6 : RequiredSameSubnetIPv4);
449 required = NLM_CONNECTIVITY(
d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET
450 : NLM_CONNECTIVITY_IPV4_INTERNET);
453 return d_func()->connectivity & required;
static constexpr auto IPv6Protocol
The QHostAddress class provides an IP address.
bool isNull() const
Returns true if this host address is not valid for any host or interface.
bool isInSubnet(const QHostAddress &subnet, int netmask) const
NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
HRESULT STDMETHODCALLTYPE NetworkConnectionPropertyChanged(GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE flags) override
HRESULT STDMETHODCALLTYPE NetworkConnectionConnectivityChanged(GUID connectionId, NLM_CONNECTIVITY connectivity) override
virtual ~QNetworkConnectionEvents()
ULONG STDMETHODCALLTYPE Release() override
bool setTarget(const QNetworkInterface &iface)
QNetworkConnectionEvents(QNetworkConnectionMonitorPrivate *monitor)
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override
ULONG STDMETHODCALLTYPE AddRef() override
bool setTargets(const QHostAddress &local, const QHostAddress &remote)
~QNetworkConnectionMonitorPrivate()
QNetworkConnectionMonitorPrivate()
void setConnectivity(NLM_CONNECTIVITY newConnectivity)
bool isMonitoring() const
bool setTargets(const QHostAddress &local, const QHostAddress &remote)
~QNetworkConnectionMonitor()
QNetworkConnectionMonitor()
The QNetworkInterface class provides a listing of the host's IP addresses and network interfaces.
static QList< QNetworkInterface > allInterfaces()
Returns a listing of all the network interfaces found on the host machine.
const_iterator cend() const noexcept
bool isNull() const noexcept
Returns true if this is the null UUID {00000000-0000-0000-0000-000000000000}; otherwise returns false...
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection * connection
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLdouble GLdouble GLdouble GLdouble q
IUIViewSettingsInterop __RPC__in REFIID riid