summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2019-03-15 12:05:38 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2019-05-02 05:07:39 +0000
commit402cb62d5db7516e4d8d77d972e55e90cb855679 (patch)
treeb5f67fd4164cead23d0f041cd9e5cd454563ea3d /src
parent355ecfb11c838b4c9facc9a631e04a52531a2127 (diff)
Introduce QNetworkConnection/Status/Monitor
Private classes to replace broken or even not working at all 'session management' and 'bearer manager' (on at least two major platforms we support). This implementation is macOS/iOS-specific and uses SystemConfiguration framework, or more precisely SCNetworkReachability's part of it. Task-number: QTBUG-40332 Change-Id: Iac5f44c4063c4092b93b8cf2bde3fb2c524855b3 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp38
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h13
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp12
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp153
-rw-r--r--src/network/access/qnetworkaccessmanager.h2
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h8
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp15
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp2
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h2
-rw-r--r--src/network/kernel/kernel.pri12
-rw-r--r--src/network/kernel/qnetconmonitor_darwin.mm434
-rw-r--r--src/network/kernel/qnetconmonitor_p.h126
-rw-r--r--src/network/kernel/qnetconmonitor_stub.cpp141
13 files changed, 903 insertions, 55 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 0a37122fc6..cb4c722eb5 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -1320,6 +1320,10 @@ QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16
Q_D(QHttpNetworkConnection);
d->networkSession = std::move(networkSession);
d->init();
+ if (QNetworkStatusMonitor::isEnabled()) {
+ connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
+ this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
+ }
}
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
@@ -1332,6 +1336,10 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS
Q_D(QHttpNetworkConnection);
d->networkSession = std::move(networkSession);
d->init();
+ if (QNetworkStatusMonitor::isEnabled()) {
+ connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
+ this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
+ }
}
#else
QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt,
@@ -1340,6 +1348,10 @@ QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16
{
Q_D(QHttpNetworkConnection);
d->init();
+ if (QNetworkStatusMonitor::isEnabled()) {
+ connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
+ this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
+ }
}
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
@@ -1350,8 +1362,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS
{
Q_D(QHttpNetworkConnection);
d->init();
+ if (QNetworkStatusMonitor::isEnabled()) {
+ connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
+ this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
+ }
}
-#endif
+#endif // QT_NO_BEARERMANAGEMENT
QHttpNetworkConnection::~QHttpNetworkConnection()
{
@@ -1531,6 +1547,26 @@ void QHttpNetworkConnection::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
+void QHttpNetworkConnection::onlineStateChanged(bool isOnline)
+{
+ Q_D(QHttpNetworkConnection);
+
+ if (isOnline) {
+ // If we did not have any 'isOffline' previously - well, good
+ // to know, we are 'online' apparently.
+ return;
+ }
+
+ for (int i = 0; i < d->activeChannelCount; i++) {
+ auto &channel = d->channels[i];
+ channel.emitFinishedWithError(QNetworkReply::TemporaryNetworkFailureError, "Temporary network failure.");
+ channel.close();
+ }
+
+ // We don't care, this connection is broken from our POV.
+ d->connectionMonitor.stopMonitoring();
+}
+
#ifndef QT_NO_NETWORKPROXY
// only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not
// from QHttpNetworkConnectionChannel::handleAuthenticationChallenge
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 2f3c334248..85d89f20c2 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -67,6 +67,7 @@
#include <private/qhttpnetworkheader_p.h>
#include <private/qhttpnetworkrequest_p.h>
#include <private/qhttpnetworkreply_p.h>
+#include <private/qnetconmonitor_p.h>
#include <private/http2protocol_p.h>
#include <private/qhttpnetworkconnectionchannel_p.h>
@@ -156,6 +157,10 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
+
+public slots:
+ void onlineStateChanged(bool isOnline);
+
private:
Q_DECLARE_PRIVATE(QHttpNetworkConnection)
Q_DISABLE_COPY_MOVE(QHttpNetworkConnection)
@@ -292,6 +297,14 @@ public:
Http2::ProtocolParameters http2Parameters;
QString peerVerifyName;
+ // If network status monitoring is enabled, we activate connectionMonitor
+ // as soons as one of channels managed to connect to host (and we
+ // have a pair of addresses (us,peer).
+ // NETMONTODO: consider activating a monitor on a change from
+ // HostLookUp state to ConnectingState (means we have both
+ // local/remote addresses known and can start monitoring this
+ // early).
+ QNetworkConnectionMonitor connectionMonitor;
friend class QHttpNetworkConnectionChannel;
};
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index f79a4d1dc6..9309d718e4 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -59,6 +59,8 @@
#include "private/qnetworksession_p.h"
#endif
+#include "private/qnetconmonitor_p.h"
+
QT_BEGIN_NAMESPACE
namespace
@@ -896,6 +898,16 @@ void QHttpNetworkConnectionChannel::_q_connected()
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
+ if (QNetworkStatusMonitor::isEnabled()) {
+ auto connectionPrivate = connection->d_func();
+ if (!connectionPrivate->connectionMonitor.isMonitoring()) {
+ // Now that we have a pair of addresses, we can start monitoring the
+ // connection status to handle its loss properly.
+ if (connectionPrivate->connectionMonitor.setTargets(socket->localAddress(), socket->peerAddress()))
+ connectionPrivate->connectionMonitor.startMonitoring();
+ }
+ }
+
// ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
//channels[i].reconnectAttempts = 2;
if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 50b9488594..8bd630ad9d 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -90,6 +90,8 @@
#include "qnetworkreplywasmimpl_p.h"
#endif
+#include "qnetconmonitor_p.h"
+
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
@@ -486,18 +488,25 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
qRegisterMetaType<QNetworkReply::NetworkError>();
qRegisterMetaType<QSharedPointer<char> >();
-#ifndef QT_NO_BEARERMANAGEMENT
Q_D(QNetworkAccessManager);
- // if a session is required, we track online state through
- // the QNetworkSession's signals if a request is already made.
- // we need to track current accessibility state by default
- //
- connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
- SLOT(_q_onlineStateChanged(bool)));
- connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)),
- SLOT(_q_configurationChanged(QNetworkConfiguration)));
-
-#endif
+ if (QNetworkStatusMonitor::isEnabled()) {
+ connect(&d->statusMonitor, SIGNAL(onlineStateChanged(bool)),
+ SLOT(_q_onlineStateChanged(bool)));
+#ifdef QT_NO_BEARERMANAGEMENT
+ d->networkAccessible = d->statusMonitor.isNetworkAccesible();
+#else
+ d->networkAccessible = d->statusMonitor.isNetworkAccesible() ? Accessible : NotAccessible;
+ } else {
+ // if a session is required, we track online state through
+ // the QNetworkSession's signals if a request is already made.
+ // we need to track current accessibility state by default
+ //
+ connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
+ SLOT(_q_onlineStateChanged(bool)));
+ connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)),
+ SLOT(_q_configurationChanged(QNetworkConfiguration)));
+#endif // QT_NO_BEARERMANAGEMENT
+ }
}
/*!
@@ -1030,9 +1039,13 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ
void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
{
Q_D(QNetworkAccessManager);
- d->networkConfiguration = config;
- d->customNetworkConfiguration = true;
- d->createSession(config);
+ if (!d->statusMonitor.isEnabled()) {
+ d->networkConfiguration = config;
+ d->customNetworkConfiguration = true;
+ d->createSession(config);
+ } else {
+ qWarning(lcNetMon, "No network configuration can be set with network status monitor enabled");
+ }
}
/*!
@@ -1048,7 +1061,7 @@ QNetworkConfiguration QNetworkAccessManager::configuration() const
Q_D(const QNetworkAccessManager);
QSharedPointer<QNetworkSession> session(d->getNetworkSession());
- if (session) {
+ if (session && !d->statusMonitor.isEnabled()) {
return session->configuration();
} else {
return d->networkConfigurationManager.defaultConfiguration();
@@ -1075,7 +1088,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
Q_D(const QNetworkAccessManager);
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
- if (networkSession) {
+ if (networkSession && !d->statusMonitor.isEnabled()) {
return d->networkConfigurationManager.configurationFromIdentifier(
networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
} else {
@@ -1094,6 +1107,11 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
{
Q_D(QNetworkAccessManager);
+ if (d->statusMonitor.isEnabled()) {
+ qWarning(lcNetMon, "Can not manually set network accessibility with the network status monitor enabled");
+ return;
+ }
+
d->defaultAccessControl = accessible == NotAccessible ? false : true;
if (d->networkAccessible != accessible) {
@@ -1114,6 +1132,12 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
{
Q_D(const QNetworkAccessManager);
+ if (d->statusMonitor.isEnabled()) {
+ if (!d->statusMonitor.isMonitoring())
+ d->statusMonitor.start();
+ return d->networkAccessible;
+ }
+
if (d->customNetworkConfiguration && d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
return UnknownAccessibility;
@@ -1434,35 +1458,57 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
}
-#ifndef QT_NO_BEARERMANAGEMENT
+ if (d->statusMonitor.isEnabled()) {
+ // See the code in ctor - QNetworkStatusMonitor allows us to
+ // immediately set 'networkAccessible' even before we start
+ // the monitor.
+#ifdef QT_NO_BEARERMANAGEMENT
+ if (d->networkAccessible
+#else
+ if (d->networkAccessible == NotAccessible
+#endif // QT_NO_BEARERMANAGEMENT
+ && !isLocalFile) {
+ QHostAddress dest;
+ QString host = req.url().host().toLower();
+ if (!(dest.setAddress(host) && dest.isLoopback())
+ && host != QLatin1String("localhost")
+ && host != QHostInfo::localHostName().toLower()) {
+ return new QDisabledNetworkReply(this, req, op);
+ }
+ }
- // Return a disabled network reply if network access is disabled.
- // Except if the scheme is empty or file:// or if the host resolves to a loopback address.
- if (d->networkAccessible == NotAccessible && !isLocalFile) {
- QHostAddress dest;
- QString host = req.url().host().toLower();
- if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost")
+ if (!d->statusMonitor.isMonitoring() && !d->statusMonitor.start())
+ qWarning(lcNetMon, "failed to start network status monitoring");
+ } else {
+#ifndef QT_NO_BEARERMANAGEMENT
+ // Return a disabled network reply if network access is disabled.
+ // Except if the scheme is empty or file:// or if the host resolves to a loopback address.
+ if (d->networkAccessible == NotAccessible && !isLocalFile) {
+ QHostAddress dest;
+ QString host = req.url().host().toLower();
+ if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost")
&& host != QHostInfo::localHostName().toLower()) {
- return new QDisabledNetworkReply(this, req, op);
+ return new QDisabledNetworkReply(this, req, op);
+ }
}
- }
- if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) {
- if (!d->networkConfiguration.identifier().isEmpty()) {
- if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined)
- && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration())
- d->createSession(d->networkConfigurationManager.defaultConfiguration());
- else
- d->createSession(d->networkConfiguration);
+ if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) {
+ if (!d->networkConfiguration.identifier().isEmpty()) {
+ if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined)
+ && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration())
+ d->createSession(d->networkConfigurationManager.defaultConfiguration());
+ else
+ d->createSession(d->networkConfiguration);
- } else {
- if (d->networkSessionRequired)
- d->createSession(d->networkConfigurationManager.defaultConfiguration());
- else
- d->initializeSession = false;
+ } else {
+ if (d->networkSessionRequired)
+ d->createSession(d->networkConfigurationManager.defaultConfiguration());
+ else
+ d->initializeSession = false;
+ }
}
- }
#endif
+ }
QNetworkRequest request = req;
if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
@@ -1509,8 +1555,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
#endif
QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
#ifndef QT_NO_BEARERMANAGEMENT
- connect(this, SIGNAL(networkSessionConnected()),
- reply, SLOT(_q_networkSessionConnected()));
+ if (!d->statusMonitor.isEnabled()) {
+ connect(this, SIGNAL(networkSessionConnected()),
+ reply, SLOT(_q_networkSessionConnected()));
+ }
#endif
return reply;
}
@@ -1519,7 +1567,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
// first step: create the reply
QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
#ifndef QT_NO_BEARERMANAGEMENT
- if (!isLocalFile) {
+ // NETMONTODO: network reply impl must be augmented to use the same monitoring
+ // capabilities as http network reply impl does.
+ if (!isLocalFile && !d->statusMonitor.isEnabled()) {
connect(this, SIGNAL(networkSessionConnected()),
reply, SLOT(_q_networkSessionConnected()));
}
@@ -1988,7 +2038,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
{
- Q_Q(QNetworkAccessManager);
+ Q_Q(QNetworkAccessManager);
+
+ if (statusMonitor.isEnabled()) {
+ networkAccessible = isOnline ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible;
+ return;
+ }
+
// if the user set a config, we only care whether this one is active.
// Otherwise, this QNAM is online if there is an online config.
@@ -2018,6 +2074,9 @@ void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfiguration &configuration)
{
+ if (statusMonitor.isEnabled())
+ return;
+
const QString id = configuration.identifier();
if (configuration.state().testFlag(QNetworkConfiguration::Active)) {
if (!onlineConfigurations.contains(id)) {
@@ -2050,6 +2109,9 @@ void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfigu
void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::SessionError)
{
+ if (statusMonitor.isEnabled())
+ return;
+
const auto cfgs = networkConfigurationManager.allConfigurations();
for (const QNetworkConfiguration &cfg : cfgs) {
if (cfg.state().testFlag(QNetworkConfiguration::Active)) {
@@ -2061,6 +2123,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::Sess
}
}
+#else
+
+void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
+{
+ networkAccessible = isOnline;
+}
+
#endif // QT_NO_BEARERMANAGEMENT
#if QT_CONFIG(http)
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 7e2f7683d0..fa23537c68 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -209,10 +209,10 @@ private:
#ifndef QT_NO_BEARERMANAGEMENT
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed())
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State))
- Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool))
Q_PRIVATE_SLOT(d_func(), void _q_configurationChanged(const QNetworkConfiguration &))
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed(QNetworkSession::SessionError))
#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool))
};
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index 5cab4928e4..d3a3936533 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -55,6 +55,7 @@
#include "qnetworkaccessmanager.h"
#include "qnetworkaccesscache_p.h"
#include "qnetworkaccessbackend_p.h"
+#include "qnetconmonitor_p.h"
#include "qnetworkrequest.h"
#include "qhsts_p.h"
#include "private/qobject_p.h"
@@ -151,6 +152,7 @@ public:
QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request);
QStringList backendSupportedSchemes() const;
+ void _q_onlineStateChanged(bool isOnline);
#ifndef QT_NO_BEARERMANAGEMENT
void createSession(const QNetworkConfiguration &config);
QSharedPointer<QNetworkSession> getNetworkSession() const;
@@ -160,12 +162,11 @@ public:
void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config,
bool isSeamless);
void _q_networkSessionStateChanged(QNetworkSession::State state);
- void _q_onlineStateChanged(bool isOnline);
+
void _q_configurationChanged(const QNetworkConfiguration &configuration);
void _q_networkSessionFailed(QNetworkSession::SessionError error);
QSet<QString> onlineConfigurations;
-
#endif
#if QT_CONFIG(http)
@@ -199,6 +200,8 @@ public:
int activeReplyCount;
bool online;
bool initializeSession;
+#else
+ bool networkAccessible = true;
#endif
bool cookieJarCreated;
@@ -222,6 +225,7 @@ public:
QScopedPointer<QHstsStore> stsStore;
#endif // QT_CONFIG(settings)
bool stsEnabled = false;
+ mutable QNetworkStatusMonitor statusMonitor;
#ifndef QT_NO_BEARERMANAGEMENT
Q_AUTOTEST_EXPORT static const QWeakPointer<const QNetworkSession> getNetworkSession(const QNetworkAccessManager *manager);
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index f801ef0c88..b9651b35d2 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -59,6 +59,7 @@
#include <QtCore/private/qthread_p.h>
#include "qnetworkcookiejar.h"
+#include "qnetconmonitor_p.h"
#include <string.h> // for strchr
@@ -166,6 +167,11 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
#if QT_CONFIG(bearermanagement)
static bool isSessionNeeded(const QUrl &url)
{
+ if (QNetworkStatusMonitor::isEnabled()) {
+ // In case QNetworkStatus/QNetConManager are in business,
+ // no session, no bearer manager are involved.
+ return false;
+ }
// Connections to the local machine does not require a session
QString host = url.host().toLower();
return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost")
@@ -796,7 +802,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (blob.isValid() && blob.canConvert<Http2::ProtocolParameters>())
delegate->http2Parameters = blob.value<Http2::ProtocolParameters>();
#ifndef QT_NO_BEARERMANAGEMENT
- delegate->networkSession = managerPrivate->getNetworkSession();
+ if (!QNetworkStatusMonitor::isEnabled())
+ delegate->networkSession = managerPrivate->getNetworkSession();
#endif
// For the synchronous HTTP, this is the normal way the delegate gets deleted
@@ -1807,7 +1814,7 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
{
#ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession(managerPrivate->getNetworkSession());
- if (!networkSession) {
+ if (!networkSession || QNetworkStatusMonitor::isEnabled()) {
#endif
postRequest(newHttpRequest);
return true;
@@ -1895,7 +1902,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
// state changes.
if (!startWaitForSession(session))
return;
- } else if (session) {
+ } else if (session && !QNetworkStatusMonitor::isEnabled()) {
QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)),
Qt::QueuedConnection);
@@ -2184,7 +2191,7 @@ void QNetworkReplyHttpImplPrivate::finished()
#ifndef QT_NO_BEARERMANAGEMENT
Q_ASSERT(managerPrivate);
QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
- if (session && session->state() == QNetworkSession::Roaming &&
+ if (!QNetworkStatusMonitor::isEnabled() && session && session->state() == QNetworkSession::Roaming &&
state == Working && errorCode != QNetworkReply::OperationCanceledError) {
// only content with a known size will fail with a temporary network failure error
if (!totalSize.isNull()) {
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index f5bb4d5887..1a02938de9 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -1117,7 +1117,6 @@ bool QNetworkReplyImplPrivate::migrateBackend()
return true;
}
-#ifndef QT_NO_BEARERMANAGEMENT
QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
const QNetworkRequest &req,
QNetworkAccessManager::Operation op)
@@ -1142,7 +1141,6 @@ QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
QDisabledNetworkReply::~QDisabledNetworkReply()
{
}
-#endif
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 4881e84e9c..85f5b862a8 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -209,7 +209,6 @@ public:
};
Q_DECLARE_TYPEINFO(QNetworkReplyImplPrivate::InternalNotifications, Q_PRIMITIVE_TYPE);
-#ifndef QT_NO_BEARERMANAGEMENT
class QDisabledNetworkReply : public QNetworkReply
{
Q_OBJECT
@@ -223,7 +222,6 @@ public:
protected:
qint64 readData(char *, qint64) override { return -1; }
};
-#endif
QT_END_NAMESPACE
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index b86119b200..0e4cef5e74 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -16,7 +16,8 @@ HEADERS += kernel/qtnetworkglobal.h \
kernel/qnetworkinterface.h \
kernel/qnetworkinterface_p.h \
kernel/qnetworkinterface_unix_p.h \
- kernel/qnetworkproxy.h
+ kernel/qnetworkproxy.h \
+ kernel/qnetconmonitor_p.h
SOURCES += kernel/qauthenticator.cpp \
kernel/qhostaddress.cpp \
@@ -71,6 +72,15 @@ mac {
!uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration
}
+macos | ios {
+ OBJECTIVE_SOURCES += \
+ kernel/qnetconmonitor_darwin.mm
+
+ LIBS_PRIVATE += -framework SystemConfiguration
+} else {
+ SOURCES += kernel/qnetconmonitor_stub.cpp
+}
+
qtConfig(gssapi): LIBS_PRIVATE += -lgssapi_krb5
uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h
diff --git a/src/network/kernel/qnetconmonitor_darwin.mm b/src/network/kernel/qnetconmonitor_darwin.mm
new file mode 100644
index 0000000000..322c87cb4b
--- /dev/null
+++ b/src/network/kernel/qnetconmonitor_darwin.mm
@@ -0,0 +1,434 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "private/qnativesocketengine_p.h"
+#include "private/qnetconmonitor_p.h"
+
+#include "private/qobject_p.h"
+
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <netinet/in.h>
+
+#include <cstring>
+#include <mutex>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor");
+
+namespace {
+
+class ReachabilityDispatchQueue
+{
+public:
+ ReachabilityDispatchQueue()
+ {
+ queue = dispatch_queue_create("qt-network-reachability-queue", nullptr);
+ if (!queue)
+ qCWarning(lcNetMon, "Failed to create a dispatch queue for reachability probes");
+ }
+
+ ~ReachabilityDispatchQueue()
+ {
+ if (queue)
+ dispatch_release(queue);
+ }
+
+ dispatch_queue_t data() const
+ {
+ return queue;
+ }
+
+private:
+ dispatch_queue_t queue = nullptr;
+
+ Q_DISABLE_COPY_MOVE(ReachabilityDispatchQueue)
+};
+
+dispatch_queue_t qt_reachability_queue()
+{
+ static const ReachabilityDispatchQueue reachabilityQueue;
+ return reachabilityQueue.data();
+}
+
+qt_sockaddr qt_hostaddress_to_sockaddr(const QHostAddress &src)
+{
+ if (src.isNull())
+ return {};
+
+ qt_sockaddr dst;
+ if (src.protocol() == QAbstractSocket::IPv4Protocol) {
+ dst.a4 = sockaddr_in{};
+ dst.a4.sin_family = AF_INET;
+ dst.a4.sin_addr.s_addr = htonl(src.toIPv4Address());
+ dst.a4.sin_len = sizeof(sockaddr_in);
+ } else if (src.protocol() == QAbstractSocket::IPv6Protocol) {
+ dst.a6 = sockaddr_in6{};
+ dst.a6.sin6_family = AF_INET6;
+ dst.a6.sin6_len = sizeof(sockaddr_in6);
+ const Q_IPV6ADDR ipv6 = src.toIPv6Address();
+ std::memcpy(&dst.a6.sin6_addr, &ipv6, sizeof ipv6);
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ return dst;
+}
+
+} // unnamed namespace
+
+class QNetworkConnectionMonitorPrivate : public QObjectPrivate
+{
+public:
+ SCNetworkReachabilityRef probe = nullptr;
+ SCNetworkReachabilityFlags state = kSCNetworkReachabilityFlagsIsLocalAddress;
+ bool scheduled = false;
+
+ void updateState(SCNetworkReachabilityFlags newState);
+ void reset();
+ bool isReachable() const;
+
+ static void probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info);
+
+ Q_DECLARE_PUBLIC(QNetworkConnectionMonitor)
+};
+
+void QNetworkConnectionMonitorPrivate::updateState(SCNetworkReachabilityFlags newState)
+{
+ // To be executed only on the reachability queue.
+ Q_Q(QNetworkConnectionMonitor);
+
+ // NETMONTODO: for now, 'online' for us means kSCNetworkReachabilityFlagsReachable
+ // 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();
+ state = newState;
+ if (wasReachable != isReachable())
+ emit q->reachabilityChanged(isReachable());
+}
+
+void QNetworkConnectionMonitorPrivate::reset()
+{
+ if (probe) {
+ CFRelease(probe);
+ probe = nullptr;
+ }
+
+ state = kSCNetworkReachabilityFlagsIsLocalAddress;
+ scheduled = false;
+}
+
+bool QNetworkConnectionMonitorPrivate::isReachable() const
+{
+ return !!(state & kSCNetworkReachabilityFlagsReachable);
+}
+
+void QNetworkConnectionMonitorPrivate::probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info)
+{
+ // To be executed only on the reachability queue.
+ Q_UNUSED(probe);
+
+ auto monitorPrivate = static_cast<QNetworkConnectionMonitorPrivate *>(info);
+ Q_ASSERT(monitorPrivate);
+ monitorPrivate->updateState(flags);
+}
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor()
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+}
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote)
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+ setTargets(local, remote);
+}
+
+QNetworkConnectionMonitor::~QNetworkConnectionMonitor()
+{
+ Q_D(QNetworkConnectionMonitor);
+
+ stopMonitoring();
+ d->reset();
+}
+
+bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote)
+{
+ Q_D(QNetworkConnectionMonitor);
+
+ if (isMonitoring()) {
+ qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ return false;
+ }
+
+ if (local.isNull()) {
+ qCWarning(lcNetMon, "Invalid (null) local address, cannot create a reachability target");
+ return false;
+ }
+
+ // Clear the old target if needed:
+ d->reset();
+
+ qt_sockaddr client = qt_hostaddress_to_sockaddr(local);
+ if (remote.isNull()) {
+ // That's a special case our QNetworkStatusMonitor is using (AnyIpv4/6 address to check an overall status).
+ d->probe = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, reinterpret_cast<sockaddr *>(&client));
+ } else {
+ qt_sockaddr target = qt_hostaddress_to_sockaddr(remote);
+ d->probe = SCNetworkReachabilityCreateWithAddressPair(kCFAllocatorDefault,
+ reinterpret_cast<sockaddr *>(&client),
+ reinterpret_cast<sockaddr *>(&target));
+ }
+
+ if (d->probe) {
+ // Let's read the initial state so that callback coming later can
+ // see a difference. Ignore errors though.
+ SCNetworkReachabilityGetFlags(d->probe, &d->state);
+ }else {
+ qCWarning(lcNetMon, "Failed to create network reachability probe");
+ return false;
+ }
+
+ return true;
+}
+
+bool QNetworkConnectionMonitor::startMonitoring()
+{
+ Q_D(QNetworkConnectionMonitor);
+
+ if (isMonitoring()) {
+ qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ return false;
+ }
+
+ if (!d->probe) {
+ qCWarning(lcNetMon, "Can not start monitoring, set targets first");
+ return false;
+ }
+
+ auto queue = qt_reachability_queue();
+ if (!queue) {
+ qWarning(lcNetMon, "Failed to create a dispatch queue to schedule a probe on");
+ return false;
+ }
+
+ SCNetworkReachabilityContext context = {};
+ context.info = d;
+ if (!SCNetworkReachabilitySetCallback(d->probe, QNetworkConnectionMonitorPrivate::probeCallback, &context)) {
+ qWarning(lcNetMon, "Failed to set a reachability callback");
+ return false;
+ }
+
+
+ if (!SCNetworkReachabilitySetDispatchQueue(d->probe, queue)) {
+ qWarning(lcNetMon, "Failed to schedule a reachability callback on a queue");
+ return false;
+ }
+
+ return d->scheduled = true;
+}
+
+bool QNetworkConnectionMonitor::isMonitoring() const
+{
+ Q_D(const QNetworkConnectionMonitor);
+
+ return d->scheduled;
+}
+
+void QNetworkConnectionMonitor::stopMonitoring()
+{
+ Q_D(QNetworkConnectionMonitor);
+
+ if (d->scheduled) {
+ Q_ASSERT(d->probe);
+ SCNetworkReachabilitySetDispatchQueue(d->probe, nullptr);
+ SCNetworkReachabilitySetCallback(d->probe, nullptr, nullptr);
+ d->scheduled = false;
+ }
+}
+
+bool QNetworkConnectionMonitor::isReachable()
+{
+ Q_D(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->isReachable();
+}
+
+class QNetworkStatusMonitorPrivate : public QObjectPrivate
+{
+public:
+ QNetworkConnectionMonitor ipv4Probe;
+ bool isOnlineIpv4 = false;
+ QNetworkConnectionMonitor ipv6Probe;
+ bool isOnlineIpv6 = false;
+
+ static bool enabled;
+ static void readEnv();
+};
+
+bool QNetworkStatusMonitorPrivate::enabled = false;
+
+void QNetworkStatusMonitorPrivate::readEnv()
+{
+ bool envOk = false;
+ const int env = qEnvironmentVariableIntValue("QT_USE_NETWORK_MONITOR", &envOk);
+ enabled = envOk && env > 0;
+}
+
+QNetworkStatusMonitor::QNetworkStatusMonitor()
+ : QObject(*new QNetworkStatusMonitorPrivate)
+{
+ Q_D(QNetworkStatusMonitor);
+
+ if (d->ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
+ // We manage to create SCNetworkReachabilityRef for IPv4, let's
+ // read the last known state then!
+ d->isOnlineIpv4 = d->ipv4Probe.isReachable();
+ }
+
+ if (d->ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) {
+ // We manage to create SCNetworkReachability ref for IPv6, let's
+ // read the last known state then!
+ d->isOnlineIpv6 = d->ipv6Probe.isReachable();
+ }
+
+
+ connect(&d->ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection);
+ connect(&d->ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
+ &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection);
+}
+
+QNetworkStatusMonitor::~QNetworkStatusMonitor()
+{
+ Q_D(QNetworkStatusMonitor);
+
+ d->ipv4Probe.disconnect();
+ d->ipv4Probe.stopMonitoring();
+ d->ipv6Probe.disconnect();
+ d->ipv6Probe.stopMonitoring();
+}
+
+bool QNetworkStatusMonitor::start()
+{
+ Q_D(QNetworkStatusMonitor);
+
+ if (isMonitoring()) {
+ qCWarning(lcNetMon, "Network status monitor is already active");
+ return true;
+ }
+
+ d->ipv4Probe.startMonitoring();
+ d->ipv6Probe.startMonitoring();
+
+ return isMonitoring();
+}
+
+void QNetworkStatusMonitor::stop()
+{
+ Q_D(QNetworkStatusMonitor);
+
+ if (d->ipv4Probe.isMonitoring())
+ d->ipv4Probe.stopMonitoring();
+ if (d->ipv6Probe.isMonitoring())
+ d->ipv6Probe.stopMonitoring();
+}
+
+bool QNetworkStatusMonitor::isMonitoring() const
+{
+ Q_D(const QNetworkStatusMonitor);
+
+ return d->ipv4Probe.isMonitoring() || d->ipv6Probe.isMonitoring();
+}
+
+bool QNetworkStatusMonitor::isNetworkAccesible()
+{
+ // This function is to be executed on the thread that created
+ // and uses 'this'.
+ Q_D(QNetworkStatusMonitor);
+
+ return d->isOnlineIpv4 || d->isOnlineIpv6;
+}
+
+bool QNetworkStatusMonitor::isEnabled()
+{
+ static std::once_flag envRead = {};
+ std::call_once(envRead, QNetworkStatusMonitorPrivate::readEnv);
+ return QNetworkStatusMonitorPrivate::enabled;
+}
+
+void QNetworkStatusMonitor::reachabilityChanged(bool online)
+{
+ // This function is executed on the thread that created/uses 'this',
+ // not on the reachability queue.
+ Q_D(QNetworkStatusMonitor);
+
+ auto probe = qobject_cast<QNetworkConnectionMonitor *>(sender());
+ if (!probe)
+ return;
+
+ const bool isIpv4 = probe == &d->ipv4Probe;
+ bool &probeOnline = isIpv4 ? d->isOnlineIpv4 : d->isOnlineIpv6;
+ bool otherOnline = isIpv4 ? d->isOnlineIpv6 : d->isOnlineIpv4;
+
+ if (probeOnline == online) {
+ // We knew this already?
+ return;
+ }
+
+ probeOnline = online;
+ if (!otherOnline) {
+ // We either just lost or got a network access.
+ emit onlineStateChanged(probeOnline);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetconmonitor_p.h b/src/network/kernel/qnetconmonitor_p.h
new file mode 100644
index 0000000000..74ee56d422
--- /dev/null
+++ b/src/network/kernel/qnetconmonitor_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#ifndef QNETCONMONITOR_P_H
+#define QNETCONMONITOR_P_H
+
+#include <private/qtnetworkglobal_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtNetwork/qhostaddress.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkConnectionMonitorPrivate;
+class QNetworkConnectionMonitor : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNetworkConnectionMonitor();
+ QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote = {});
+ ~QNetworkConnectionMonitor();
+
+ bool setTargets(const QHostAddress &local, const QHostAddress &remote);
+ bool isReachable();
+
+ // Important: on Darwin you should not call isReachable() after
+ // startMonitoring(), you have to listen to reachabilityChanged()
+ // signal instead.
+ bool startMonitoring();
+ bool isMonitoring() const;
+ void stopMonitoring();
+
+Q_SIGNALS:
+ // Important: connect to this using QueuedConnection. On Darwin
+ // callback is coming on a special dispatch queue.
+ void reachabilityChanged(bool isOnline);
+
+private:
+ Q_DECLARE_PRIVATE(QNetworkConnectionMonitor)
+ Q_DISABLE_COPY_MOVE(QNetworkConnectionMonitor)
+};
+
+class QNetworkStatusMonitorPrivate;
+class QNetworkStatusMonitor : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNetworkStatusMonitor();
+ ~QNetworkStatusMonitor();
+
+ bool isNetworkAccesible();
+
+ bool start();
+ void stop();
+ bool isMonitoring() const;
+
+ static bool isEnabled();
+
+Q_SIGNALS:
+ // Unlike QNetworkConnectionMonitor, this can be connected to directly.
+ void onlineStateChanged(bool isOnline);
+
+private slots:
+ void reachabilityChanged(bool isOnline);
+
+private:
+ Q_DECLARE_PRIVATE(QNetworkStatusMonitor)
+ Q_DISABLE_COPY_MOVE(QNetworkStatusMonitor)
+};
+
+Q_DECLARE_LOGGING_CATEGORY(lcNetMon)
+
+QT_END_NAMESPACE
+
+#endif // QNETCONMONITOR_P_H
diff --git a/src/network/kernel/qnetconmonitor_stub.cpp b/src/network/kernel/qnetconmonitor_stub.cpp
new file mode 100644
index 0000000000..7f3a0c44c6
--- /dev/null
+++ b/src/network/kernel/qnetconmonitor_stub.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qnetconmonitor_p.h"
+
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor");
+
+// Note: this 'stub' version is never enabled (see QNetworkStatusMonitor::isEnabled below)
+// and thus should never affect QNAM in any unusuall way. Having this 'stub' version is similar
+// to building Qt with bearer management configured out.
+
+class QNetworkConnectionMonitorPrivate : public QObjectPrivate
+{
+};
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor()
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+}
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote)
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+ Q_UNUSED(local)
+ Q_UNUSED(remote)
+}
+
+QNetworkConnectionMonitor::~QNetworkConnectionMonitor()
+{
+}
+
+bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote)
+{
+ Q_UNUSED(local)
+ Q_UNUSED(remote)
+
+ return false;
+}
+
+bool QNetworkConnectionMonitor::startMonitoring()
+{
+ return false;
+}
+
+bool QNetworkConnectionMonitor::isMonitoring() const
+{
+ return false;
+}
+
+void QNetworkConnectionMonitor::stopMonitoring()
+{
+}
+
+bool QNetworkConnectionMonitor::isReachable()
+{
+ return false;
+}
+
+class QNetworkStatusMonitorPrivate : public QObjectPrivate
+{
+};
+
+QNetworkStatusMonitor::QNetworkStatusMonitor()
+ : QObject(*new QNetworkStatusMonitorPrivate)
+{
+}
+
+QNetworkStatusMonitor::~QNetworkStatusMonitor()
+{
+}
+
+bool QNetworkStatusMonitor::start()
+{
+ return false;
+}
+
+void QNetworkStatusMonitor::stop()
+{
+}
+
+bool QNetworkStatusMonitor::isMonitoring() const
+{
+ return false;
+}
+
+bool QNetworkStatusMonitor::isNetworkAccesible()
+{
+ return false;
+}
+
+bool QNetworkStatusMonitor::isEnabled()
+{
+ return false;
+}
+
+void QNetworkStatusMonitor::reachabilityChanged(bool online)
+{
+ Q_UNUSED(online)
+}
+
+QT_END_NAMESPACE