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(
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;
95 QUuid currentConnectionId{};
123 QComHelper comHelper;
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);
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);
171 auto hr = networkListManager->GetNetworkConnections(connections.GetAddressOf());
173 qCDebug(lcNetMon) <<
"Failed to enumerate network connections:"
174 << QSystemError::windowsComString(hr);
179 hr = connections->Next(1,
connection.GetAddressOf(),
nullptr);
181 qCDebug(lcNetMon) <<
"Failed to get next network connection in enumeration:"
182 << QSystemError::windowsComString(hr);
189 qCDebug(lcNetMon) <<
"Failed to get adapter ID from network connection:"
190 << QSystemError::windowsComString(hr);
193 if (guid == adapterId)
205 return QueryInterfaceImpl<IUnknown>(
this,
riid, ppvObject)
206 || QueryInterfaceImpl<INetworkConnectionEvents>(
this,
riid, ppvObject)
212 GUID connectionId, NLM_CONNECTIVITY newConnectivity)
217 [
this, connectionId, newConnectivity, monitor =
this->monitor]() {
218 if (connectionId == currentConnectionId)
219 monitor->setConnectivity(newConnectivity);
226 GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE
flags)
236 currentConnectionId =
QUuid{};
239 if (ConvertInterfaceIndexToLuid(iface.index(), &luid) != NO_ERROR) {
240 qCDebug(lcNetMon,
"Could not get the LUID for the interface.");
244 if (ConvertInterfaceLuidToGuid(&luid, &guid) != NO_ERROR) {
245 qCDebug(lcNetMon,
"Could not get the GUID for the interface.");
250 qCDebug(lcNetMon,
"Could not get the INetworkConnection instance for the adapter GUID.");
255 qCDebug(lcNetMon) <<
"Failed to get the connection's GUID:"
256 << QSystemError::windowsComString(hr);
259 currentConnectionId = guid;
266 if (currentConnectionId.
isNull()) {
267 qCDebug(lcNetMon,
"Can not start monitoring, set targets first");
270 if (!connectionPoint) {
272 "We don't have the connection point, cannot start listening to events!");
276 auto hr = connectionPoint->Advise(
this, &cookie);
278 qCDebug(lcNetMon) <<
"Failed to subscribe to network connectivity events:"
279 << QSystemError::windowsComString(hr);
287 auto hr = connectionPoint->Unadvise(cookie);
289 qCDebug(lcNetMon) <<
"Failed to unsubscribe from network connection events:"
290 << QSystemError::windowsComString(hr);
294 currentConnectionId =
QUuid{};
300 if (!comHelper.isValid())
308 if (!comHelper.isValid())
312 connectionEvents.Reset();
318 if (!comHelper.isValid())
322 if (!iface.isValid())
324 const auto &addressEntries = iface.addressEntries();
325 auto it = std::find_if(
326 addressEntries.cbegin(), addressEntries.cend(),
329 qCDebug(lcNetMon,
"The address entry we were working with disappeared");
332 sameSubnet = remote.
isInSubnet(local,
it->prefixLength());
336 return connectionEvents->setTarget(iface);
342 const bool reachable =
q->isReachable();
343 connectivity = newConnectivity;
344 const bool newReachable =
q->isReachable();
345 if (reachable != newReachable)
346 emit q->reachabilityChanged(newReachable);
353 if (connectionEvents->startMonitoring())
362 if (connectionEvents->stopMonitoring())
383 qCDebug(lcNetMon,
"Monitor is already active, call stopMonitoring() first");
387 qCDebug(lcNetMon,
"Invalid (null) local address, cannot create a reachability target");
394 return d_func()->setTargets(local, remote);
401 qCDebug(lcNetMon,
"Monitor is already active, call stopMonitoring() first");
404 return d->startMonitoring();
409 return d_func()->monitoring;
416 qCDebug(lcNetMon,
"stopMonitoring was called when not monitoring!");
426 const NLM_CONNECTIVITY RequiredSameSubnetIPv6 =
427 NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV6_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK
428 | NLM_CONNECTIVITY_IPV6_INTERNET);
429 const NLM_CONNECTIVITY RequiredSameSubnetIPv4 =
430 NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV4_LOCALNETWORK
431 | NLM_CONNECTIVITY_IPV4_INTERNET);
433 NLM_CONNECTIVITY required;
434 if (
d->isLinkLocal) {
435 required = NLM_CONNECTIVITY(
436 d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_NOTRAFFIC | RequiredSameSubnetIPv6
437 : NLM_CONNECTIVITY_IPV4_NOTRAFFIC | RequiredSameSubnetIPv4);
438 }
else if (
d->sameSubnet) {
440 NLM_CONNECTIVITY(
d->remoteIsIPv6 ? RequiredSameSubnetIPv6 : RequiredSameSubnetIPv4);
443 required = NLM_CONNECTIVITY(
d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET
444 : NLM_CONNECTIVITY_IPV4_INTERNET);
447 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.
const_iterator cend() const noexcept
const_iterator cbegin() const noexcept
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