QNI: transportMedium support for iOS

It can only differentiate between cellular and not cellular
and then we can determine if it's disconnected or (presumably) using
wifi.
It is also explicitly not supported on macOS, which adds to the
confusion.

Task-number: QTBUG-91023
Change-Id: I1d002ba06dd9acf1a0daabfb2a4193c07871e9b4
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Mårten Nordheim 2021-10-18 17:48:36 +02:00
parent f40e0bcf67
commit a6947853ee
3 changed files with 95 additions and 2 deletions

View File

@ -124,6 +124,9 @@ public:
void updateState(SCNetworkReachabilityFlags newState);
void reset();
bool isReachable() const;
#ifdef QT_PLATFORM_UIKIT
bool isWwan() const;
#endif
static void probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info);
@ -139,9 +142,19 @@ void QNetworkConnectionMonitorPrivate::updateState(SCNetworkReachabilityFlags ne
// is set. There are more possible flags that require more tests/some special
// setup. So in future this part and related can change/be extended.
const bool wasReachable = isReachable();
#ifdef QT_PLATFORM_UIKIT
const bool hadWwan = isWwan();
#endif
state = newState;
if (wasReachable != isReachable())
emit q->reachabilityChanged(isReachable());
#ifdef QT_PLATFORM_UIKIT
if (hadWwan != isWwan())
emit q->isWwanChanged(isWwan());
#endif
}
void QNetworkConnectionMonitorPrivate::reset()
@ -160,6 +173,13 @@ bool QNetworkConnectionMonitorPrivate::isReachable() const
return !!(state & kSCNetworkReachabilityFlagsReachable);
}
#ifdef QT_PLATFORM_UIKIT // The IsWWAN flag is not available on macOS
bool QNetworkConnectionMonitorPrivate::isWwan() const
{
return !!(state & kSCNetworkReachabilityFlagsIsWWAN);
}
#endif
void QNetworkConnectionMonitorPrivate::probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info)
{
// To be executed only on the reachability queue.
@ -301,6 +321,25 @@ bool QNetworkConnectionMonitor::isReachable()
return d->isReachable();
}
#ifdef QT_PLATFORM_UIKIT
bool QNetworkConnectionMonitor::isWwan() const
{
Q_D(const QNetworkConnectionMonitor);
if (isMonitoring()) {
qCWarning(lcNetMon, "Calling isReachable() is unsafe after the monitoring started");
return false;
}
if (!d->probe) {
qCWarning(lcNetMon, "Reachability is unknown, set the target first");
return false;
}
return d->isWwan();
}
#endif
bool QNetworkConnectionMonitor::isEnabled()
{
return true;

View File

@ -73,7 +73,11 @@ public:
bool setTargets(const QHostAddress &local, const QHostAddress &remote);
bool isReachable();
// Important: on Darwin you should not call isReachable() after
#ifdef QT_PLATFORM_UIKIT
bool isWwan() const;
#endif
// Important: on Darwin you should not call isReachable/isWwan() after
// startMonitoring(), you have to listen to reachabilityChanged()
// signal instead.
bool startMonitoring();
@ -87,6 +91,10 @@ Q_SIGNALS:
// callback is coming on a special dispatch queue.
void reachabilityChanged(bool isOnline);
#ifdef QT_PLATFORM_UIKIT
void isWwanChanged(bool isWwan);
#endif
private:
Q_DECLARE_PRIVATE(QNetworkConnectionMonitor)
Q_DISABLE_COPY_MOVE(QNetworkConnectionMonitor)

View File

@ -69,12 +69,20 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability);
return QNetworkInformation::Features(QNetworkInformation::Feature::Reachability
#ifdef QT_PLATFORM_UIKIT
| QNetworkInformation::Feature::TransportMedium
#endif
);
}
private Q_SLOTS:
void reachabilityChanged(bool isOnline);
#ifdef QT_PLATFORM_UIKIT
void isWwanChanged(bool isOnline);
#endif
private:
Q_DISABLE_COPY_MOVE(QSCNetworkReachabilityNetworkInformationBackend);
@ -110,10 +118,16 @@ private:
QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkInformationBackend()
{
bool isOnline = false;
#ifdef QT_PLATFORM_UIKIT
bool isWwan = false;
#endif
if (ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
// We manage to create SCNetworkReachabilityRef for IPv4, let's
// read the last known state then!
isOnline |= ipv4Probe.isReachable();
#ifdef QT_PLATFORM_UIKIT
isWwan |= ipv4Probe.isWwan();
#endif
ipv4Probe.startMonitoring();
}
@ -121,9 +135,15 @@ QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkIn
// We manage to create SCNetworkReachability ref for IPv6, let's
// read the last known state then!
isOnline |= ipv6Probe.isReachable();
#ifdef QT_PLATFORM_UIKIT
isWwan |= ipv6Probe.isWwan();
#endif
ipv6Probe.startMonitoring();
}
reachabilityChanged(isOnline);
#ifdef QT_PLATFORM_UIKIT
isWwanChanged(isWwan);
#endif
connect(&ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
@ -131,6 +151,15 @@ QSCNetworkReachabilityNetworkInformationBackend::QSCNetworkReachabilityNetworkIn
connect(&ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged,
Qt::QueuedConnection);
#ifdef QT_PLATFORM_UIKIT
connect(&ipv4Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
Qt::QueuedConnection);
connect(&ipv6Probe, &QNetworkConnectionMonitor::isWwanChanged, this,
&QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged,
Qt::QueuedConnection);
#endif
}
QSCNetworkReachabilityNetworkInformationBackend::~QSCNetworkReachabilityNetworkInformationBackend()
@ -143,6 +172,23 @@ void QSCNetworkReachabilityNetworkInformationBackend::reachabilityChanged(bool i
: QNetworkInformation::Reachability::Disconnected);
}
#ifdef QT_PLATFORM_UIKIT
void QSCNetworkReachabilityNetworkInformationBackend::isWwanChanged(bool isWwan)
{
// The reachability API from Apple only has one entry regarding transport medium: "IsWWAN"[0].
// This is _serviceable_ on iOS where the only other credible options are "WLAN" or
// "Disconnected". But on macOS you could be connected by Ethernet as well, so how would that be
// reported? It doesn't matter anyway since "IsWWAN" is not available on macOS.
// [0]: https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityflags/kscnetworkreachabilityflagsiswwan?language=objc
if (reachability() == QNetworkInformation::Reachability::Disconnected) {
setTransportMedium(QNetworkInformation::TransportMedium::Unknown);
} else {
setTransportMedium(isWwan ? QNetworkInformation::TransportMedium::Cellular
: QNetworkInformation::TransportMedium::WiFi);
}
}
#endif
QT_END_NAMESPACE
#include "qscnetworkreachabilitynetworkinformationbackend.moc"