summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/access.pri6
-rw-r--r--src/network/access/http2/hpack.cpp5
-rw-r--r--src/network/access/http2/hpack_p.h1
-rw-r--r--src/network/access/http2/http2frames.cpp4
-rw-r--r--src/network/access/http2/http2protocol.cpp116
-rw-r--r--src/network/access/http2/http2protocol_p.h64
-rw-r--r--src/network/access/qabstractnetworkcache.h6
-rw-r--r--src/network/access/qftp.cpp19
-rw-r--r--src/network/access/qftp_p.h7
-rw-r--r--src/network/access/qhsts.cpp4
-rw-r--r--src/network/access/qhstspolicy.h4
-rw-r--r--src/network/access/qhttp2configuration.cpp312
-rw-r--r--src/network/access/qhttp2configuration.h100
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp84
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h27
-rw-r--r--src/network/access/qhttpmultipart.h6
-rw-r--r--src/network/access/qhttpmultipart_p.h2
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp70
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h25
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp18
-rw-r--r--src/network/access/qhttpnetworkreply.cpp3
-rw-r--r--src/network/access/qhttpnetworkreply_p.h2
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp6
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h13
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager_p.h4
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp10
-rw-r--r--src/network/access/qnetworkaccesscache.cpp32
-rw-r--r--src/network/access/qnetworkaccessftpbackend.cpp7
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp184
-rw-r--r--src/network/access/qnetworkaccessmanager.h5
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h10
-rw-r--r--src/network/access/qnetworkcookie.cpp1
-rw-r--r--src/network/access/qnetworkcookie.h6
-rw-r--r--src/network/access/qnetworkdiskcache_p.h4
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp79
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h2
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp24
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h8
-rw-r--r--src/network/access/qnetworkrequest.cpp92
-rw-r--r--src/network/access/qnetworkrequest.h15
-rw-r--r--src/network/access/qspdyprotocolhandler.cpp15
-rw-r--r--src/network/access/qspdyprotocolhandler_p.h2
-rw-r--r--src/network/bearer/qbearerengine.cpp11
-rw-r--r--src/network/bearer/qbearerengine_p.h4
-rw-r--r--src/network/bearer/qbearerplugin_p.h2
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.cpp71
-rw-r--r--src/network/bearer/qnetworkconfigmanager_p.h2
-rw-r--r--src/network/bearer/qnetworkconfiguration.cpp29
-rw-r--r--src/network/bearer/qnetworkconfiguration.h6
-rw-r--r--src/network/bearer/qnetworkconfiguration_p.h10
-rw-r--r--src/network/bearer/qnetworksession_p.h4
-rw-r--r--src/network/bearer/qsharednetworksession.cpp44
-rw-r--r--src/network/bearer/qsharednetworksession_p.h16
-rw-r--r--src/network/configure.json68
-rw-r--r--src/network/kernel/kernel.pri16
-rw-r--r--src/network/kernel/qauthenticator.cpp413
-rw-r--r--src/network/kernel/qauthenticator_p.h17
-rw-r--r--src/network/kernel/qdnslookup.h30
-rw-r--r--src/network/kernel/qdnslookup_p.h2
-rw-r--r--src/network/kernel/qdnslookup_win.cpp1
-rw-r--r--src/network/kernel/qhostaddress.cpp2
-rw-r--r--src/network/kernel/qhostaddress.h11
-rw-r--r--src/network/kernel/qhostinfo.cpp425
-rw-r--r--src/network/kernel/qhostinfo.h8
-rw-r--r--src/network/kernel/qhostinfo_p.h102
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp139
-rw-r--r--src/network/kernel/qhostinfo_win.cpp110
-rw-r--r--src/network/kernel/qnetconmonitor_darwin.mm419
-rw-r--r--src/network/kernel/qnetconmonitor_p.h126
-rw-r--r--src/network/kernel/qnetconmonitor_stub.cpp141
-rw-r--r--src/network/kernel/qnetconmonitor_win.cpp712
-rw-r--r--src/network/kernel/qnetworkdatagram.h6
-rw-r--r--src/network/kernel/qnetworkinterface.h12
-rw-r--r--src/network/kernel/qnetworkinterface_p.h2
-rw-r--r--src/network/kernel/qnetworkinterface_unix_p.h2
-rw-r--r--src/network/kernel/qnetworkproxy.cpp9
-rw-r--r--src/network/kernel/qnetworkproxy.h12
-rw-r--r--src/network/network.pro2
-rw-r--r--src/network/socket/qabstractsocketengine_p.h12
-rw-r--r--src/network/socket/qhttpsocketengine.cpp2
-rw-r--r--src/network/socket/qhttpsocketengine_p.h8
-rw-r--r--src/network/socket/qlocalserver_p.h2
-rw-r--r--src/network/socket/qnativesocketengine_p.h10
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp3
-rw-r--r--src/network/socket/qsctpserver.cpp7
-rw-r--r--src/network/socket/qsocks5socketengine.cpp12
-rw-r--r--src/network/socket/qsocks5socketengine_p.h10
-rw-r--r--src/network/socket/socket.pri2
-rw-r--r--src/network/ssl/qasn1element_p.h4
-rw-r--r--src/network/ssl/qdtls.cpp2
-rw-r--r--src/network/ssl/qdtls_openssl.cpp2
-rw-r--r--src/network/ssl/qocspresponse.cpp6
-rw-r--r--src/network/ssl/qocspresponse.h10
-rw-r--r--src/network/ssl/qsslcertificate.h10
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp15
-rw-r--r--src/network/ssl/qsslcertificate_p.h2
-rw-r--r--src/network/ssl/qsslcertificate_qt.cpp2
-rw-r--r--src/network/ssl/qsslcertificateextension.h6
-rw-r--r--src/network/ssl/qsslcipher.h6
-rw-r--r--src/network/ssl/qsslconfiguration.h6
-rw-r--r--src/network/ssl/qsslcontext_openssl11.cpp2
-rw-r--r--src/network/ssl/qsslcontext_openssl_p.h2
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.cpp12
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.h24
-rw-r--r--src/network/ssl/qsslellipticcurve.h18
-rw-r--r--src/network/ssl/qsslellipticcurve_dummy.cpp2
-rw-r--r--src/network/ssl/qsslellipticcurve_openssl.cpp2
-rw-r--r--src/network/ssl/qsslerror.cpp9
-rw-r--r--src/network/ssl/qsslerror.h10
-rw-r--r--src/network/ssl/qsslkey.h7
-rw-r--r--src/network/ssl/qsslkey_mac.cpp22
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp9
-rw-r--r--src/network/ssl/qsslkey_p.cpp18
-rw-r--r--src/network/ssl/qsslkey_p.h7
-rw-r--r--src/network/ssl/qsslkey_qt.cpp50
-rw-r--r--src/network/ssl/qsslkey_schannel.cpp4
-rw-r--r--src/network/ssl/qsslkey_winrt.cpp9
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.h6
-rw-r--r--src/network/ssl/qsslsocket.cpp35
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp5
-rw-r--r--src/network/ssl/qsslsocket_openssl11.cpp8
-rw-r--r--src/network/ssl/qsslsocket_openssl11_symbols_p.h1
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp127
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h12
-rw-r--r--src/network/ssl/qsslsocket_opensslpre11.cpp1
-rw-r--r--src/network/ssl/qsslsocket_qt.cpp1
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp2
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp1
129 files changed, 3548 insertions, 1389 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 8a92308f12..cfb20dcd71 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -97,7 +97,8 @@ qtConfig(http) {
access/qhttpnetworkrequest.cpp \
access/qhttpprotocolhandler.cpp \
access/qhttpthreaddelegate.cpp \
- access/qnetworkreplyhttpimpl.cpp
+ access/qnetworkreplyhttpimpl.cpp \
+ access/qhttp2configuration.cpp
HEADERS += \
access/qabstractprotocolhandler_p.h \
@@ -111,7 +112,8 @@ qtConfig(http) {
access/qhttpnetworkrequest_p.h \
access/qhttpprotocolhandler_p.h \
access/qhttpthreaddelegate_p.h \
- access/qnetworkreplyhttpimpl_p.h
+ access/qnetworkreplyhttpimpl_p.h \
+ access/qhttp2configuration.h
qtConfig(ssl) {
SOURCES += \
diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp
index 2d324d5092..b40cc29e1a 100644
--- a/src/network/access/http2/hpack.cpp
+++ b/src/network/access/http2/hpack.cpp
@@ -208,6 +208,11 @@ void Encoder::setMaxDynamicTableSize(quint32 size)
lookupTable.setMaxDynamicTableSize(size);
}
+void Encoder::setCompressStrings(bool compress)
+{
+ compressStrings = compress;
+}
+
bool Encoder::encodeRequestPseudoHeaders(BitOStream &outputStream,
const HttpHeader &header)
{
diff --git a/src/network/access/http2/hpack_p.h b/src/network/access/http2/hpack_p.h
index 6a1d30d87b..8c2701e7af 100644
--- a/src/network/access/http2/hpack_p.h
+++ b/src/network/access/http2/hpack_p.h
@@ -83,6 +83,7 @@ public:
quint32 newSize);
void setMaxDynamicTableSize(quint32 size);
+ void setCompressStrings(bool compress);
private:
bool encodeRequestPseudoHeaders(BitOStream &outputStream,
diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp
index e695b4dd9e..ce33505683 100644
--- a/src/network/access/http2/http2frames.cpp
+++ b/src/network/access/http2/http2frames.cpp
@@ -305,7 +305,7 @@ FrameStatus FrameReader::read(QAbstractSocket &socket)
return status;
}
- if (Http2PredefinedParameters::maxFrameSize < frame.payloadSize())
+ if (Http2PredefinedParameters::maxPayloadSize < frame.payloadSize())
return FrameStatus::sizeError;
frame.buffer.resize(frame.payloadSize() + frameHeaderSize);
@@ -388,7 +388,7 @@ void FrameWriter::setPayloadSize(quint32 size)
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
- Q_ASSERT(size < maxPayloadSize);
+ Q_ASSERT(size <= maxPayloadSize);
buffer[0] = size >> 16;
buffer[1] = size >> 8;
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp
index 0be72042c6..31da6fd616 100644
--- a/src/network/access/http2/http2protocol.cpp
+++ b/src/network/access/http2/http2protocol.cpp
@@ -43,6 +43,8 @@
#include "private/qhttpnetworkrequest_p.h"
#include "private/qhttpnetworkreply_p.h"
+#include <access/qhttp2configuration.h>
+
#include <QtCore/qbytearray.h>
#include <QtCore/qstring.h>
@@ -62,88 +64,29 @@ const char Http2clientPreface[clientPrefaceLength] =
0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a,
0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a};
-// TODO: (in 5.11) - remove it!
-const char *http2ParametersPropertyName = "QT_HTTP2_PARAMETERS_PROPERTY";
-
-ProtocolParameters::ProtocolParameters()
-{
- settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = qtDefaultStreamReceiveWindowSize;
- settingsFrameData[Settings::ENABLE_PUSH_ID] = 0;
-}
-
-bool ProtocolParameters::validate() const
+Frame configurationToSettingsFrame(const QHttp2Configuration &config)
{
- // 0. Huffman/indexing: any values are valid and allowed.
-
- // 1. Session receive window size (client side): HTTP/2 starts from the
- // default value of 64Kb, if a client code tries to set lesser value,
- // the delta would become negative, but this is not allowed.
- if (maxSessionReceiveWindowSize < qint32(defaultSessionWindowSize)) {
- qCWarning(QT_HTTP2, "Session receive window must be at least 65535 bytes");
- return false;
- }
-
- // 2. HEADER_TABLE_SIZE: we do not validate HEADER_TABLE_SIZE, considering
- // all values as valid. RFC 7540 and 7541 do not provide any lower/upper
- // limits. If it's 0 - we do not index anything, if it's too huge - a user
- // who provided such a value can potentially have a huge memory footprint,
- // up to them to decide.
-
- // 3. SETTINGS_ENABLE_PUSH: RFC 7540, 6.5.2, a value other than 0 or 1 will
- // be treated by our peer as a PROTOCOL_ERROR.
- if (settingsFrameData.contains(Settings::ENABLE_PUSH_ID)
- && settingsFrameData[Settings::ENABLE_PUSH_ID] > 1) {
- qCWarning(QT_HTTP2, "SETTINGS_ENABLE_PUSH can be only 0 or 1");
- return false;
- }
-
- // 4. SETTINGS_MAX_CONCURRENT_STREAMS : RFC 7540 recommends 100 as the lower
- // limit, says nothing about the upper limit. The RFC allows 0, but this makes
- // no sense to us at all: there is no way a user can change this later and
- // we'll not be able to get any responses on such a connection.
- if (settingsFrameData.contains(Settings::MAX_CONCURRENT_STREAMS_ID)
- && !settingsFrameData[Settings::MAX_CONCURRENT_STREAMS_ID]) {
- qCWarning(QT_HTTP2, "MAX_CONCURRENT_STREAMS must be a positive number");
- return false;
- }
-
- // 5. SETTINGS_INITIAL_WINDOW_SIZE.
- if (settingsFrameData.contains(Settings::INITIAL_WINDOW_SIZE_ID)) {
- const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID];
- // RFC 7540, 6.5.2 (the upper limit). The lower limit is our own - we send
- // SETTINGS frame only once and will not be able to change this 0, thus
- // we'll suspend all streams.
- if (!value || value > quint32(maxSessionReceiveWindowSize)) {
- qCWarning(QT_HTTP2, "INITIAL_WINDOW_SIZE must be in the range "
- "(0, 2^31-1]");
- return false;
- }
- }
-
- // 6. SETTINGS_MAX_FRAME_SIZE: RFC 7540, 6.5.2, a value outside of the range
- // [2^14-1, 2^24-1] will be treated by our peer as a PROTOCOL_ERROR.
- if (settingsFrameData.contains(Settings::MAX_FRAME_SIZE_ID)) {
- const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID];
- if (value < maxFrameSize || value > maxPayloadSize) {
- qCWarning(QT_HTTP2, "MAX_FRAME_SIZE must be in the range [2^14, 2^24-1]");
- return false;
- }
+ // 6.5 SETTINGS
+ FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
+ // Server push:
+ builder.append(Settings::ENABLE_PUSH_ID);
+ builder.append(int(config.serverPushEnabled()));
+ // Stream receive window size:
+ builder.append(Settings::INITIAL_WINDOW_SIZE_ID);
+ builder.append(config.streamReceiveWindowSize());
+
+ if (config.maxFrameSize() != minPayloadLimit) {
+ builder.append(Settings::MAX_FRAME_SIZE_ID);
+ builder.append(config.maxFrameSize());
}
-
- // For SETTINGS_MAX_HEADER_LIST_SIZE RFC 7540 does not provide any specific
- // numbers. It's clear, if a value is too small, no header can ever be sent
- // by our peer at all. The default value is unlimited and we normally do not
- // change this.
- //
- // Note: the size is calculated as the length of uncompressed (no HPACK)
- // name + value + 32 bytes.
-
- return true;
+ // TODO: In future, if the need is proven, we can
+ // also send decoding table size and header list size.
+ // For now, defaults suffice.
+ return builder.outboundFrame();
}
-QByteArray ProtocolParameters::settingsFrameToBase64() const
+QByteArray settingsFrameToBase64(const Frame &frame)
{
- Frame frame(settingsFrame());
// SETTINGS frame's payload consists of pairs:
// 2-byte-identifier | 4-byte-value == multiple of 6.
Q_ASSERT(frame.payloadSize() && !(frame.payloadSize() % 6));
@@ -157,20 +100,7 @@ QByteArray ProtocolParameters::settingsFrameToBase64() const
return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
}
-Frame ProtocolParameters::settingsFrame() const
-{
- // 6.5 SETTINGS
- FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
- for (auto it = settingsFrameData.cbegin(), end = settingsFrameData.cend();
- it != end; ++it) {
- builder.append(it.key());
- builder.append(it.value());
- }
-
- return builder.outboundFrame();
-}
-
-void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const
+void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetworkRequest *request)
{
Q_ASSERT(request);
// RFC 2616, 14.10
@@ -184,8 +114,10 @@ void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request)
request->setHeaderField("Connection", value);
// This we just (re)write.
request->setHeaderField("Upgrade", "h2c");
+
+ const Frame frame(configurationToSettingsFrame(config));
// This we just (re)write.
- request->setHeaderField("HTTP2-Settings", settingsFrameToBase64());
+ request->setHeaderField("HTTP2-Settings", settingsFrameToBase64(frame));
}
void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index 7142d6f1fa..b0af5aa919 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -55,12 +55,14 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qmap.h>
// Different HTTP/2 constants/values as defined by RFC 7540.
QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
+class QHttp2Configuration;
class QHttpNetworkReply;
class QByteArray;
class QString;
@@ -118,13 +120,19 @@ enum Http2PredefinedParameters
connectionStreamID = 0, // HTTP/2, 5.1.1
frameHeaderSize = 9, // HTTP/2, 4.1
- // It's our max frame size we send in SETTINGS frame,
- // it's also the default one and we also use it to later
- // validate incoming frames:
- maxFrameSize = 16384, // HTTP/2 6.5.2
+ // The initial allowed payload size. We would use it as an
+ // upper limit for a frame payload we send, until our peer
+ // updates us with a larger SETTINGS_MAX_FRAME_SIZE.
- defaultSessionWindowSize = 65535, // HTTP/2 6.5.2
+ // The initial maximum payload size that an HTTP/2 frame
+ // can contain is 16384. It's also the minimal size that
+ // can be advertised via 'SETTINGS' frames. A real frame
+ // can have a payload smaller than 16384.
+ minPayloadLimit = 16384, // HTTP/2 6.5.2
+ // The maximum allowed payload size.
maxPayloadSize = (1 << 24) - 1, // HTTP/2 6.5.2
+
+ defaultSessionWindowSize = 65535, // HTTP/2 6.5.2
// Using 1000 (rather arbitrarily), just to
// impose *some* upper limit:
maxPeerConcurrentStreams = 1000,
@@ -145,48 +153,9 @@ const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1
const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1);
const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / maxConcurrentStreams;
-// The class ProtocolParameters allows client code to customize HTTP/2 protocol
-// handler, if needed. Normally, we use our own default parameters (see below).
-// In 5.10 we can also use setProperty/property on a QNAM object to pass the
-// non-default values to the protocol handler. In 5.11 this will probably become
-// a public API.
-
-using RawSettings = QMap<Settings, quint32>;
-
-struct Q_AUTOTEST_EXPORT ProtocolParameters
-{
- ProtocolParameters();
-
- bool validate() const;
- QByteArray settingsFrameToBase64() const;
- struct Frame settingsFrame() const;
- void addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const;
-
- // HPACK:
- // TODO: for now we ignore them (fix it for 5.11, would require changes in HPACK)
- bool useHuffman = true;
- bool indexStrings = true;
-
- // This parameter is not negotiated via SETTINGS frames, so we have it
- // as a member and will convey it to our peer as a WINDOW_UPDATE frame.
- // Note, some servers do not accept our WINDOW_UPDATE from the default
- // 64 KB to the possible maximum. Let's use a half of it:
- qint32 maxSessionReceiveWindowSize = Http2::maxSessionReceiveWindowSize / 2;
-
- // This is our default SETTINGS frame:
- //
- // SETTINGS_INITIAL_WINDOW_SIZE: (2^31 - 1) / 100
- // SETTINGS_ENABLE_PUSH: 0.
- //
- // Note, whenever we skip some value in our SETTINGS frame, our peer
- // will assume the defaults recommended by RFC 7540, which in general
- // are good enough, although we (and most browsers) prefer to work
- // with larger window sizes.
- RawSettings settingsFrameData;
-};
-
-// TODO: remove in 5.11
-extern const Q_AUTOTEST_EXPORT char *http2ParametersPropertyName;
+struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration);
+QByteArray settingsFrameToBase64(const Frame &settingsFrame);
+void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request);
extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength];
@@ -235,6 +204,5 @@ Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Http2::Settings)
-Q_DECLARE_METATYPE(Http2::ProtocolParameters)
#endif
diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h
index 678bae2d6e..e357dfe58f 100644
--- a/src/network/access/qabstractnetworkcache.h
+++ b/src/network/access/qabstractnetworkcache.h
@@ -67,12 +67,10 @@ public:
QNetworkCacheMetaData(const QNetworkCacheMetaData &other);
~QNetworkCacheMetaData();
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkCacheMetaData &operator=(QNetworkCacheMetaData &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkCacheMetaData &operator=(QNetworkCacheMetaData &&other) noexcept { swap(other); return *this; }
QNetworkCacheMetaData &operator=(const QNetworkCacheMetaData &other);
- void swap(QNetworkCacheMetaData &other) Q_DECL_NOTHROW
+ void swap(QNetworkCacheMetaData &other) noexcept
{ qSwap(d, other.d); }
bool operator==(const QNetworkCacheMetaData &other) const;
diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp
index 4e399f018f..cc230a5411 100644
--- a/src/network/access/qftp.cpp
+++ b/src/network/access/qftp.cpp
@@ -955,11 +955,9 @@ void QFtpPI::readyRead()
}
}
}
- QString endOfMultiLine;
- endOfMultiLine[0] = '0' + replyCode[0];
- endOfMultiLine[1] = '0' + replyCode[1];
- endOfMultiLine[2] = '0' + replyCode[2];
- endOfMultiLine[3] = QLatin1Char(' ');
+ const char count[4] = { char('0' + replyCode[0]), char('0' + replyCode[1]),
+ char('0' + replyCode[2]), char(' ') };
+ QString endOfMultiLine(QLatin1String(count, 4));
QString lineCont(endOfMultiLine);
lineCont[3] = QLatin1Char('-');
QStringRef lineLeft4 = line.leftRef(4);
@@ -2124,6 +2122,17 @@ void QFtp::abort()
/*!
\internal
+ Clears the last error.
+
+ \sa currentCommand()
+*/
+void QFtp::clearError()
+{
+ d_func()->error = NoError;
+}
+
+/*!
+ \internal
Returns the identifier of the FTP command that is being executed
or 0 if there is no command being executed.
diff --git a/src/network/access/qftp_p.h b/src/network/access/qftp_p.h
index 0516c3d1f9..a55429933b 100644
--- a/src/network/access/qftp_p.h
+++ b/src/network/access/qftp_p.h
@@ -67,7 +67,7 @@ class Q_AUTOTEST_EXPORT QFtp : public QObject
Q_OBJECT
public:
- explicit QFtp(QObject *parent = 0);
+ explicit QFtp(QObject *parent = nullptr);
virtual ~QFtp();
enum State {
@@ -118,7 +118,7 @@ public:
int setTransferMode(TransferMode mode);
int list(const QString &dir = QString());
int cd(const QString &dir);
- int get(const QString &file, QIODevice *dev=0, TransferType type = Binary);
+ int get(const QString &file, QIODevice *dev=nullptr, TransferType type = Binary);
int put(const QByteArray &data, const QString &file, TransferType type = Binary);
int put(QIODevice *dev, const QString &file, TransferType type = Binary);
int remove(const QString &file);
@@ -157,6 +157,9 @@ Q_SIGNALS:
void commandFinished(int, bool);
void done(bool);
+protected:
+ void clearError();
+
private:
Q_DISABLE_COPY_MOVE(QFtp)
Q_DECLARE_PRIVATE(QFtp)
diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp
index ce70b6af90..0cef0ad3dc 100644
--- a/src/network/access/qhsts.cpp
+++ b/src/network/access/qhsts.cpp
@@ -145,7 +145,7 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires,
return;
}
- knownHosts.insert(pos, {hostName, newPolicy});
+ knownHosts.insert({hostName, newPolicy});
#if QT_CONFIG(settings)
if (hstsStore)
hstsStore->addToObserved(newPolicy);
@@ -156,7 +156,7 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires,
if (newPolicy.isExpired())
knownHosts.erase(pos);
else if (pos->second != newPolicy)
- pos->second = std::move(newPolicy);
+ pos->second = newPolicy;
else
return;
diff --git a/src/network/access/qhstspolicy.h b/src/network/access/qhstspolicy.h
index 176a8fa635..f1b2ee99e5 100644
--- a/src/network/access/qhstspolicy.h
+++ b/src/network/access/qhstspolicy.h
@@ -65,10 +65,10 @@ public:
QUrl::ParsingMode mode = QUrl::DecodedMode);
QHstsPolicy(const QHstsPolicy &rhs);
QHstsPolicy &operator=(const QHstsPolicy &rhs);
- QHstsPolicy &operator=(QHstsPolicy &&other) Q_DECL_NOTHROW { swap(other); return *this; }
+ QHstsPolicy &operator=(QHstsPolicy &&other) noexcept { swap(other); return *this; }
~QHstsPolicy();
- void swap(QHstsPolicy &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QHstsPolicy &other) noexcept { qSwap(d, other.d); }
void setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode);
QString host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const;
diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp
new file mode 100644
index 0000000000..bd4318d4e9
--- /dev/null
+++ b/src/network/access/qhttp2configuration.cpp
@@ -0,0 +1,312 @@
+/****************************************************************************
+**
+** 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 "qhttp2configuration.h"
+
+#include "private/http2protocol_p.h"
+#include "private/hpack_p.h"
+
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHttp2Configuration
+ \brief The QHttp2Configuration class controls HTTP/2 parameters and settings.
+ \since 5.14
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup network
+ \ingroup shared
+
+ QHttp2Configuration controls HTTP/2 parameters and settings that
+ QNetworkAccessManager will use to send requests and process responses
+ when the HTTP/2 protocol is enabled.
+
+ The HTTP/2 parameters that QHttp2Configuration currently supports include:
+
+ \list
+ \li The session window size for connection-level flow control.
+ Will be sent to a remote peer when needed as 'WINDOW_UPDATE'
+ frames on the stream with an identifier 0.
+ \li The stream receiving window size for stream-level flow control.
+ Sent as 'SETTINGS_INITIAL_WINDOW_SIZE' parameter in the initial
+ SETTINGS frame and, when needed, 'WINDOW_UPDATE' frames will be
+ sent on streams that QNetworkAccessManager opens.
+ \li The maximum frame size. This parameter limits the maximum payload
+ a frame coming from the remote peer can have. Sent by QNetworkAccessManager
+ as 'SETTINGS_MAX_FRAME_SIZE' parameter in the initial 'SETTINGS'
+ frame.
+ \li The server push. Allows to enable or disable server push. Sent
+ as 'SETTINGS_ENABLE_PUSH' parameter in the initial 'SETTINGS'
+ frame.
+ \endlist
+
+ The QHttp2Configuration class also controls if the header compression
+ algorithm (HPACK) is additionally using Huffman coding for string
+ compression.
+
+ \note The configuration must be set before the first request
+ was sent to a given host (and thus an HTTP/2 session established).
+
+ \note Details about flow control, server push and 'SETTINGS'
+ can be found in \l {https://httpwg.org/specs/rfc7540.html}{RFC 7540}.
+ Different modes and parameters of the HPACK compression algorithm
+ are described in \l {https://httpwg.org/specs/rfc7541.html}{RFC 7541}.
+
+ \sa QNetworkRequest::setHttp2Configuration(), QNetworkRequest::http2Configuration(), QNetworkAccessManager
+*/
+
+class QHttp2ConfigurationPrivate : public QSharedData
+{
+public:
+ unsigned sessionWindowSize = Http2::defaultSessionWindowSize;
+ // The size below is quite a limiting default value, QNetworkRequest
+ // by default sets a larger number, an application can change this using
+ // QNetworkRequest::setHttp2Configuration.
+ unsigned streamWindowSize = Http2::defaultSessionWindowSize;
+
+ unsigned maxFrameSize = Http2::minPayloadLimit; // Initial (default) value of 16Kb.
+
+ bool pushEnabled = false;
+ // TODO: for now those two below are noop.
+ bool huffmanCompressionEnabled = true;
+};
+
+/*!
+ Default constructs a QHttp2Configuration object.
+
+ Such a configuration has the following values:
+ \list
+ \li Server push is disabled
+ \li Huffman string compression is enabled
+ \li Window size for connection-level flow control is 65535 octets
+ \li Window size for stream-level flow control is 65535 octets
+ \li Frame size is 16384 octets
+ \endlist
+*/
+QHttp2Configuration::QHttp2Configuration()
+ : d(new QHttp2ConfigurationPrivate)
+{
+}
+
+/*!
+ Copy-constructs this QHttp2Configuration.
+*/
+QHttp2Configuration::QHttp2Configuration(const QHttp2Configuration &) = default;
+
+/*!
+ Move-constructs this QHttp2Configuration from \a other
+*/
+QHttp2Configuration::QHttp2Configuration(QHttp2Configuration &&other) noexcept
+{
+ swap(other);
+}
+
+/*!
+ Copy-assigns to this QHttp2Configuration.
+*/
+QHttp2Configuration &QHttp2Configuration::operator=(const QHttp2Configuration &) = default;
+
+/*!
+ Move-assigns to this QHttp2Configuration.
+*/
+QHttp2Configuration &QHttp2Configuration::operator=(QHttp2Configuration &&) noexcept = default;
+
+/*!
+ Destructor.
+*/
+QHttp2Configuration::~QHttp2Configuration()
+{
+}
+
+/*!
+ If \a enable is \c true, a remote server can potentially
+ use server push to send reponses in advance.
+
+ \sa serverPushEnabled
+*/
+void QHttp2Configuration::setServerPushEnabled(bool enable)
+{
+ d->pushEnabled = enable;
+}
+
+/*!
+ Returns true if server push was enabled.
+
+ \note By default, QNetworkAccessManager disables server
+ push via the 'SETTINGS' frame.
+
+ \sa setServerPushEnabled
+*/
+bool QHttp2Configuration::serverPushEnabled() const
+{
+ return d->pushEnabled;
+}
+
+/*!
+ If \a enable is \c true, HPACK compression will additionally
+ compress string using the Huffman coding. Enabled by default.
+
+ \note This parameter only affects 'HEADERS' frames that
+ QNetworkAccessManager is sending.
+
+ \sa huffmanCompressionEnabled
+*/
+void QHttp2Configuration::setHuffmanCompressionEnabled(bool enable)
+{
+ d->huffmanCompressionEnabled = enable;
+}
+
+/*!
+ Returns \c true if the Huffman coding in HPACK is enabled.
+
+ \sa setHuffmanCompressionEnabled
+*/
+bool QHttp2Configuration::huffmanCompressionEnabled() const
+{
+ return d->huffmanCompressionEnabled;
+}
+
+/*!
+ Sets the window size for connection-level flow control.
+ \a size cannot be 0 and must not exceed 2147483647 octets.
+
+ \sa sessionReceiveWindowSize
+*/
+bool QHttp2Configuration::setSessionReceiveWindowSize(unsigned size)
+{
+ if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9
+ qCWarning(QT_HTTP2) << "Invalid session window size";
+ return false;
+ }
+
+ d->sessionWindowSize = size;
+ return true;
+}
+
+/*!
+ Returns the window size for connection-level flow control.
+ The default value QNetworkAccessManager will be using is
+ 2147483647 octets.
+*/
+unsigned QHttp2Configuration::sessionReceiveWindowSize() const
+{
+ return d->sessionWindowSize;
+}
+
+/*!
+ Sets the window size for stream-level flow control.
+ \a size cannot be 0 and must not exceed 2147483647 octets.
+
+ \sa streamReceiveWindowSize
+ */
+bool QHttp2Configuration::setStreamReceiveWindowSize(unsigned size)
+{
+ if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9
+ qCWarning(QT_HTTP2) << "Invalid stream window size";
+ return false;
+ }
+
+ d->streamWindowSize = size;
+ return true;
+}
+
+/*!
+ Returns the window size for stream-level flow control.
+ The default value QNetworkAccessManager will be using is
+ 21474836 octets.
+*/
+unsigned QHttp2Configuration::streamReceiveWindowSize() const
+{
+ return d->streamWindowSize;
+}
+
+/*!
+ Sets the maximum frame size that QNetworkAccessManager
+ will advertise to the server when sending its initial SETTINGS frame.
+ \note While this \a size is required to be within a range between
+ 16384 and 16777215 inclusive, the actual payload size in frames
+ that carry payload maybe be less than 16384.
+*/
+bool QHttp2Configuration::setMaxFrameSize(unsigned size)
+{
+ if (size < Http2::minPayloadLimit || size > Http2::maxPayloadSize) {
+ qCWarning(QT_HTTP2) << "Maximum frame size to advertise is invalid";
+ return false;
+ }
+
+ d->maxFrameSize = size;
+ return true;
+}
+
+/*!
+ The maximum payload size that HTTP/2 frames can
+ have. The default (initial) value is 16384 octets.
+*/
+unsigned QHttp2Configuration::maxFrameSize() const
+{
+ return d->maxFrameSize;
+}
+
+/*!
+ Swaps this configuration with the \a other configuration.
+*/
+void QHttp2Configuration::swap(QHttp2Configuration &other) noexcept
+{
+ d.swap(other.d);
+}
+
+/*!
+ Returns \c true if \a lhs and \a rhs have the same set of HTTP/2
+ parameters.
+*/
+bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
+{
+ if (lhs.d == rhs.d)
+ return true;
+
+ return lhs.d->pushEnabled == rhs.d->pushEnabled
+ && lhs.d->huffmanCompressionEnabled == rhs.d->huffmanCompressionEnabled
+ && lhs.d->sessionWindowSize == rhs.d->sessionWindowSize
+ && lhs.d->streamWindowSize == rhs.d->streamWindowSize;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h
new file mode 100644
index 0000000000..e5c235e2be
--- /dev/null
+++ b/src/network/access/qhttp2configuration.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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 QHTTP2CONFIGURATION_H
+#define QHTTP2CONFIGURATION_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtCore/qshareddata.h>
+
+#ifndef Q_CLANG_QDOC
+QT_REQUIRE_CONFIG(http);
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QHttp2ConfigurationPrivate;
+class Q_NETWORK_EXPORT QHttp2Configuration
+{
+ friend Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
+
+public:
+ QHttp2Configuration();
+ QHttp2Configuration(const QHttp2Configuration &other);
+ QHttp2Configuration(QHttp2Configuration &&other) noexcept;
+ QHttp2Configuration &operator = (const QHttp2Configuration &other);
+ QHttp2Configuration &operator = (QHttp2Configuration &&other) noexcept;
+
+ ~QHttp2Configuration();
+
+ void setServerPushEnabled(bool enable);
+ bool serverPushEnabled() const;
+
+ void setHuffmanCompressionEnabled(bool enable);
+ bool huffmanCompressionEnabled() const;
+
+ bool setSessionReceiveWindowSize(unsigned size);
+ unsigned sessionReceiveWindowSize() const;
+
+ bool setStreamReceiveWindowSize(unsigned size);
+ unsigned streamReceiveWindowSize() const;
+
+ bool setMaxFrameSize(unsigned size);
+ unsigned maxFrameSize() const;
+
+ void swap(QHttp2Configuration &other) noexcept;
+
+private:
+
+ QSharedDataPointer<QHttp2ConfigurationPrivate> d;
+};
+
+Q_DECLARE_SHARED(QHttp2Configuration)
+
+Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
+
+inline bool operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
+{
+ return !(lhs == rhs);
+}
+
+QT_END_NAMESPACE
+
+#endif // QHTTP2CONFIGURATION_H
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 6609aa0594..dce51d4fd5 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -40,6 +40,7 @@
#include "qhttpnetworkconnection_p.h"
#include "qhttp2protocolhandler_p.h"
+#include "http2/http2frames_p.h"
#include "http2/bitstreams_p.h"
#include <private/qnoncontiguousbytedevice_p.h>
@@ -51,6 +52,8 @@
#include <QtCore/qlist.h>
#include <QtCore/qurl.h>
+#include <qhttp2configuration.h>
+
#ifndef QT_NO_NETWORKPROXY
#include <QtNetwork/qnetworkproxy.h>
#endif
@@ -174,30 +177,11 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan
Q_ASSERT(channel && m_connection);
continuedFrames.reserve(20);
- const ProtocolParameters params(m_connection->http2Parameters());
- Q_ASSERT(params.validate());
-
- maxSessionReceiveWindowSize = params.maxSessionReceiveWindowSize;
-
- const RawSettings &data = params.settingsFrameData;
- for (auto param = data.cbegin(), end = data.cend(); param != end; ++param) {
- switch (param.key()) {
- case Settings::INITIAL_WINDOW_SIZE_ID:
- streamInitialReceiveWindowSize = param.value();
- break;
- case Settings::ENABLE_PUSH_ID:
- pushPromiseEnabled = param.value();
- break;
- case Settings::HEADER_TABLE_SIZE_ID:
- case Settings::MAX_CONCURRENT_STREAMS_ID:
- case Settings::MAX_FRAME_SIZE_ID:
- case Settings::MAX_HEADER_LIST_SIZE_ID:
- // These other settings are just recommendations to our peer. We
- // only check they are not crazy in ProtocolParameters::validate().
- default:
- break;
- }
- }
+ const auto h2Config = m_connection->http2Parameters();
+ maxSessionReceiveWindowSize = h2Config.sessionReceiveWindowSize();
+ pushPromiseEnabled = h2Config.serverPushEnabled();
+ streamInitialReceiveWindowSize = h2Config.streamReceiveWindowSize();
+ encoder.setCompressStrings(h2Config.huffmanCompressionEnabled());
if (!channel->ssl && m_connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// We upgraded from HTTP/1.1 to HTTP/2. channel->request was already sent
@@ -243,7 +227,8 @@ void QHttp2ProtocolHandler::_q_uploadDataReadyRead()
auto data = qobject_cast<QNonContiguousByteDevice *>(sender());
Q_ASSERT(data);
- const qint32 streamID = data->property("HTTP2StreamID").toInt();
+ const qint32 streamID = streamIDs.value(data);
+ Q_ASSERT(streamID != 0);
Q_ASSERT(activeStreams.contains(streamID));
auto &stream = activeStreams[streamID];
@@ -258,7 +243,7 @@ void QHttp2ProtocolHandler::_q_uploadDataReadyRead()
void QHttp2ProtocolHandler::_q_replyDestroyed(QObject *reply)
{
- const quint32 streamID = reply->property("HTTP2StreamID").toInt();
+ const quint32 streamID = streamIDs.take(reply);
if (activeStreams.contains(streamID)) {
sendRST_STREAM(streamID, CANCEL);
markAsReset(streamID);
@@ -266,6 +251,11 @@ void QHttp2ProtocolHandler::_q_replyDestroyed(QObject *reply)
}
}
+void QHttp2ProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData)
+{
+ streamIDs.remove(uploadData);
+}
+
void QHttp2ProtocolHandler::_q_readyRead()
{
_q_receiveReply();
@@ -441,20 +431,17 @@ bool QHttp2ProtocolHandler::sendClientPreface()
return false;
// 6.5 SETTINGS
- const ProtocolParameters params(m_connection->http2Parameters());
- Q_ASSERT(params.validate());
- frameWriter.setOutboundFrame(params.settingsFrame());
+ frameWriter.setOutboundFrame(Http2::configurationToSettingsFrame(m_connection->http2Parameters()));
Q_ASSERT(frameWriter.outboundFrame().payloadSize());
if (!frameWriter.write(*m_socket))
return false;
sessionReceiveWindowSize = maxSessionReceiveWindowSize;
- // ProtocolParameters::validate does not allow maxSessionReceiveWindowSize
- // to be smaller than defaultSessionWindowSize, so everything is OK here with
- // 'delta':
+ // We only send WINDOW_UPDATE for the connection if the size differs from the
+ // default 64 KB:
const auto delta = maxSessionReceiveWindowSize - Http2::defaultSessionWindowSize;
- if (!sendWINDOW_UPDATE(Http2::connectionStreamID, delta))
+ if (delta && !sendWINDOW_UPDATE(Http2::connectionStreamID, delta))
return false;
prefaceSent = true;
@@ -1088,7 +1075,7 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
}
if (identifier == Settings::MAX_FRAME_SIZE_ID) {
- if (newValue < Http2::maxFrameSize || newValue > Http2::maxPayloadSize) {
+ if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) {
connectionError(PROTOCOL_ERROR, "SETTGINGS max frame size is out of range");
return false;
}
@@ -1295,7 +1282,7 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
replyPrivate->connection = m_connection;
replyPrivate->connectionChannel = m_channel;
reply->setSpdyWasUsed(true);
- reply->setProperty("HTTP2StreamID", newStreamID);
+ streamIDs.insert(reply, newStreamID);
connect(reply, SIGNAL(destroyed(QObject*)),
this, SLOT(_q_replyDestroyed(QObject*)));
@@ -1307,7 +1294,9 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
if (auto src = newStream.data()) {
connect(src, SIGNAL(readyRead()), this,
SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
- src->setProperty("HTTP2StreamID", newStreamID);
+ connect(src, &QHttp2ProtocolHandler::destroyed,
+ this, &QHttp2ProtocolHandler::_q_uploadDataDestroyed);
+ streamIDs.insert(src, newStreamID);
}
}
@@ -1350,14 +1339,13 @@ void QHttp2ProtocolHandler::markAsReset(quint32 streamID)
quint32 QHttp2ProtocolHandler::popStreamToResume()
{
quint32 streamID = connectionStreamID;
- const int nQ = sizeof suspendedStreams / sizeof suspendedStreams[0];
using QNR = QHttpNetworkRequest;
- const QNR::Priority ranks[nQ] = {QNR::HighPriority,
- QNR::NormalPriority,
- QNR::LowPriority};
+ const QNR::Priority ranks[] = {QNR::HighPriority,
+ QNR::NormalPriority,
+ QNR::LowPriority};
- for (int i = 0; i < nQ; ++i) {
- auto &queue = suspendedStreams[ranks[i]];
+ for (const QNR::Priority rank : ranks) {
+ auto &queue = suspendedStreams[rank];
auto it = queue.begin();
for (; it != queue.end(); ++it) {
if (!activeStreams.contains(*it))
@@ -1378,9 +1366,7 @@ quint32 QHttp2ProtocolHandler::popStreamToResume()
void QHttp2ProtocolHandler::removeFromSuspended(quint32 streamID)
{
- const int nQ = sizeof suspendedStreams / sizeof suspendedStreams[0];
- for (int i = 0; i < nQ; ++i) {
- auto &q = suspendedStreams[i];
+ for (auto &q : suspendedStreams) {
q.erase(std::remove(q.begin(), q.end(), streamID), q.end());
}
}
@@ -1389,10 +1375,14 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
{
if (activeStreams.contains(streamID)) {
auto &stream = activeStreams[streamID];
- if (stream.reply())
+ if (stream.reply()) {
stream.reply()->disconnect(this);
- if (stream.data())
+ streamIDs.remove(stream.reply());
+ }
+ if (stream.data()) {
stream.data()->disconnect(this);
+ streamIDs.remove(stream.data());
+ }
activeStreams.remove(streamID);
}
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index d91853f613..43fdb136cd 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -55,6 +55,8 @@
#include <private/qabstractprotocolhandler_p.h>
#include <private/qhttpnetworkrequest_p.h>
+#include <access/qhttp2configuration.h>
+
#include <private/http2protocol_p.h>
#include <private/http2streams_p.h>
#include <private/http2frames_p.h>
@@ -95,6 +97,7 @@ public:
private slots:
void _q_uploadDataReadyRead();
void _q_replyDestroyed(QObject* reply);
+ void _q_uploadDataDestroyed(QObject* uploadData);
private:
using Stream = Http2::Stream;
@@ -158,13 +161,15 @@ private:
HPack::Decoder decoder;
HPack::Encoder encoder;
+ QHash<QObject *, int> streamIDs;
QHash<quint32, Stream> activeStreams;
std::deque<quint32> suspendedStreams[3]; // 3 for priorities: High, Normal, Low.
static const std::deque<quint32>::size_type maxRecycledStreams;
std::deque<quint32> recycledStreams;
- // Peer's max frame size.
- quint32 maxFrameSize = Http2::maxFrameSize;
+ // Peer's max frame size (this min is the default value
+ // we start with, that can be updated by SETTINGS frame):
+ quint32 maxFrameSize = Http2::minPayloadLimit;
Http2::FrameReader frameReader;
Http2::Frame inboundFrame;
@@ -176,28 +181,28 @@ private:
// Control flow:
- // This is how many concurrent streams our peer expects from us:
- // 100 is the default value, can be updated by the server's SETTINGS
- // frame(s):
+ // This is how many concurrent streams our peer allows us, 100 is the
+ // initial value, can be updated by the server's SETTINGS frame(s):
quint32 maxConcurrentStreams = Http2::maxConcurrentStreams;
// While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer,
// it's just a hint and we do not actually enforce it (and we can continue
// sending requests and creating streams while maxConcurrentStreams allows).
- // This is the max value, we set it in a ctor from Http2::ProtocolParameters,
- // it does not change after that.
+ // This is our (client-side) maximum possible receive window size, we set
+ // it in a ctor from QHttp2Configuration, it does not change after that.
+ // The default is 64Kb:
qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize;
- // Our session receive window size, default is 64Kb. We'll update it from QNAM's
- // Http2::ProtocolParameters. Signed integer since it can become negative
+ // Our session current receive window size, updated in a ctor from
+ // QHttp2Configuration. Signed integer since it can become negative
// (it's still a valid window size).
qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize;
// Our per-stream receive window size, default is 64 Kb, will be updated
- // from QNAM's Http2::ProtocolParameters. Again, signed - can become negative.
+ // from QHttp2Configuration. Again, signed - can become negative.
qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize;
// These are our peer's receive window sizes, they will be updated by the
- // peer's SETTINGS and WINDOW_UPDATE frames.
+ // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb.
qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize;
qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize;
diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h
index 78585a704d..56db83779a 100644
--- a/src/network/access/qhttpmultipart.h
+++ b/src/network/access/qhttpmultipart.h
@@ -60,12 +60,10 @@ public:
QHttpPart();
QHttpPart(const QHttpPart &other);
~QHttpPart();
-#ifdef Q_COMPILER_RVALUE_REFS
- QHttpPart &operator=(QHttpPart &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QHttpPart &operator=(QHttpPart &&other) noexcept { swap(other); return *this; }
QHttpPart &operator=(const QHttpPart &other);
- void swap(QHttpPart &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QHttpPart &other) noexcept { qSwap(d, other.d); }
bool operator==(const QHttpPart &other) const;
inline bool operator!=(const QHttpPart &other) const
diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h
index 363e0b346c..ead1eadf3b 100644
--- a/src/network/access/qhttpmultipart_p.h
+++ b/src/network/access/qhttpmultipart_p.h
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
class QHttpPartPrivate: public QSharedData, public QNetworkHeadersPrivate
{
public:
- inline QHttpPartPrivate() : bodyDevice(0), headerCreated(false), readPointer(0)
+ inline QHttpPartPrivate() : bodyDevice(nullptr), headerCreated(false), readPointer(0)
{
}
~QHttpPartPrivate()
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 294273d751..21c6359807 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -398,11 +398,12 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica
{
Q_ASSERT(auth);
- // NTLM is a multi phase authentication. Copying credentials between authenticators would mess things up.
+ // NTLM and Negotiate do multi-phase authentication.
+ // Copying credentialsbetween authenticators would mess things up.
if (fromChannel >= 0) {
- if (!isProxy && channels[fromChannel].authMethod == QAuthenticatorPrivate::Ntlm)
- return;
- if (isProxy && channels[fromChannel].proxyAuthMethod == QAuthenticatorPrivate::Ntlm)
+ const QHttpNetworkConnectionChannel &channel = channels[fromChannel];
+ const QAuthenticatorPrivate::Method method = isProxy ? channel.proxyAuthMethod : channel.authMethod;
+ if (method == QAuthenticatorPrivate::Ntlm || method == QAuthenticatorPrivate::Negotiate)
return;
}
@@ -592,24 +593,26 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false));
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), request.url().host());
request.setHeaderField("Authorization", response);
channels[i].authenticationCredentialsSent = true;
}
}
}
+#if QT_CONFIG(networkproxy)
// Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) {
if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false));
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), networkProxy.hostName());
request.setHeaderField("Proxy-Authorization", response);
channels[i].proxyCredentialsSent = true;
}
}
}
+#endif // QT_CONFIG(networkproxy)
}
QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetworkRequest &request)
@@ -1318,8 +1321,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16
: QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt, connectionType)), parent)
{
Q_D(QHttpNetworkConnection);
- d->networkSession = qMove(networkSession);
+ 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,
@@ -1330,8 +1337,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS
connectionType)), parent)
{
Q_D(QHttpNetworkConnection);
- d->networkSession = qMove(networkSession);
+ 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 +1351,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 +1365,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()
{
@@ -1438,21 +1457,16 @@ void QHttpNetworkConnection::setConnectionType(ConnectionType type)
d->connectionType = type;
}
-Http2::ProtocolParameters QHttpNetworkConnection::http2Parameters() const
+QHttp2Configuration QHttpNetworkConnection::http2Parameters() const
{
Q_D(const QHttpNetworkConnection);
return d->http2Parameters;
}
-void QHttpNetworkConnection::setHttp2Parameters(const Http2::ProtocolParameters &params)
+void QHttpNetworkConnection::setHttp2Parameters(const QHttp2Configuration &params)
{
Q_D(QHttpNetworkConnection);
- if (params.validate()) {
- d->http2Parameters = params;
- } else {
- qCWarning(QT_HTTP2)
- << "invalid HTTP/2 parameters, falling back to defaults instead";
- }
+ d->http2Parameters = params;
}
// SSL support below
@@ -1477,7 +1491,7 @@ QSharedPointer<QSslContext> QHttpNetworkConnection::sslContext()
void QHttpNetworkConnection::setSslContext(QSharedPointer<QSslContext> context)
{
Q_D(QHttpNetworkConnection);
- d->sslContext = qMove(context);
+ d->sslContext = std::move(context);
}
void QHttpNetworkConnection::ignoreSslErrors(int channel)
@@ -1531,6 +1545,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 2bd727e0af..6808a0c0ac 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -57,6 +57,8 @@
#include <QtNetwork/qabstractsocket.h>
#include <QtNetwork/qnetworksession.h>
+#include <qhttp2configuration.h>
+
#include <private/qobject_p.h>
#include <qauthenticator.h>
#include <qnetworkproxy.h>
@@ -67,6 +69,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>
@@ -101,10 +104,10 @@ public:
#ifndef QT_NO_BEARERMANAGEMENT
explicit QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false,
ConnectionType connectionType = ConnectionTypeHTTP,
- QObject *parent = 0, QSharedPointer<QNetworkSession> networkSession
+ QObject *parent = nullptr, QSharedPointer<QNetworkSession> networkSession
= QSharedPointer<QNetworkSession>());
QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80,
- bool encrypt = false, QObject *parent = 0,
+ bool encrypt = false, QObject *parent = nullptr,
QSharedPointer<QNetworkSession> networkSession = QSharedPointer<QNetworkSession>(),
ConnectionType connectionType = ConnectionTypeHTTP);
#else
@@ -141,8 +144,8 @@ public:
ConnectionType connectionType();
void setConnectionType(ConnectionType type);
- Http2::ProtocolParameters http2Parameters() const;
- void setHttp2Parameters(const Http2::ProtocolParameters &params);
+ QHttp2Configuration http2Parameters() const;
+ void setHttp2Parameters(const QHttp2Configuration &params);
#ifndef QT_NO_SSL
void setSslConfiguration(const QSslConfiguration &config);
@@ -156,6 +159,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)
@@ -289,9 +296,17 @@ public:
QSharedPointer<QNetworkSession> networkSession;
#endif
- Http2::ProtocolParameters http2Parameters;
+ QHttp2Configuration 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 8f94cef32b..39f392a79b 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -40,6 +40,7 @@
#include "qhttpnetworkconnectionchannel_p.h"
#include "qhttpnetworkconnection_p.h"
+#include "qhttp2configuration.h"
#include "private/qnoncontiguousbytedevice_p.h"
#include <qpair.h>
@@ -48,6 +49,7 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/qspdyprotocolhandler_p.h>
+#include <private/http2protocol_p.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -59,6 +61,8 @@
#include "private/qnetworksession_p.h"
#endif
+#include "private/qnetconmonitor_p.h"
+
QT_BEGIN_NAMESPACE
namespace
@@ -902,6 +906,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
@@ -938,9 +952,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
if (tryProtocolUpgrade) {
// Let's augment our request with some magic headers and try to
// switch to HTTP/2.
- const Http2::ProtocolParameters params(connection->http2Parameters());
- Q_ASSERT(params.validate());
- params.addProtocolUpgradeHeaders(&request);
+ Http2::appendProtocolUpgradeHeaders(connection->http2Parameters(), &request);
}
sendRequest();
}
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index c9c3172304..a8b635c45a 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -444,6 +444,9 @@ QAuthenticatorPrivate::Method QHttpNetworkReplyPrivate::authenticationMethod(boo
} else if (method < QAuthenticatorPrivate::DigestMd5
&& line.startsWith("digest")) {
method = QAuthenticatorPrivate::DigestMd5;
+ } else if (method < QAuthenticatorPrivate::Negotiate
+ && line.startsWith("negotiate")) {
+ method = QAuthenticatorPrivate::Negotiate;
}
}
return method;
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 863e21ea3e..12cfe359aa 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -89,7 +89,7 @@ class Q_AUTOTEST_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkH
Q_OBJECT
public:
- explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = 0);
+ explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = nullptr);
virtual ~QHttpNetworkReply();
QUrl url() const override;
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index 46a6615f4d..63a3c4f204 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -190,7 +190,7 @@ public:
QHttpNetworkConnection::ConnectionType connectionType,
QSharedPointer<QNetworkSession> networkSession)
: QHttpNetworkConnection(hostName, port, encrypt, connectionType, /*parent=*/0,
- qMove(networkSession))
+ std::move(networkSession))
#endif
{
setExpires(true);
@@ -354,9 +354,9 @@ void QHttpThreadDelegate::startRequest()
networkSession);
#endif // QT_NO_BEARERMANAGEMENT
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
- && http2Parameters.validate()) {
+ || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
httpConnection->setHttp2Parameters(http2Parameters);
- } // else we ignore invalid parameters and use our own defaults.
+ }
#ifndef QT_NO_SSL
// Set the QSslConfiguration from this QNetworkRequest.
if (ssl)
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 019a8b8b74..355d1afc30 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -62,6 +62,7 @@
#include <QNetworkReply>
#include "qhttpnetworkrequest_p.h"
#include "qhttpnetworkconnection_p.h"
+#include "qhttp2configuration.h"
#include <QSharedPointer>
#include <QScopedPointer>
#include "private/qnoncontiguousbytedevice_p.h"
@@ -82,7 +83,7 @@ class QHttpThreadDelegate : public QObject
{
Q_OBJECT
public:
- explicit QHttpThreadDelegate(QObject *parent = 0);
+ explicit QHttpThreadDelegate(QObject *parent = nullptr);
~QHttpThreadDelegate();
@@ -116,7 +117,7 @@ public:
qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;
QString incomingErrorDetail;
- Http2::ProtocolParameters http2Parameters;
+ QHttp2Configuration http2Parameters;
#ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession;
#endif
@@ -207,7 +208,7 @@ public:
: QNonContiguousByteDevice(),
wantDataPending(false),
m_amount(0),
- m_data(0),
+ m_data(nullptr),
m_atEnd(aE),
m_size(s),
m_pos(0)
@@ -240,12 +241,12 @@ public:
// Do nothing, we already sent a wantData signal and wait for results
len = 0;
}
- return 0;
+ return nullptr;
}
bool advanceReadPointer(qint64 a) override
{
- if (m_data == 0)
+ if (m_data == nullptr)
return false;
m_amount -= a;
@@ -269,7 +270,7 @@ public:
bool reset() override
{
m_amount = 0;
- m_data = 0;
+ m_data = nullptr;
m_dataArray.clear();
if (wantDataPending) {
diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h
index 548675728f..31111ca2a5 100644
--- a/src/network/access/qnetworkaccessauthenticationmanager_p.h
+++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h
@@ -90,12 +90,12 @@ public:
void cacheCredentials(const QUrl &url, const QAuthenticator *auth);
QNetworkAuthenticationCredential fetchCachedCredentials(const QUrl &url,
- const QAuthenticator *auth = 0);
+ const QAuthenticator *auth = nullptr);
#ifndef QT_NO_NETWORKPROXY
void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth);
QNetworkAuthenticationCredential fetchCachedProxyCredentials(const QNetworkProxy &proxy,
- const QAuthenticator *auth = 0);
+ const QAuthenticator *auth = nullptr);
#endif
void clearCache();
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index 272dd22097..566e410051 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
class QNetworkAccessBackendFactoryData: public QList<QNetworkAccessBackendFactory *>
{
public:
- QNetworkAccessBackendFactoryData() : mutex(QMutex::Recursive)
+ QNetworkAccessBackendFactoryData()
{
valid.ref();
}
@@ -68,7 +68,7 @@ public:
valid.deref();
}
- QMutex mutex;
+ QRecursiveMutex mutex;
//this is used to avoid (re)constructing factory data from destructors of other global classes
static QBasicAtomicInt valid;
};
@@ -83,7 +83,7 @@ QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
{
- if (QNetworkAccessBackendFactoryData::valid.load()) {
+ if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
QMutexLocker locker(&factoryData()->mutex);
factoryData()->removeAll(this);
}
@@ -92,7 +92,7 @@ QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
const QNetworkRequest &request)
{
- if (QNetworkAccessBackendFactoryData::valid.load()) {
+ if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
QMutexLocker locker(&factoryData()->mutex);
QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(),
end = factoryData()->constEnd();
@@ -110,7 +110,7 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM
QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const
{
- if (QNetworkAccessBackendFactoryData::valid.load()) {
+ if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
QMutexLocker locker(&factoryData()->mutex);
QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin();
QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd();
diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp
index 00bb18cb82..b694a2c999 100644
--- a/src/network/access/qnetworkaccesscache.cpp
+++ b/src/network/access/qnetworkaccesscache.cpp
@@ -40,11 +40,12 @@
#include "qnetworkaccesscache_p.h"
#include "QtCore/qpointer.h"
#include "QtCore/qdatetime.h"
-#include "QtCore/qqueue.h"
#include "qnetworkaccessmanager_p.h"
#include "qnetworkreply_p.h"
#include "qnetworkrequest.h"
+#include <vector>
+
QT_BEGIN_NAMESPACE
enum ExpiryTimeEnum {
@@ -63,7 +64,7 @@ namespace {
struct QNetworkAccessCache::Node
{
QDateTime timestamp;
- QQueue<Receiver> receiverQueue;
+ std::vector<Receiver> receiverQueue;
QByteArray key;
Node *older, *newer;
@@ -277,10 +278,7 @@ bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, c
// object is not shareable and is in use
// queue for later use
Q_ASSERT(node->older == 0 && node->newer == 0);
- Receiver receiver;
- receiver.object = target;
- receiver.member = member;
- node->receiverQueue.enqueue(receiver);
+ node->receiverQueue.push_back({target, member});
// request queued
return true;
@@ -331,17 +329,19 @@ void QNetworkAccessCache::releaseEntry(const QByteArray &key)
Q_ASSERT(node->useCount > 0);
// are there other objects waiting?
- if (!node->receiverQueue.isEmpty()) {
+ const auto objectStillExists = [](const Receiver &r) { return !r.object.isNull(); };
+
+ auto &queue = node->receiverQueue;
+ auto qit = std::find_if(queue.begin(), queue.end(), objectStillExists);
+
+ const Receiver receiver = qit == queue.end() ? Receiver{} : std::move(*qit++) ;
+
+ queue.erase(queue.begin(), qit);
+
+ if (receiver.object) {
// queue another activation
- Receiver receiver;
- do {
- receiver = node->receiverQueue.dequeue();
- } while (receiver.object.isNull() && !node->receiverQueue.isEmpty());
-
- if (!receiver.object.isNull()) {
- emitEntryReady(node, receiver.object, receiver.member);
- return;
- }
+ emitEntryReady(node, receiver.object, receiver.member);
+ return;
}
if (!--node->useCount) {
diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp
index 5ad820eba0..51ed2f5a55 100644
--- a/src/network/access/qnetworkaccessftpbackend.cpp
+++ b/src/network/access/qnetworkaccessftpbackend.cpp
@@ -99,6 +99,8 @@ public:
connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater()));
close();
}
+
+ using QFtp::clearError;
};
QNetworkAccessFtpBackend::QNetworkAccessFtpBackend()
@@ -282,7 +284,10 @@ void QNetworkAccessFtpBackend::ftpDone()
}
// check for errors:
- if (ftp->error() != QFtp::NoError) {
+ if (state == CheckingFeatures && ftp->error() == QFtp::UnknownError) {
+ qWarning("QNetworkAccessFtpBackend: HELP command failed, ignoring it");
+ ftp->clearError();
+ } else if (ftp->error() != QFtp::NoError) {
QString msg;
if (operation() == QNetworkAccessManager::GetOperation)
msg = tr("Error while downloading %1: %2");
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index b9c8116421..76b95b5823 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -70,6 +70,7 @@
#include "QtNetwork/private/qauthenticator_p.h"
#include "QtNetwork/qsslconfiguration.h"
#include "QtNetwork/qnetworkconfigmanager.h"
+#include "QtNetwork/private/http2protocol_p.h"
#if QT_CONFIG(http)
#include "qhttpmultipart.h"
@@ -90,6 +91,8 @@
#include "qnetworkreplywasmimpl_p.h"
#endif
+#include "qnetconmonitor_p.h"
+
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
@@ -486,18 +489,26 @@ 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.isNetworkAccessible();
+#else
+ d->networkAccessible = d->statusMonitor.isNetworkAccessible() ? 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,6 +1041,7 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ
void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
{
Q_D(QNetworkAccessManager);
+
d->networkConfiguration = config;
d->customNetworkConfiguration = true;
d->createSession(config);
@@ -1048,7 +1060,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 +1087,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 {
@@ -1114,6 +1126,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;
@@ -1162,7 +1180,6 @@ QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(
#endif // QT_NO_BEARERMANAGEMENT
-
#ifndef QT_NO_SSL
/*!
\since 5.2
@@ -1387,6 +1404,11 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
}
+ if (autoDeleteReplies()
+ && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) {
+ req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true);
+ }
+
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
@@ -1435,35 +1457,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() &&
@@ -1510,8 +1554,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;
}
@@ -1520,7 +1566,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. Once it does: uncomment the condition below
+ if (!isLocalFile /*&& !d->statusMonitor.isEnabled()*/) {
connect(this, SIGNAL(networkSessionConnected()),
reply, SLOT(_q_networkSessionConnected()));
}
@@ -1631,13 +1679,50 @@ void QNetworkAccessManager::clearConnectionCache()
QNetworkAccessManagerPrivate::clearConnectionCache(this);
}
+
+/*!
+ \since 5.14
+
+ Returns the true if QNetworkAccessManager is currently configured
+ to automatically delete QNetworkReplies, false otherwise.
+
+ \sa setAutoDeleteReplies,
+ QNetworkRequest::AutoDeleteReplyOnFinishAttribute
+*/
+bool QNetworkAccessManager::autoDeleteReplies() const
+{
+ return d_func()->autoDeleteReplies;
+}
+
+/*!
+ \since 5.14
+
+ Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}.
+
+ Setting \a shouldAutoDelete to true is the same as setting the
+ QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to
+ true on all \e{future} \l {QNetworkRequest} {QNetworkRequests}
+ passed to this instance of QNetworkAccessManager unless the
+ attribute was already explicitly set on the QNetworkRequest.
+
+ \sa autoDeleteReplies,
+ QNetworkRequest::AutoDeleteReplyOnFinishAttribute
+*/
+void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
+{
+ d_func()->autoDeleteReplies = shouldAutoDelete;
+}
+
void QNetworkAccessManagerPrivate::_q_replyFinished()
{
Q_Q(QNetworkAccessManager);
QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
- if (reply)
+ if (reply) {
emit q->finished(reply);
+ if (reply->request().attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false).toBool())
+ QMetaObject::invokeMethod(reply, [reply] { reply->deleteLater(); }, Qt::QueuedConnection);
+ }
#ifndef QT_NO_BEARERMANAGEMENT
// If there are no active requests, release our reference to the network session.
@@ -1989,7 +2074,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.
@@ -2019,6 +2110,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)) {
@@ -2051,6 +2145,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)) {
@@ -2062,6 +2159,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..98498d07d2 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -167,6 +167,9 @@ public:
void setRedirectPolicy(QNetworkRequest::RedirectPolicy policy);
QNetworkRequest::RedirectPolicy redirectPolicy() const;
+ bool autoDeleteReplies() const;
+ void setAutoDeleteReplies(bool autoDelete);
+
Q_SIGNALS:
#ifndef QT_NO_NETWORKPROXY
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
@@ -209,10 +212,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..67ea2094b3 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 "private/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,9 @@ public:
QScopedPointer<QHstsStore> stsStore;
#endif // QT_CONFIG(settings)
bool stsEnabled = false;
+ mutable QNetworkStatusMonitor statusMonitor;
+
+ bool autoDeleteReplies = false;
#ifndef QT_NO_BEARERMANAGEMENT
Q_AUTOTEST_EXPORT static const QWeakPointer<const QNetworkSession> getNetworkSession(const QNetworkAccessManager *manager);
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index b7cf989477..903de322ff 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -46,6 +46,7 @@
#include "QtCore/qdebug.h"
#include "QtCore/qlist.h"
#include "QtCore/qlocale.h"
+#include <QtCore/qregexp.h>
#include "QtCore/qstring.h"
#include "QtCore/qstringlist.h"
#include "QtCore/qurl.h"
diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h
index e462b98555..b712b63849 100644
--- a/src/network/access/qnetworkcookie.h
+++ b/src/network/access/qnetworkcookie.h
@@ -66,12 +66,10 @@ public:
explicit QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray());
QNetworkCookie(const QNetworkCookie &other);
~QNetworkCookie();
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkCookie &operator=(QNetworkCookie &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkCookie &operator=(QNetworkCookie &&other) noexcept { swap(other); return *this; }
QNetworkCookie &operator=(const QNetworkCookie &other);
- void swap(QNetworkCookie &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkCookie &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkCookie &other) const;
inline bool operator!=(const QNetworkCookie &other) const
diff --git a/src/network/access/qnetworkdiskcache_p.h b/src/network/access/qnetworkdiskcache_p.h
index f7988e7dda..c797e63830 100644
--- a/src/network/access/qnetworkdiskcache_p.h
+++ b/src/network/access/qnetworkdiskcache_p.h
@@ -67,7 +67,7 @@ class QFile;
class QCacheItem
{
public:
- QCacheItem() : file(0)
+ QCacheItem() : file(nullptr)
{
}
~QCacheItem()
@@ -85,7 +85,7 @@ public:
metaData = QNetworkCacheMetaData();
data.close();
delete file;
- file = 0;
+ file = nullptr;
}
void writeHeader(QFile *device) const;
void writeCompressedData(QFile *device) const;
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 489c489e5c..8ac81d1780 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")
@@ -792,12 +798,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
- // Propagate Http/2 settings if any
- const QVariant blob(manager->property(Http2::http2ParametersPropertyName));
- if (blob.isValid() && blob.canConvert<Http2::ProtocolParameters>())
- delegate->http2Parameters = blob.value<Http2::ProtocolParameters>();
+ // Propagate Http/2 settings:
+ delegate->http2Parameters = request.http2Configuration();
#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
@@ -1048,59 +1053,39 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
if (!q->isOpen())
return;
- int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1;
+ if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice)
+ initCacheSaveDevice();
+
+ // This is going to look a little strange. When downloading data while a
+ // HTTP redirect is happening (and enabled), we write the redirect
+ // response to the cache. However, we do not append it to our internal
+ // buffer as that will contain the response data only for the final
+ // response
+ if (cacheSaveDevice)
+ cacheSaveDevice->write(d);
+ if (!isHttpRedirectResponse()) {
+ buffer.append(d);
+ bytesDownloaded += d.size();
+ }
+ bytesBuffered += d.size();
+
+ int pendingSignals = pendingDownloadDataEmissions->fetchAndSubAcquire(1) - 1;
if (pendingSignals > 0) {
// Some more signal emissions to this slot are pending.
// Instead of writing the downstream data, we wait
// and do it in the next call we get
// (signal comppression)
- pendingDownloadData.append(d);
return;
}
- pendingDownloadData.append(d);
- d.clear();
- // We need to usa a copy for calling writeDownstreamData as we could
- // possibly recurse into this this function when we call
- // appendDownstreamDataSignalEmissions because the user might call
- // processEvents() or spin an event loop when this occur.
- QByteDataBuffer pendingDownloadDataCopy = pendingDownloadData;
- pendingDownloadData.clear();
-
- if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) {
- initCacheSaveDevice();
- }
-
- qint64 bytesWritten = 0;
- for (int i = 0; i < pendingDownloadDataCopy.bufferCount(); i++) {
- QByteArray const &item = pendingDownloadDataCopy[i];
-
- // This is going to look a little strange. When downloading data while a
- // HTTP redirect is happening (and enabled), we write the redirect
- // response to the cache. However, we do not append it to our internal
- // buffer as that will contain the response data only for the final
- // response
- if (cacheSaveDevice)
- cacheSaveDevice->write(item.constData(), item.size());
-
- if (!isHttpRedirectResponse())
- buffer.append(item);
-
- bytesWritten += item.size();
- }
- bytesBuffered += bytesWritten;
- pendingDownloadDataCopy.clear();
+ if (isHttpRedirectResponse())
+ return;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
if (preMigrationDownloaded != Q_INT64_C(-1))
totalSize = totalSize.toLongLong() + preMigrationDownloaded;
- if (isHttpRedirectResponse())
- return;
-
- bytesDownloaded += bytesWritten;
-
emit q->readyRead();
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
@@ -1808,7 +1793,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;
@@ -1896,7 +1881,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);
@@ -2185,7 +2170,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/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index f5f01d0811..ef69ce0653 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -63,7 +63,6 @@
#include <QtNetwork/QNetworkCacheMetaData>
#include <private/qhttpnetworkrequest_p.h>
-#include <private/qbytedata_p.h>
#include <private/qnetworkreply_p.h>
#include <QtNetwork/QNetworkProxy>
#include <QtNetwork/QNetworkSession>
@@ -248,7 +247,6 @@ public:
quint64 resumeOffset;
qint64 preMigrationDownloaded;
- QByteDataBuffer pendingDownloadData; // For signal compression
qint64 bytesDownloaded;
qint64 bytesBuffered;
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index a794b492e7..6eab500e8c 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -158,7 +158,7 @@ void QNetworkReplyImplPrivate::_q_startOperation()
} else {
if (state != Finished) {
if (operation == QNetworkAccessManager::GetOperation)
- pendingNotifications.append(NotifyDownstreamReadyWrite);
+ pendingNotifications.push_back(NotifyDownstreamReadyWrite);
handleNotifications();
}
@@ -368,6 +368,7 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
outgoingData = data;
request = req;
+ originalRequest = req;
url = request.url();
operation = op;
@@ -432,8 +433,9 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
void QNetworkReplyImplPrivate::backendNotify(InternalNotifications notification)
{
Q_Q(QNetworkReplyImpl);
- if (!pendingNotifications.contains(notification))
- pendingNotifications.enqueue(notification);
+ const auto it = std::find(pendingNotifications.cbegin(), pendingNotifications.cend(), notification);
+ if (it == pendingNotifications.cend())
+ pendingNotifications.push_back(notification);
if (pendingNotifications.size() == 1)
QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated));
@@ -444,14 +446,9 @@ void QNetworkReplyImplPrivate::handleNotifications()
if (notificationHandlingPaused)
return;
- NotificationQueue current = pendingNotifications;
- pendingNotifications.clear();
-
- if (state != Working)
- return;
-
- while (state == Working && !current.isEmpty()) {
- InternalNotifications notification = current.dequeue();
+ for (InternalNotifications notification : qExchange(pendingNotifications, {})) {
+ if (state != Working)
+ return;
switch (notification) {
case NotifyDownstreamReadyWrite:
if (copyDevice)
@@ -465,8 +462,7 @@ void QNetworkReplyImplPrivate::handleNotifications()
break;
case NotifyCopyFinished: {
- QIODevice *dev = copyDevice;
- copyDevice = 0;
+ QIODevice *dev = qExchange(copyDevice, nullptr);
backend->copyFinished(dev);
break;
}
@@ -1116,7 +1112,6 @@ bool QNetworkReplyImplPrivate::migrateBackend()
return true;
}
-#ifndef QT_NO_BEARERMANAGEMENT
QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
const QNetworkRequest &req,
QNetworkAccessManager::Operation op)
@@ -1141,7 +1136,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 f4e8284ab6..8cec79541a 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -74,7 +74,7 @@ class QNetworkReplyImpl: public QNetworkReply
{
Q_OBJECT
public:
- QNetworkReplyImpl(QObject *parent = 0);
+ QNetworkReplyImpl(QObject *parent = nullptr);
~QNetworkReplyImpl();
virtual void abort() override;
@@ -117,8 +117,6 @@ public:
NotifyCopyFinished
};
- typedef QQueue<InternalNotifications> NotificationQueue;
-
QNetworkReplyImplPrivate();
void _q_startOperation();
@@ -178,7 +176,7 @@ public:
bool cacheEnabled;
QIODevice *cacheSaveDevice;
- NotificationQueue pendingNotifications;
+ std::vector<InternalNotifications> pendingNotifications;
bool notificationHandlingPaused;
QUrl urlForLastAuthentication;
@@ -209,7 +207,6 @@ public:
};
Q_DECLARE_TYPEINFO(QNetworkReplyImplPrivate::InternalNotifications, Q_PRIMITIVE_TYPE);
-#ifndef QT_NO_BEARERMANAGEMENT
class QDisabledNetworkReply : public QNetworkReply
{
Q_OBJECT
@@ -223,7 +220,6 @@ public:
protected:
qint64 readData(char *, qint64) override { return -1; }
};
-#endif
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index f15c43cdd8..118fb6b1fb 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -42,6 +42,10 @@
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+#include "qhttp2configuration.h"
+#include "private/http2protocol_p.h"
+#endif
#include "QtCore/qshareddata.h"
#include "QtCore/qlocale.h"
#include "QtCore/qdatetime.h"
@@ -331,6 +335,12 @@ QT_BEGIN_NAMESPACE
\omitvalue ResourceTypeAttribute
+ \value AutoDeleteReplyOnFinishAttribute
+ Requests only, type: QMetaType::Bool (default: false)
+ If set, this attribute will make QNetworkAccessManager delete
+ the QNetworkReply after having emitted "finished".
+ (This value was introduced in 5.14.)
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -439,6 +449,9 @@ public:
sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
#endif
peerVerifyName = other.peerVerifyName;
+#if QT_CONFIG(http)
+ h2Configuration = other.h2Configuration;
+#endif
}
inline bool operator==(const QNetworkRequestPrivate &other) const
@@ -448,7 +461,11 @@ public:
rawHeaders == other.rawHeaders &&
attributes == other.attributes &&
maxRedirectsAllowed == other.maxRedirectsAllowed &&
- peerVerifyName == other.peerVerifyName;
+ peerVerifyName == other.peerVerifyName
+#if QT_CONFIG(http)
+ && h2Configuration == other.h2Configuration
+#endif
+ ;
// don't compare cookedHeaders
}
@@ -459,16 +476,39 @@ public:
#endif
int maxRedirectsAllowed;
QString peerVerifyName;
+#if QT_CONFIG(http)
+ QHttp2Configuration h2Configuration;
+#endif
};
/*!
+ Constructs a QNetworkRequest object with no URL to be requested.
+ Use setUrl() to set one.
+
+ \sa url(), setUrl()
+*/
+QNetworkRequest::QNetworkRequest()
+ : d(new QNetworkRequestPrivate)
+{
+#if QT_CONFIG(http)
+ // Initial values proposed by RFC 7540 are quite draconian,
+ // so unless an application will set its own parameters, we
+ // make stream window size larger and increase (via WINDOW_UPDATE)
+ // the session window size. These are our 'defaults':
+ d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize);
+ d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize);
+ d->h2Configuration.setServerPushEnabled(false);
+#endif // QT_CONFIG(http)
+}
+
+/*!
Constructs a QNetworkRequest object with \a url as the URL to be
requested.
\sa url(), setUrl()
*/
QNetworkRequest::QNetworkRequest(const QUrl &url)
- : d(new QNetworkRequestPrivate)
+ : QNetworkRequest()
{
d->url = url;
}
@@ -818,6 +858,52 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+/*!
+ \since 5.14
+
+ Returns the current parameters that QNetworkAccessManager is
+ using for this request and its underlying HTTP/2 connection.
+ This is either a configuration previously set by an application
+ or a default configuration.
+
+ The default values that QNetworkAccessManager is using are:
+
+ \list
+ \li Window size for connection-level flowcontrol is 2147483647 octets
+ \li Window size for stream-level flowcontrol is 21474836 octets
+ \li Max frame size is 16384
+ \endlist
+
+ By default, server push is disabled, Huffman compression and
+ string indexing are enabled.
+
+ \sa setHttp2Configuration
+*/
+QHttp2Configuration QNetworkRequest::http2Configuration() const
+{
+ return d->h2Configuration;
+}
+
+/*!
+ \since 5.14
+
+ Sets request's HTTP/2 parameters from \a configuration.
+
+ \note The configuration must be set prior to making a request.
+ \note HTTP/2 multiplexes several streams in a single HTTP/2
+ connection. This implies that QNetworkAccessManager will use
+ the configuration found in the first request from a series
+ of requests sent to the same host.
+
+ \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration
+*/
+void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration)
+{
+ d->h2Configuration = configuration;
+}
+#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
@@ -1338,7 +1424,7 @@ QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
{
- return QLocale::c().toString(dt, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'"))
+ return QLocale::c().toString(dt, u"ddd, dd MMM yyyy hh:mm:ss 'GMT'")
.toLatin1();
}
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index efb9cbecba..e09ff8aaae 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
class QSslConfiguration;
+class QHttp2Configuration;
class QNetworkRequestPrivate;
class Q_NETWORK_EXPORT QNetworkRequest
@@ -98,6 +99,7 @@ public:
RedirectPolicyAttribute,
Http2DirectAttribute,
ResourceTypeAttribute, // internal
+ AutoDeleteReplyOnFinishAttribute,
User = 1000,
UserMax = 32767
@@ -127,15 +129,14 @@ public:
};
- explicit QNetworkRequest(const QUrl &url = QUrl());
+ QNetworkRequest();
+ explicit QNetworkRequest(const QUrl &url);
QNetworkRequest(const QNetworkRequest &other);
~QNetworkRequest();
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkRequest &operator=(QNetworkRequest &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkRequest &operator=(QNetworkRequest &&other) noexcept { swap(other); return *this; }
QNetworkRequest &operator=(const QNetworkRequest &other);
- void swap(QNetworkRequest &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkRequest &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkRequest &other) const;
inline bool operator!=(const QNetworkRequest &other) const
@@ -175,6 +176,10 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+ QHttp2Configuration http2Configuration() const;
+ void setHttp2Configuration(const QHttp2Configuration &configuration);
+#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp
index 403c01e974..f845235bf7 100644
--- a/src/network/access/qspdyprotocolhandler.cpp
+++ b/src/network/access/qspdyprotocolhandler.cpp
@@ -305,7 +305,7 @@ bool QSpdyProtocolHandler::sendRequest()
currentReply->setSpdyWasUsed(true);
qint32 streamID = generateNextStreamID();
- currentReply->setProperty("SPDYStreamID", streamID);
+ m_streamIDs.insert(currentReply, streamID);
currentReply->setRequest(currentRequest);
currentReply->d_func()->connection = m_connection;
@@ -322,7 +322,7 @@ bool QSpdyProtocolHandler::sendRequest()
void QSpdyProtocolHandler::_q_replyDestroyed(QObject* reply)
{
- qint32 streamID = reply->property("SPDYStreamID").toInt();
+ qint32 streamID = m_streamIDs.take(reply);
if (m_inFlightStreams.remove(streamID))
sendRST_STREAM(streamID, RST_STREAM_CANCEL);
}
@@ -624,10 +624,12 @@ void QSpdyProtocolHandler::sendSYN_STREAM(const HttpMessagePair &messagePair,
// hack: set the stream ID on the device directly, so when we get
// the signal for uploading we know which stream we are sending on
- request.uploadByteDevice()->setProperty("SPDYStreamID", streamID);
+ m_streamIDs.insert(request.uploadByteDevice(), streamID);
QObject::connect(request.uploadByteDevice(), SIGNAL(readyRead()), this,
SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
+ QObject::connect(request.uploadByteDevice(), SIGNAL(destroyed(QObject*)), this,
+ SLOT(_q_uploadDataDestroyed(QObject *)));
}
QByteArray namesAndValues = composeHeader(request);
@@ -663,6 +665,11 @@ void QSpdyProtocolHandler::sendSYN_STREAM(const HttpMessagePair &messagePair,
uploadData(streamID);
}
+void QSpdyProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData)
+{
+ m_streamIDs.remove(uploadData);
+}
+
void QSpdyProtocolHandler::sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode)
{
char wireData[8];
@@ -756,7 +763,7 @@ void QSpdyProtocolHandler::_q_uploadDataReadyRead()
{
QNonContiguousByteDevice *device = qobject_cast<QNonContiguousByteDevice *>(sender());
Q_ASSERT(device);
- qint32 streamID = device->property("SPDYStreamID").toInt();
+ qint32 streamID = m_streamIDs.value(device);
Q_ASSERT(streamID > 0);
uploadData(streamID);
}
diff --git a/src/network/access/qspdyprotocolhandler_p.h b/src/network/access/qspdyprotocolhandler_p.h
index dd93a9aba2..14e2ff388a 100644
--- a/src/network/access/qspdyprotocolhandler_p.h
+++ b/src/network/access/qspdyprotocolhandler_p.h
@@ -110,6 +110,7 @@ public:
private slots:
void _q_uploadDataReadyRead();
void _q_replyDestroyed(QObject*);
+ void _q_uploadDataDestroyed(QObject *);
private:
@@ -216,6 +217,7 @@ private:
bool m_waitingForCompleteStream;
z_stream m_deflateStream;
z_stream m_inflateStream;
+ QHash<QObject *, qint32> m_streamIDs;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::DataFrameFlags)
diff --git a/src/network/bearer/qbearerengine.cpp b/src/network/bearer/qbearerengine.cpp
index 677da08cb6..06bf449611 100644
--- a/src/network/bearer/qbearerengine.cpp
+++ b/src/network/bearer/qbearerengine.cpp
@@ -38,6 +38,8 @@
****************************************************************************/
#include "qbearerengine_p.h"
+#include <QtCore/private/qlocking_p.h>
+
#include <algorithm>
#ifndef QT_NO_BEARERMANAGEMENT
@@ -46,24 +48,23 @@ QT_BEGIN_NAMESPACE
static void cleanUpConfigurations(QHash<QString, QNetworkConfigurationPrivatePointer> &configurations)
{
- for (const auto &ptr : qAsConst(configurations)) {
+ for (auto &ptr : qExchange(configurations, {})) {
ptr->isValid = false;
ptr->id.clear();
}
- configurations.clear();
}
static bool hasUsedConfiguration(const QHash<QString, QNetworkConfigurationPrivatePointer> &configurations)
{
auto isUsed = [](const QNetworkConfigurationPrivatePointer &ptr) {
- return ptr->ref.load() > 1;
+ return ptr->ref.loadRelaxed() > 1;
};
const auto end = configurations.end();
return std::find_if(configurations.begin(), end, isUsed) != end;
}
QBearerEngine::QBearerEngine(QObject *parent)
- : QObject(parent), mutex(QMutex::Recursive)
+ : QObject(parent)
{
}
@@ -87,7 +88,7 @@ bool QBearerEngine::requiresPolling() const
*/
bool QBearerEngine::configurationsInUse() const
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
return hasUsedConfiguration(accessPointConfigurations)
|| hasUsedConfiguration(snapConfigurations)
|| hasUsedConfiguration(userChoiceConfigurations);
diff --git a/src/network/bearer/qbearerengine_p.h b/src/network/bearer/qbearerengine_p.h
index 5fc2578a78..c69f478b26 100644
--- a/src/network/bearer/qbearerengine_p.h
+++ b/src/network/bearer/qbearerengine_p.h
@@ -77,7 +77,7 @@ class Q_NETWORK_EXPORT QBearerEngine : public QObject
friend class QNetworkConfigurationManagerPrivate;
public:
- explicit QBearerEngine(QObject *parent = 0);
+ explicit QBearerEngine(QObject *parent = nullptr);
virtual ~QBearerEngine();
virtual bool hasIdentifier(const QString &id) = 0;
@@ -105,7 +105,7 @@ protected:
QHash<QString, QNetworkConfigurationPrivatePointer> snapConfigurations;
QHash<QString, QNetworkConfigurationPrivatePointer> userChoiceConfigurations;
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
};
QT_END_NAMESPACE
diff --git a/src/network/bearer/qbearerplugin_p.h b/src/network/bearer/qbearerplugin_p.h
index 0cdde3c06c..ac787d0541 100644
--- a/src/network/bearer/qbearerplugin_p.h
+++ b/src/network/bearer/qbearerplugin_p.h
@@ -68,7 +68,7 @@ class Q_NETWORK_EXPORT QBearerEnginePlugin : public QObject
{
Q_OBJECT
public:
- explicit QBearerEnginePlugin(QObject *parent = 0);
+ explicit QBearerEnginePlugin(QObject *parent = nullptr);
virtual ~QBearerEnginePlugin();
virtual QBearerEngine *create(const QString &key) const = 0;
diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp
index a903ecda5f..b432444669 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.cpp
+++ b/src/network/bearer/qnetworkconfigmanager_p.cpp
@@ -45,6 +45,7 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qthread.h>
#include <QtCore/private/qcoreapplication_p.h>
+#include <QtCore/private/qlocking_p.h>
#include <QtCore/private/qthread_p.h>
#include <QtCore/qbytearray.h>
@@ -58,7 +59,7 @@
QT_BEGIN_NAMESPACE
QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate()
- : QObject(), pollTimer(0), mutex(QMutex::Recursive),
+ : QObject(), pollTimer(0),
loader(QBearerEngineFactoryInterface_iid, QLatin1String("/bearer")),
forcedPolling(0), firstUpdate(true)
{
@@ -115,10 +116,10 @@ QNetworkConfiguration QNetworkConfigurationManagerPrivate::defaultConfiguration(
QNetworkConfigurationPrivatePointer defaultConfiguration;
for (QBearerEngine *engine : sessionEngines) {
- QMutexLocker locker(&engine->mutex);
+ const auto locker = qt_scoped_lock(engine->mutex);
for (const auto &ptr : qAsConst(engine->snapConfigurations)) {
- QMutexLocker configLocker(&ptr->mutex);
+ const auto locker = qt_scoped_lock(ptr->mutex);
if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
QNetworkConfiguration config;
@@ -211,11 +212,11 @@ QList<QNetworkConfiguration> QNetworkConfigurationManagerPrivate::allConfigurati
for (QBearerEngine *engine : sessionEngines) {
- QMutexLocker locker(&engine->mutex);
+ const auto locker = qt_scoped_lock(engine->mutex);
//find all InternetAccessPoints
for (const auto &ptr : qAsConst(engine->accessPointConfigurations)) {
- QMutexLocker configLocker(&ptr->mutex);
+ const auto locker = qt_scoped_lock(ptr->mutex);
if ((ptr->state & filter) == filter) {
QNetworkConfiguration pt;
@@ -226,7 +227,7 @@ QList<QNetworkConfiguration> QNetworkConfigurationManagerPrivate::allConfigurati
//find all service networks
for (const auto &ptr : qAsConst(engine->snapConfigurations)) {
- QMutexLocker configLocker(&ptr->mutex);
+ const auto locker = qt_scoped_lock(ptr->mutex);
if ((ptr->state & filter) == filter) {
QNetworkConfiguration pt;
@@ -243,10 +244,10 @@ QNetworkConfiguration QNetworkConfigurationManagerPrivate::configurationFromIden
{
QNetworkConfiguration item;
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
for (QBearerEngine *engine : sessionEngines) {
- QMutexLocker locker(&engine->mutex);
+ const auto locker = qt_scoped_lock(engine->mutex);
if (auto ptr = engine->accessPointConfigurations.value(identifier)) {
item.d = std::move(ptr);
break;
@@ -266,7 +267,7 @@ QNetworkConfiguration QNetworkConfigurationManagerPrivate::configurationFromIden
bool QNetworkConfigurationManagerPrivate::isOnline() const
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
// We need allConfigurations since onlineConfigurations is filled with queued connections
// and thus is not always (more importantly just after creation) up to date
@@ -275,7 +276,7 @@ bool QNetworkConfigurationManagerPrivate::isOnline() const
QNetworkConfigurationManager::Capabilities QNetworkConfigurationManagerPrivate::capabilities() const
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
QNetworkConfigurationManager::Capabilities capFlags;
@@ -287,7 +288,7 @@ QNetworkConfigurationManager::Capabilities QNetworkConfigurationManagerPrivate::
void QNetworkConfigurationManagerPrivate::configurationAdded(QNetworkConfigurationPrivatePointer ptr)
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
if (!firstUpdate) {
QNetworkConfiguration item;
@@ -295,24 +296,24 @@ void QNetworkConfigurationManagerPrivate::configurationAdded(QNetworkConfigurati
emit configurationAdded(item);
}
- ptr->mutex.lock();
+ auto ptrLocker = qt_unique_lock(ptr->mutex);
if (ptr->state == QNetworkConfiguration::Active) {
- ptr->mutex.unlock();
- onlineConfigurations.insert(ptr->id);
+ const auto id = ptr->id;
+ ptrLocker.unlock();
+ onlineConfigurations.insert(id);
if (!firstUpdate && onlineConfigurations.count() == 1)
emit onlineStateChanged(true);
- } else {
- ptr->mutex.unlock();
}
}
void QNetworkConfigurationManagerPrivate::configurationRemoved(QNetworkConfigurationPrivatePointer ptr)
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
- ptr->mutex.lock();
- ptr->isValid = false;
- ptr->mutex.unlock();
+ {
+ const auto locker = qt_scoped_lock(ptr->mutex);
+ ptr->isValid = false;
+ }
if (!firstUpdate) {
QNetworkConfiguration item;
@@ -327,7 +328,7 @@ void QNetworkConfigurationManagerPrivate::configurationRemoved(QNetworkConfigura
void QNetworkConfigurationManagerPrivate::configurationChanged(QNetworkConfigurationPrivatePointer ptr)
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
if (!firstUpdate) {
QNetworkConfiguration item;
@@ -337,12 +338,13 @@ void QNetworkConfigurationManagerPrivate::configurationChanged(QNetworkConfigura
bool previous = !onlineConfigurations.isEmpty();
- ptr->mutex.lock();
- if (ptr->state == QNetworkConfiguration::Active)
- onlineConfigurations.insert(ptr->id);
- else
- onlineConfigurations.remove(ptr->id);
- ptr->mutex.unlock();
+ {
+ const auto locker = qt_scoped_lock(ptr->mutex);
+ if (ptr->state == QNetworkConfiguration::Active)
+ onlineConfigurations.insert(ptr->id);
+ else
+ onlineConfigurations.remove(ptr->id);
+ }
bool online = !onlineConfigurations.isEmpty();
@@ -354,7 +356,8 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
{
typedef QMultiMap<int, QString> PluginKeyMap;
typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
- QMutexLocker locker(&mutex);
+
+ auto locker = qt_unique_lock(mutex);
if (firstUpdate) {
if (qobject_cast<QBearerEngine *>(sender()))
@@ -432,7 +435,7 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
void QNetworkConfigurationManagerPrivate::performAsyncConfigurationUpdate()
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
if (sessionEngines.isEmpty()) {
emit configurationUpdateComplete();
@@ -449,14 +452,14 @@ void QNetworkConfigurationManagerPrivate::performAsyncConfigurationUpdate()
QList<QBearerEngine *> QNetworkConfigurationManagerPrivate::engines() const
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
return sessionEngines;
}
void QNetworkConfigurationManagerPrivate::startPolling()
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
if (!pollTimer) {
pollTimer = new QTimer(this);
bool ok;
@@ -482,7 +485,7 @@ void QNetworkConfigurationManagerPrivate::startPolling()
void QNetworkConfigurationManagerPrivate::pollEngines()
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
for (QBearerEngine *engine : qAsConst(sessionEngines)) {
if (engine->requiresPolling() && (forcedPolling || engine->configurationsInUse())) {
@@ -494,7 +497,7 @@ void QNetworkConfigurationManagerPrivate::pollEngines()
void QNetworkConfigurationManagerPrivate::enablePolling()
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
++forcedPolling;
@@ -504,7 +507,7 @@ void QNetworkConfigurationManagerPrivate::enablePolling()
void QNetworkConfigurationManagerPrivate::disablePolling()
{
- QMutexLocker locker(&mutex);
+ const auto locker = qt_scoped_lock(mutex);
--forcedPolling;
}
diff --git a/src/network/bearer/qnetworkconfigmanager_p.h b/src/network/bearer/qnetworkconfigmanager_p.h
index 380e25c22f..4819c2027c 100644
--- a/src/network/bearer/qnetworkconfigmanager_p.h
+++ b/src/network/bearer/qnetworkconfigmanager_p.h
@@ -117,7 +117,7 @@ private:
QThread *bearerThread;
private:
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
QFactoryLoader loader;
QList<QBearerEngine *> sessionEngines;
diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp
index f5ced0693a..19bc44e02a 100644
--- a/src/network/bearer/qnetworkconfiguration.cpp
+++ b/src/network/bearer/qnetworkconfiguration.cpp
@@ -414,34 +414,7 @@ bool QNetworkConfiguration::isRoamingAvailable() const
*/
QList<QNetworkConfiguration> QNetworkConfiguration::children() const
{
- QList<QNetworkConfiguration> results;
-
- if (!d)
- return results;
-
- QMutexLocker locker(&d->mutex);
-
- if (d->type != QNetworkConfiguration::ServiceNetwork || !d->isValid)
- return results;
-
- for (auto it = d->serviceNetworkMembers.begin(), end = d->serviceNetworkMembers.end(); it != end;) {
- QNetworkConfigurationPrivatePointer p = it.value();
- //if we have an invalid member get rid of it -> was deleted earlier on
- {
- QMutexLocker childLocker(&p->mutex);
-
- if (!p->isValid) {
- it = d->serviceNetworkMembers.erase(it);
- continue;
- }
- }
- QNetworkConfiguration item;
- item.d = p;
- results << item;
- ++it;
- }
-
- return results;
+ return {};
}
/*!
diff --git a/src/network/bearer/qnetworkconfiguration.h b/src/network/bearer/qnetworkconfiguration.h
index e7b74034fc..048abc2fc8 100644
--- a/src/network/bearer/qnetworkconfiguration.h
+++ b/src/network/bearer/qnetworkconfiguration.h
@@ -55,13 +55,11 @@ class Q_NETWORK_EXPORT QNetworkConfiguration
public:
QNetworkConfiguration();
QNetworkConfiguration(const QNetworkConfiguration& other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkConfiguration &operator=(QNetworkConfiguration &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkConfiguration &operator=(QNetworkConfiguration &&other) noexcept { swap(other); return *this; }
QNetworkConfiguration &operator=(const QNetworkConfiguration &other);
~QNetworkConfiguration();
- void swap(QNetworkConfiguration &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkConfiguration &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkConfiguration &other) const;
inline bool operator!=(const QNetworkConfiguration &other) const
diff --git a/src/network/bearer/qnetworkconfiguration_p.h b/src/network/bearer/qnetworkconfiguration_p.h
index 1b1ece39b7..96854fe831 100644
--- a/src/network/bearer/qnetworkconfiguration_p.h
+++ b/src/network/bearer/qnetworkconfiguration_p.h
@@ -65,22 +65,14 @@ class QNetworkConfigurationPrivate : public QSharedData
{
public:
QNetworkConfigurationPrivate() :
- mutex(QMutex::Recursive),
type(QNetworkConfiguration::Invalid),
purpose(QNetworkConfiguration::UnknownPurpose),
bearerType(QNetworkConfiguration::BearerUnknown),
isValid(false), roamingSupported(false),
timeout(DefaultTimeout)
{}
- virtual ~QNetworkConfigurationPrivate()
- {
- //release pointers to member configurations
- serviceNetworkMembers.clear();
- }
- QMap<unsigned int, QNetworkConfigurationPrivatePointer> serviceNetworkMembers;
-
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
QString name;
QString id;
diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h
index 661587603c..7c1ff63b68 100644
--- a/src/network/bearer/qnetworksession_p.h
+++ b/src/network/bearer/qnetworksession_p.h
@@ -68,7 +68,7 @@ class Q_NETWORK_EXPORT QNetworkSessionPrivate : public QObject
public:
QNetworkSessionPrivate() : QObject(),
- state(QNetworkSession::Invalid), isOpen(false), mutex(QMutex::Recursive)
+ state(QNetworkSession::Invalid), isOpen(false)
{}
virtual ~QNetworkSessionPrivate()
{}
@@ -147,7 +147,7 @@ protected:
QNetworkSession::State state;
bool isOpen;
- QMutex mutex;
+ QRecursiveMutex mutex;
};
QT_END_NAMESPACE
diff --git a/src/network/bearer/qsharednetworksession.cpp b/src/network/bearer/qsharednetworksession.cpp
index fc01acb8b4..b3e9892f4b 100644
--- a/src/network/bearer/qsharednetworksession.cpp
+++ b/src/network/bearer/qsharednetworksession.cpp
@@ -57,36 +57,44 @@ inline QSharedNetworkSessionManager* sharedNetworkSessionManager()
return rv;
}
-static void doDeleteLater(QObject* obj)
+struct DeleteLater {
+ void operator()(QObject* obj) const
+ {
+ obj->deleteLater();
+ }
+};
+
+template <typename Container>
+static void maybe_prune_expired(Container &c)
{
- obj->deleteLater();
+ if (c.size() > 16) {
+ for (auto it = c.cbegin(), end = c.cend(); it != end; /*erasing*/) {
+ if (!it->second.lock())
+ it = c.erase(it);
+ else
+ ++it;
+ }
+ }
}
QSharedPointer<QNetworkSession> QSharedNetworkSessionManager::getSession(const QNetworkConfiguration &config)
{
- QSharedNetworkSessionManager *m(sharedNetworkSessionManager());
- const auto it = m->sessions.constFind(config);
+ QSharedNetworkSessionManager *m = sharedNetworkSessionManager();
+ maybe_prune_expired(m->sessions);
+ auto &entry = m->sessions[config];
//if already have a session, return it
- if (it != m->sessions.cend()) {
- QSharedPointer<QNetworkSession> p = it.value().toStrongRef();
- if (!p.isNull())
- return p;
- }
+ if (auto p = entry.toStrongRef())
+ return p;
//otherwise make one
- QSharedPointer<QNetworkSession> session(new QNetworkSession(config), doDeleteLater);
- m->sessions[config] = session;
+ QSharedPointer<QNetworkSession> session(new QNetworkSession(config), DeleteLater{});
+ entry = session;
return session;
}
void QSharedNetworkSessionManager::setSession(const QNetworkConfiguration &config, QSharedPointer<QNetworkSession> session)
{
- QSharedNetworkSessionManager *m(sharedNetworkSessionManager());
- m->sessions[config] = session;
-}
-
-uint qHash(const QNetworkConfiguration& config)
-{
- return ((uint)config.type()) | (((uint)config.bearerType()) << 8) | (((uint)config.purpose()) << 16);
+ QSharedNetworkSessionManager *m = sharedNetworkSessionManager();
+ m->sessions[config] = std::move(session);
}
QT_END_NAMESPACE
diff --git a/src/network/bearer/qsharednetworksession_p.h b/src/network/bearer/qsharednetworksession_p.h
index 001b8af02a..f22f9eeacb 100644
--- a/src/network/bearer/qsharednetworksession_p.h
+++ b/src/network/bearer/qsharednetworksession_p.h
@@ -54,16 +54,26 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "qnetworksession.h"
#include "qnetworkconfiguration.h"
-#include <QHash>
#include <QSharedPointer>
#include <QWeakPointer>
#include <QMutex>
+#include <unordered_map>
+
#ifndef QT_NO_BEARERMANAGEMENT
QT_BEGIN_NAMESPACE
-uint qHash(const QNetworkConfiguration& config);
+namespace QtPrivate {
+struct NetworkConfigurationHash {
+ using result_type = size_t;
+ using argument_type = QNetworkConfiguration;
+ size_t operator()(const QNetworkConfiguration &config) const noexcept
+ {
+ return std::hash<size_t>{}(size_t(config.type()) | (size_t(config.bearerType()) << 8) | (size_t(config.purpose()) << 16));
+ }
+};
+}
class QSharedNetworkSessionManager
{
@@ -71,7 +81,7 @@ public:
static QSharedPointer<QNetworkSession> getSession(const QNetworkConfiguration &config);
static void setSession(const QNetworkConfiguration &config, QSharedPointer<QNetworkSession> session);
private:
- QHash<QNetworkConfiguration, QWeakPointer<QNetworkSession> > sessions;
+ std::unordered_map<QNetworkConfiguration, QWeakPointer<QNetworkSession>, QtPrivate::NetworkConfigurationHash> sessions;
};
QT_END_NAMESPACE
diff --git a/src/network/configure.json b/src/network/configure.json
index f74c481f38..f501465c91 100644
--- a/src/network/configure.json
+++ b/src/network/configure.json
@@ -98,6 +98,30 @@
"condition": "!config.msvc"
}
]
+ },
+ "gssapi": {
+ "label": "KRB5 GSSAPI Support",
+ "test": {
+ "head": [
+ "#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))",
+ "# include <TargetConditionals.h>",
+ "# if defined(TARGET_OS_MAC) && TARGET_OS_MAC",
+ "# include <GSS/GSS.h>",
+ "# endif",
+ "#else",
+ "# include <gssapi/gssapi.h>",
+ "#endif"
+ ],
+ "main": [
+ "gss_ctx_id_t ctx;",
+ "gss_context_time(nullptr, ctx, nullptr);"
+ ]
+ },
+ "sources": [
+ { "libs": "-framework GSS", "condition": "config.darwin" },
+ { "type": "pkgConfig", "args": "krb5-gssapi" },
+ "-lgssapi_krb5"
+ ]
}
},
@@ -199,6 +223,22 @@
]
},
"use": "openssl"
+ },
+ "netlistmgr": {
+ "label": "Network List Manager",
+ "type": "compile",
+ "test": {
+ "include": [ "netlistmgr.h", "wrl/client.h" ],
+ "main": [
+ "using namespace Microsoft::WRL;",
+ "ComPtr<INetworkListManager> networkListManager;",
+ "ComPtr<IConnectionPoint> connectionPoint;",
+ "ComPtr<IConnectionPointContainer> connectionPointContainer;",
+ "networkListManager.As(&connectionPointContainer);",
+ "connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents, &connectionPoint);"
+ ],
+ "qmake": "LIBS += -lOle32"
+ }
}
},
@@ -261,7 +301,7 @@
"disable": "input.securetransport == 'no' || input.ssl == 'no'",
"condition": "config.darwin && (input.openssl == '' || input.openssl == 'no')",
"output": [
- "privateFeature",
+ "publicFeature",
{ "type": "define", "name": "QT_SECURETRANSPORT" }
]
},
@@ -283,7 +323,7 @@
"label": "DTLS",
"purpose": "Provides a DTLS implementation",
"section": "Networking",
- "condition": "features.openssl && tests.dtls",
+ "condition": "features.openssl && features.udpsocket && tests.dtls",
"output": [ "publicFeature" ]
},
"ocsp": {
@@ -378,6 +418,27 @@
"purpose": "Provides API for DNS lookups.",
"section": "Networking",
"output": [ "publicFeature" ]
+ },
+ "gssapi": {
+ "label": "GSSAPI",
+ "purpose": "Enable SPNEGO authentication through GSSAPI",
+ "section": "Networking",
+ "condition": "!config.win32 && libs.gssapi",
+ "output": [ "publicFeature", "feature" ]
+ },
+ "sspi": {
+ "label": "SSPI",
+ "purpose": "Enable NTLM/SPNEGO authentication through SSPI",
+ "section": "Networking",
+ "condition": "config.win32 && !config.winrt",
+ "output": [ "publicFeature", "feature" ]
+ },
+ "netlistmgr": {
+ "label": "Network List Manager",
+ "purpose": "Use Network List Manager to keep track of network connectivity",
+ "section": "Networking",
+ "condition": "config.win32 && tests.netlistmgr",
+ "output": [ "privateFeature" ]
}
},
@@ -437,7 +498,8 @@ For example:
"dtls",
"ocsp",
"sctp",
- "system-proxies"
+ "system-proxies",
+ "gssapi"
]
}
]
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index 7074fcd5eb..110d9f56bf 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,19 @@ mac {
!uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration
}
+macos | ios {
+ OBJECTIVE_SOURCES += \
+ kernel/qnetconmonitor_darwin.mm
+
+ LIBS_PRIVATE += -framework SystemConfiguration
+} else:qtConfig(netlistmgr) {
+ SOURCES += kernel/qnetconmonitor_win.cpp
+} else {
+ SOURCES += kernel/qnetconmonitor_stub.cpp
+}
+
+qtConfig(gssapi): QMAKE_USE_PRIVATE += gssapi
+
uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h
osx:SOURCES += kernel/qnetworkproxy_mac.cpp
else:win32:!winrt: SOURCES += kernel/qnetworkproxy_win.cpp
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 47ce9ab0c6..33a30eb1cd 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -52,22 +52,34 @@
#ifdef Q_OS_WIN
#include <qmutex.h>
-#include <private/qmutexpool_p.h>
#include <rpc.h>
-#ifndef Q_OS_WINRT
+#endif
+
+#if QT_CONFIG(sspi) // SSPI
#define SECURITY_WIN32 1
#include <security.h>
-#endif
-#endif
+#elif QT_CONFIG(gssapi) // GSSAPI
+#if defined(Q_OS_DARWIN)
+#include <GSS/GSS.h>
+#else
+#include <gssapi/gssapi.h>
+#endif // Q_OS_DARWIN
+#endif // Q_CONFIG(sspi)
QT_BEGIN_NAMESPACE
static QByteArray qNtlmPhase1();
static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx);
-static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
-#endif
+#if QT_CONFIG(sspi) // SSPI
+static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
+ const QString& host);
+static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
+ const QString& host, const QByteArray& challenge = QByteArray());
+#elif QT_CONFIG(gssapi) // GSSAPI
+static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString& host);
+static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx,
+ const QByteArray& challenge = QByteArray());
+#endif // gssapi
/*!
\class QAuthenticator
@@ -90,6 +102,7 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray&
\li Basic
\li NTLM version 2
\li Digest-MD5
+ \li SPNEGO/Negotiate
\endlist
\target qauthenticator-options
@@ -133,6 +146,10 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray&
The Digest-MD5 authentication mechanism supports no outgoing options.
+ \section2 SPNEGO/Negotiate
+
+ This authentication mechanism currently supports no incoming or outgoing options.
+
\sa QSslSocket
*/
@@ -187,7 +204,7 @@ QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other)
d->options = other.d->options;
} else if (d->phase == QAuthenticatorPrivate::Start) {
delete d;
- d = 0;
+ d = nullptr;
}
return *this;
}
@@ -339,21 +356,25 @@ bool QAuthenticator::isNull() const
return !d;
}
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-class QNtlmWindowsHandles
+#if QT_CONFIG(sspi) // SSPI
+class QSSPIWindowsHandles
{
public:
CredHandle credHandle;
CtxtHandle ctxHandle;
};
-#endif
+#elif QT_CONFIG(gssapi) // GSSAPI
+class QGssApiHandles
+{
+public:
+ gss_ctx_id_t gssCtx = nullptr;
+ gss_name_t targetName;
+};
+#endif // gssapi
QAuthenticatorPrivate::QAuthenticatorPrivate()
: method(None)
- #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- , ntlmWindowsHandles(0)
- #endif
, hasFailed(false)
, phase(Start)
, nonceCount(0)
@@ -363,13 +384,7 @@ QAuthenticatorPrivate::QAuthenticatorPrivate()
nonceCount = 0;
}
-QAuthenticatorPrivate::~QAuthenticatorPrivate()
-{
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- if (ntlmWindowsHandles)
- delete ntlmWindowsHandles;
-#endif
-}
+QAuthenticatorPrivate::~QAuthenticatorPrivate() = default;
void QAuthenticatorPrivate::updateCredentials()
{
@@ -424,6 +439,9 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
} else if (method < DigestMd5 && str.startsWith("digest")) {
method = DigestMd5;
headerVal = current.second.mid(7);
+ } else if (method < Negotiate && str.startsWith("negotiate")) {
+ method = Negotiate;
+ headerVal = current.second.mid(10);
}
}
@@ -439,6 +457,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
phase = Done;
break;
case Ntlm:
+ case Negotiate:
// work is done in calculateResponse()
break;
case DigestMd5: {
@@ -456,33 +475,36 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
}
}
-QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path)
+QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path, const QString& host)
{
+#if !QT_CONFIG(sspi) && !QT_CONFIG(gssapi)
+ Q_UNUSED(host);
+#endif
QByteArray response;
- const char *methodString = 0;
+ const char* methodString = nullptr;
switch(method) {
case QAuthenticatorPrivate::None:
methodString = "";
phase = Done;
break;
case QAuthenticatorPrivate::Basic:
- methodString = "Basic ";
+ methodString = "Basic";
response = user.toLatin1() + ':' + password.toLatin1();
response = response.toBase64();
phase = Done;
break;
case QAuthenticatorPrivate::DigestMd5:
- methodString = "Digest ";
+ methodString = "Digest";
response = digestMd5Response(challenge, requestMethod, path);
phase = Done;
break;
case QAuthenticatorPrivate::Ntlm:
- methodString = "NTLM ";
+ methodString = "NTLM";
if (challenge.isEmpty()) {
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+#if QT_CONFIG(sspi) // SSPI
QByteArray phase1Token;
if (user.isEmpty()) // Only pull from system if no user was specified in authenticator
- phase1Token = qNtlmPhase1_SSPI(this);
+ phase1Token = qSspiStartup(this, method, host);
if (!phase1Token.isEmpty()) {
response = phase1Token.toBase64();
phase = Phase2;
@@ -496,10 +518,10 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
phase = Phase2;
}
} else {
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+#if QT_CONFIG(sspi) // SSPI
QByteArray phase3Token;
- if (ntlmWindowsHandles)
- phase3Token = qNtlmPhase3_SSPI(this, QByteArray::fromBase64(challenge));
+ if (sspiWindowsHandles)
+ phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
if (!phase3Token.isEmpty()) {
response = phase3Token.toBase64();
phase = Done;
@@ -512,8 +534,39 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
}
break;
+ case QAuthenticatorPrivate::Negotiate:
+ methodString = "Negotiate";
+ if (challenge.isEmpty()) {
+ QByteArray phase1Token;
+#if QT_CONFIG(sspi) // SSPI
+ phase1Token = qSspiStartup(this, method, host);
+#elif QT_CONFIG(gssapi) // GSSAPI
+ phase1Token = qGssapiStartup(this, host);
+#endif
+
+ if (!phase1Token.isEmpty()) {
+ response = phase1Token.toBase64();
+ phase = Phase2;
+ } else {
+ phase = Done;
+ }
+ } else {
+ QByteArray phase3Token;
+#if QT_CONFIG(sspi) // SSPI
+ phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
+#elif QT_CONFIG(gssapi) // GSSAPI
+ phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge));
+#endif
+ if (!phase3Token.isEmpty()) {
+ response = phase3Token.toBase64();
+ phase = Done;
+ }
+ }
+
+ break;
}
- return QByteArray(methodString) + response;
+
+ return QByteArray::fromRawData(methodString, qstrlen(methodString)) + ' ' + response;
}
@@ -699,9 +752,10 @@ QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge,
return credentials;
}
-// ---------------------------- Digest Md5 code ----------------------------------------
+// ---------------------------- End of Digest Md5 code ---------------------------------
+// ---------------------------- NTLM code ----------------------------------------------
/*
* NTLM message flags.
@@ -1419,156 +1473,237 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas
return rc;
}
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+// ---------------------------- End of NTLM code ---------------------------------------
+
+#if QT_CONFIG(sspi) // SSPI
+// ---------------------------- SSPI code ----------------------------------------------
// See http://davenport.sourceforge.net/ntlm.html
// and libcurl http_ntlm.c
// Handle of secur32.dll
-static HMODULE securityDLLHandle = NULL;
+static HMODULE securityDLLHandle = nullptr;
// Pointer to SSPI dispatch table
-static PSecurityFunctionTable pSecurityFunctionTable = NULL;
-
+static PSecurityFunctionTable pSecurityFunctionTable = nullptr;
-static bool q_NTLM_SSPI_library_load()
+static bool q_SSPI_library_load()
{
static QBasicMutex mutex;
QMutexLocker l(&mutex);
// Initialize security interface
- if (pSecurityFunctionTable == NULL) {
+ if (pSecurityFunctionTable == nullptr) {
securityDLLHandle = LoadLibrary(L"secur32.dll");
- if (securityDLLHandle != NULL) {
+ if (securityDLLHandle != nullptr) {
INIT_SECURITY_INTERFACE pInitSecurityInterface =
reinterpret_cast<INIT_SECURITY_INTERFACE>(
reinterpret_cast<QFunctionPointer>(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW")));
- if (pInitSecurityInterface != NULL)
+ if (pInitSecurityInterface != nullptr)
pSecurityFunctionTable = pInitSecurityInterface();
}
}
- if (pSecurityFunctionTable == NULL)
+ if (pSecurityFunctionTable == nullptr)
return false;
return true;
}
-// Phase 1:
-static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx)
+static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
+ const QString& host)
{
- QByteArray result;
+ if (!q_SSPI_library_load())
+ return QByteArray();
+
+ TimeStamp expiry; // For Windows 9x compatibility of SSPI calls
- if (!q_NTLM_SSPI_library_load())
- return result;
+ if (!ctx->sspiWindowsHandles)
+ ctx->sspiWindowsHandles.reset(new QSSPIWindowsHandles);
+ memset(&ctx->sspiWindowsHandles->credHandle, 0, sizeof(CredHandle));
- // 1. The client obtains a representation of the credential set
- // for the user via the SSPI AcquireCredentialsHandle function.
- if (!ctx->ntlmWindowsHandles)
- ctx->ntlmWindowsHandles = new QNtlmWindowsHandles;
- memset(&ctx->ntlmWindowsHandles->credHandle, 0, sizeof(CredHandle));
- TimeStamp tsDummy;
+ // Acquire our credentials handle
SECURITY_STATUS secStatus = pSecurityFunctionTable->AcquireCredentialsHandle(
- NULL, (SEC_WCHAR*)L"NTLM", SECPKG_CRED_OUTBOUND, NULL, NULL,
- NULL, NULL, &ctx->ntlmWindowsHandles->credHandle, &tsDummy);
+ nullptr,
+ (SEC_WCHAR*)(method == QAuthenticatorPrivate::Negotiate ? L"Negotiate" : L"NTLM"),
+ SECPKG_CRED_OUTBOUND, nullptr, nullptr, nullptr, nullptr,
+ &ctx->sspiWindowsHandles->credHandle, &expiry
+ );
if (secStatus != SEC_E_OK) {
- delete ctx->ntlmWindowsHandles;
- ctx->ntlmWindowsHandles = 0;
- return result;
+ ctx->sspiWindowsHandles.reset(nullptr);
+ return QByteArray();
}
- // 2. The client calls the SSPI InitializeSecurityContext function
- // to obtain an authentication request token (in our case, a Type 1 message).
- // The client sends this token to the server.
- SecBufferDesc desc;
- SecBuffer buf;
- desc.ulVersion = SECBUFFER_VERSION;
- desc.cBuffers = 1;
- desc.pBuffers = &buf;
- buf.cbBuffer = 0;
- buf.BufferType = SECBUFFER_TOKEN;
- buf.pvBuffer = NULL;
- ULONG attrs;
-
- secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle, NULL,
- const_cast<SEC_WCHAR*>(L"") /* host */,
- ISC_REQ_ALLOCATE_MEMORY,
- 0, SECURITY_NETWORK_DREP,
- NULL, 0,
- &ctx->ntlmWindowsHandles->ctxHandle, &desc,
- &attrs, &tsDummy);
- if (secStatus == SEC_I_COMPLETE_AND_CONTINUE ||
- secStatus == SEC_I_CONTINUE_NEEDED) {
- pSecurityFunctionTable->CompleteAuthToken(&ctx->ntlmWindowsHandles->ctxHandle, &desc);
- } else if (secStatus != SEC_E_OK) {
- if ((const char*)buf.pvBuffer)
- pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer);
- pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle);
- delete ctx->ntlmWindowsHandles;
- ctx->ntlmWindowsHandles = 0;
- return result;
+ return qSspiContinue(ctx, method, host);
+}
+
+static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
+ const QString &host, const QByteArray &challenge)
+{
+ QByteArray result;
+ SecBuffer challengeBuf;
+ SecBuffer responseBuf;
+ SecBufferDesc challengeDesc;
+ SecBufferDesc responseDesc;
+ unsigned long attrs;
+ TimeStamp expiry; // For Windows 9x compatibility of SSPI calls
+
+ if (!challenge.isEmpty())
+ {
+ // Setup the challenge "input" security buffer
+ challengeDesc.ulVersion = SECBUFFER_VERSION;
+ challengeDesc.cBuffers = 1;
+ challengeDesc.pBuffers = &challengeBuf;
+ challengeBuf.BufferType = SECBUFFER_TOKEN;
+ challengeBuf.pvBuffer = (PVOID)(challenge.data());
+ challengeBuf.cbBuffer = challenge.length();
}
- result = QByteArray((const char*)buf.pvBuffer, buf.cbBuffer);
- pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer);
+ // Setup the response "output" security buffer
+ responseDesc.ulVersion = SECBUFFER_VERSION;
+ responseDesc.cBuffers = 1;
+ responseDesc.pBuffers = &responseBuf;
+ responseBuf.BufferType = SECBUFFER_TOKEN;
+ responseBuf.pvBuffer = nullptr;
+ responseBuf.cbBuffer = 0;
+
+ // Calculate target (SPN for Negotiate, empty for NTLM)
+ std::wstring targetNameW = (method == QAuthenticatorPrivate::Negotiate
+ ? QLatin1String("HTTP/") + host : QString()).toStdWString();
+
+ // Generate our challenge-response message
+ SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext(
+ &ctx->sspiWindowsHandles->credHandle,
+ !challenge.isEmpty() ? &ctx->sspiWindowsHandles->ctxHandle : nullptr,
+ const_cast<wchar_t*>(targetNameW.data()),
+ ISC_REQ_ALLOCATE_MEMORY,
+ 0, SECURITY_NATIVE_DREP,
+ !challenge.isEmpty() ? &challengeDesc : nullptr,
+ 0, &ctx->sspiWindowsHandles->ctxHandle,
+ &responseDesc, &attrs,
+ &expiry
+ );
+
+ if (secStatus == SEC_I_COMPLETE_NEEDED || secStatus == SEC_I_COMPLETE_AND_CONTINUE) {
+ secStatus = pSecurityFunctionTable->CompleteAuthToken(&ctx->sspiWindowsHandles->ctxHandle,
+ &responseDesc);
+ }
+
+ if (secStatus != SEC_I_COMPLETE_AND_CONTINUE && secStatus != SEC_I_CONTINUE_NEEDED) {
+ pSecurityFunctionTable->FreeCredentialsHandle(&ctx->sspiWindowsHandles->credHandle);
+ pSecurityFunctionTable->DeleteSecurityContext(&ctx->sspiWindowsHandles->ctxHandle);
+ ctx->sspiWindowsHandles.reset(nullptr);
+ }
+
+ result = QByteArray((const char*)responseBuf.pvBuffer, responseBuf.cbBuffer);
+ pSecurityFunctionTable->FreeContextBuffer(responseBuf.pvBuffer);
+
return result;
}
-// Phase 2:
-// 3. The server receives the token from the client, and uses it as input to the
-// AcceptSecurityContext SSPI function. This creates a local security context on
-// the server to represent the client, and yields an authentication response token
-// (the Type 2 message), which is sent to the client.
+// ---------------------------- End of SSPI code ---------------------------------------
+
+#elif QT_CONFIG(gssapi) // GSSAPI
+
+// ---------------------------- GSSAPI code ----------------------------------------------
+// See postgres src/interfaces/libpq/fe-auth.c
+
+// Fetch all errors of a specific type
+static void q_GSSAPI_error_int(const char *message, OM_uint32 stat, int type)
+{
+ OM_uint32 minStat, msgCtx = 0;
+ gss_buffer_desc msg;
+
+ do {
+ gss_display_status(&minStat, stat, type, GSS_C_NO_OID, &msgCtx, &msg);
+ qDebug() << message << ": " << reinterpret_cast<const char*>(msg.value);
+ gss_release_buffer(&minStat, &msg);
+ } while (msgCtx);
+}
-// Phase 3:
-static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data)
+// GSSAPI errors contain two parts; extract both
+static void q_GSSAPI_error(const char *message, OM_uint32 majStat, OM_uint32 minStat)
{
- // 4. The client receives the response token from the server and calls
- // InitializeSecurityContext again, passing the server's token as input.
- // This provides us with another authentication request token (the Type 3 message).
- // The return value indicates that the security context was successfully initialized;
- // the token is sent to the server.
+ // Fetch major error codes
+ q_GSSAPI_error_int(message, majStat, GSS_C_GSS_CODE);
+ // Add the minor codes as well
+ q_GSSAPI_error_int(message, minStat, GSS_C_MECH_CODE);
+}
+
+// Send initial GSS authentication token
+static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host)
+{
+ OM_uint32 majStat, minStat;
+
+ if (!ctx->gssApiHandles)
+ ctx->gssApiHandles.reset(new QGssApiHandles);
+
+ // Convert target name to internal form
+ QByteArray serviceName = QStringLiteral("HTTPS@%1").arg(host).toLocal8Bit();
+ gss_buffer_desc nameDesc = {static_cast<std::size_t>(serviceName.size()), serviceName.data()};
+
+ majStat = gss_import_name(&minStat, &nameDesc,
+ GSS_C_NT_HOSTBASED_SERVICE, &ctx->gssApiHandles->targetName);
+
+ if (majStat != GSS_S_COMPLETE) {
+ q_GSSAPI_error("gss_import_name error", majStat, minStat);
+ ctx->gssApiHandles.reset(nullptr);
+ return QByteArray();
+ }
+
+ // Call qGssapiContinue with GSS_C_NO_CONTEXT to get initial packet
+ ctx->gssApiHandles->gssCtx = GSS_C_NO_CONTEXT;
+ return qGssapiContinue(ctx);
+}
+
+// Continue GSS authentication with next token as needed
+static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray& challenge)
+{
+ OM_uint32 majStat, minStat, ignored;
QByteArray result;
+ gss_buffer_desc inBuf = {0, nullptr}; // GSS input token
+ gss_buffer_desc outBuf; // GSS output token
- if (pSecurityFunctionTable == NULL)
- return result;
-
- SecBuffer type_2, type_3;
- SecBufferDesc type_2_desc, type_3_desc;
- ULONG attrs;
- TimeStamp tsDummy; // For Windows 9x compatibility of SPPI calls
-
- type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
- type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
- type_2_desc.pBuffers = &type_2;
- type_3_desc.pBuffers = &type_3;
-
- type_2.BufferType = SECBUFFER_TOKEN;
- type_2.pvBuffer = (PVOID)phase2data.data();
- type_2.cbBuffer = phase2data.length();
- type_3.BufferType = SECBUFFER_TOKEN;
- type_3.pvBuffer = 0;
- type_3.cbBuffer = 0;
-
- SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle,
- &ctx->ntlmWindowsHandles->ctxHandle,
- const_cast<SEC_WCHAR*>(L"") /* host */,
- ISC_REQ_ALLOCATE_MEMORY,
- 0, SECURITY_NETWORK_DREP, &type_2_desc,
- 0, &ctx->ntlmWindowsHandles->ctxHandle, &type_3_desc,
- &attrs, &tsDummy);
-
- if (secStatus == SEC_E_OK && ((const char*)type_3.pvBuffer)) {
- result = QByteArray((const char*)type_3.pvBuffer, type_3.cbBuffer);
- pSecurityFunctionTable->FreeContextBuffer(type_3.pvBuffer);
+ if (!challenge.isEmpty()) {
+ inBuf.value = const_cast<char*>(challenge.data());
+ inBuf.length = challenge.length();
}
- pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle);
- pSecurityFunctionTable->DeleteSecurityContext(&ctx->ntlmWindowsHandles->ctxHandle);
- delete ctx->ntlmWindowsHandles;
- ctx->ntlmWindowsHandles = 0;
+ majStat = gss_init_sec_context(&minStat,
+ GSS_C_NO_CREDENTIAL,
+ &ctx->gssApiHandles->gssCtx,
+ ctx->gssApiHandles->targetName,
+ GSS_C_NO_OID,
+ GSS_C_MUTUAL_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ challenge.isEmpty() ? GSS_C_NO_BUFFER : &inBuf,
+ nullptr,
+ &outBuf,
+ nullptr,
+ nullptr);
+
+ if (outBuf.length != 0)
+ result = QByteArray(reinterpret_cast<const char*>(outBuf.value), outBuf.length);
+ gss_release_buffer(&ignored, &outBuf);
+
+ if (majStat != GSS_S_COMPLETE && majStat != GSS_S_CONTINUE_NEEDED) {
+ q_GSSAPI_error("gss_init_sec_context error", majStat, minStat);
+ gss_release_name(&ignored, &ctx->gssApiHandles->targetName);
+ if (ctx->gssApiHandles->gssCtx)
+ gss_delete_sec_context(&ignored, &ctx->gssApiHandles->gssCtx, GSS_C_NO_BUFFER);
+ ctx->gssApiHandles.reset(nullptr);
+ }
+
+ if (majStat == GSS_S_COMPLETE) {
+ gss_release_name(&ignored, &ctx->gssApiHandles->targetName);
+ ctx->gssApiHandles.reset(nullptr);
+ }
return result;
}
-#endif // Q_OS_WIN && !Q_OS_WINRT
+
+// ---------------------------- End of GSSAPI code ----------------------------------------------
+
+#endif // gssapi
QT_END_NAMESPACE
diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h
index 265cb7afe2..e201d22650 100644
--- a/src/network/kernel/qauthenticator_p.h
+++ b/src/network/kernel/qauthenticator_p.h
@@ -54,6 +54,7 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <qhash.h>
#include <qbytearray.h>
+#include <qscopedpointer.h>
#include <qstring.h>
#include <qauthenticator.h>
#include <qvariant.h>
@@ -61,14 +62,16 @@
QT_BEGIN_NAMESPACE
class QHttpResponseHeader;
-#ifdef Q_OS_WIN
-class QNtlmWindowsHandles;
+#if QT_CONFIG(sspi) // SSPI
+class QSSPIWindowsHandles;
+#elif QT_CONFIG(gssapi) // GSSAPI
+class QGssApiHandles;
#endif
class Q_AUTOTEST_EXPORT QAuthenticatorPrivate
{
public:
- enum Method { None, Basic, Ntlm, DigestMd5 };
+ enum Method { None, Basic, Ntlm, DigestMd5, Negotiate };
QAuthenticatorPrivate();
~QAuthenticatorPrivate();
@@ -79,8 +82,10 @@ public:
Method method;
QString realm;
QByteArray challenge;
-#ifdef Q_OS_WIN
- QNtlmWindowsHandles *ntlmWindowsHandles;
+#if QT_CONFIG(sspi) // SSPI
+ QScopedPointer<QSSPIWindowsHandles> sspiWindowsHandles;
+#elif QT_CONFIG(gssapi) // GSSAPI
+ QScopedPointer<QGssApiHandles> gssApiHandles;
#endif
bool hasFailed; //credentials have been tried but rejected by server.
@@ -100,7 +105,7 @@ public:
QString workstation;
QString userDomain;
- QByteArray calculateResponse(const QByteArray &method, const QByteArray &path);
+ QByteArray calculateResponse(const QByteArray &method, const QByteArray &path, const QString& host);
inline static QAuthenticatorPrivate *getPrivate(QAuthenticator &auth) { return auth.d; }
inline static const QAuthenticatorPrivate *getPrivate(const QAuthenticator &auth) { return auth.d; }
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index eebd0abe66..110a74da44 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -64,13 +64,11 @@ class Q_NETWORK_EXPORT QDnsDomainNameRecord
public:
QDnsDomainNameRecord();
QDnsDomainNameRecord(const QDnsDomainNameRecord &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QDnsDomainNameRecord &operator=(QDnsDomainNameRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QDnsDomainNameRecord &operator=(QDnsDomainNameRecord &&other) noexcept { swap(other); return *this; }
QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other);
~QDnsDomainNameRecord();
- void swap(QDnsDomainNameRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QDnsDomainNameRecord &other) noexcept { qSwap(d, other.d); }
QString name() const;
quint32 timeToLive() const;
@@ -88,13 +86,11 @@ class Q_NETWORK_EXPORT QDnsHostAddressRecord
public:
QDnsHostAddressRecord();
QDnsHostAddressRecord(const QDnsHostAddressRecord &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QDnsHostAddressRecord &operator=(QDnsHostAddressRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QDnsHostAddressRecord &operator=(QDnsHostAddressRecord &&other) noexcept { swap(other); return *this; }
QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other);
~QDnsHostAddressRecord();
- void swap(QDnsHostAddressRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QDnsHostAddressRecord &other) noexcept { qSwap(d, other.d); }
QString name() const;
quint32 timeToLive() const;
@@ -112,13 +108,11 @@ class Q_NETWORK_EXPORT QDnsMailExchangeRecord
public:
QDnsMailExchangeRecord();
QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QDnsMailExchangeRecord &operator=(QDnsMailExchangeRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QDnsMailExchangeRecord &operator=(QDnsMailExchangeRecord &&other) noexcept { swap(other); return *this; }
QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other);
~QDnsMailExchangeRecord();
- void swap(QDnsMailExchangeRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QDnsMailExchangeRecord &other) noexcept { qSwap(d, other.d); }
QString exchange() const;
QString name() const;
@@ -137,13 +131,11 @@ class Q_NETWORK_EXPORT QDnsServiceRecord
public:
QDnsServiceRecord();
QDnsServiceRecord(const QDnsServiceRecord &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QDnsServiceRecord &operator=(QDnsServiceRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QDnsServiceRecord &operator=(QDnsServiceRecord &&other) noexcept { swap(other); return *this; }
QDnsServiceRecord &operator=(const QDnsServiceRecord &other);
~QDnsServiceRecord();
- void swap(QDnsServiceRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QDnsServiceRecord &other) noexcept { qSwap(d, other.d); }
QString name() const;
quint16 port() const;
@@ -164,13 +156,11 @@ class Q_NETWORK_EXPORT QDnsTextRecord
public:
QDnsTextRecord();
QDnsTextRecord(const QDnsTextRecord &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QDnsTextRecord &operator=(QDnsTextRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QDnsTextRecord &operator=(QDnsTextRecord &&other) noexcept { swap(other); return *this; }
QDnsTextRecord &operator=(const QDnsTextRecord &other);
~QDnsTextRecord();
- void swap(QDnsTextRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QDnsTextRecord &other) noexcept { qSwap(d, other.d); }
QString name() const;
quint32 timeToLive() const;
diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h
index 2dc98e527a..8c3c2ed3e1 100644
--- a/src/network/kernel/qdnslookup_p.h
+++ b/src/network/kernel/qdnslookup_p.h
@@ -95,7 +95,7 @@ public:
QDnsLookupPrivate()
: isFinished(false)
, type(QDnsLookup::A)
- , runnable(0)
+ , runnable(nullptr)
{ }
void _q_lookupFinished(const QDnsLookupReply &reply);
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp
index cfdb9ca633..262893179c 100644
--- a/src/network/kernel/qdnslookup_win.cpp
+++ b/src/network/kernel/qdnslookup_win.cpp
@@ -41,7 +41,6 @@
#include "qdnslookup_p.h"
#include <qurl.h>
-#include <private/qmutexpool_p.h>
#include <private/qsystemerror_p.h>
#include <qt_windows.h>
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index 5d0ef150f3..b54fb349fb 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -1333,7 +1333,7 @@ QDebug operator<<(QDebug d, const QHostAddress &address)
\relates QHostAddress
Returns a hash of the host address \a key, using \a seed to seed the calculation.
*/
-uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW
+uint qHash(const QHostAddress &key, uint seed) noexcept
{
return qHashBits(key.d->a6.c, 16, seed);
}
diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h
index 00555f3d8e..799247695e 100644
--- a/src/network/kernel/qhostaddress.h
+++ b/src/network/kernel/qhostaddress.h
@@ -66,7 +66,7 @@ typedef QIPv6Address Q_IPV6ADDR;
class QHostAddress;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0) Q_DECL_NOTHROW;
+Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0) noexcept;
class Q_NETWORK_EXPORT QHostAddress
{
@@ -102,11 +102,8 @@ public:
QHostAddress(SpecialAddress address);
~QHostAddress();
-#ifdef Q_COMPILER_RVALUE_REFS
- QHostAddress &operator=(QHostAddress &&other) Q_DECL_NOTHROW
+ QHostAddress &operator=(QHostAddress &&other) noexcept
{ swap(other); return *this; }
-#endif
-
QHostAddress &operator=(const QHostAddress &other);
#if QT_DEPRECATED_SINCE(5, 8)
QT_DEPRECATED_X("use = QHostAddress(string) instead")
@@ -114,7 +111,7 @@ public:
#endif
QHostAddress &operator=(SpecialAddress address);
- void swap(QHostAddress &other) Q_DECL_NOTHROW { d.swap(other.d); }
+ void swap(QHostAddress &other) noexcept { d.swap(other.d); }
void setAddress(quint32 ip4Addr);
void setAddress(quint8 *ip6Addr); // ### Qt 6: remove me
@@ -157,7 +154,7 @@ public:
static QPair<QHostAddress, int> parseSubnet(const QString &subnet);
- friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW;
+ friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) noexcept;
protected:
friend class QHostAddressPrivate;
QExplicitlySharedDataPointer<QHostAddressPrivate> d;
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index f4348b690e..f9335c3bb9 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -37,13 +37,17 @@
**
****************************************************************************/
+//#define QHOSTINFO_DEBUG
+
#include "qhostinfo.h"
#include "qhostinfo_p.h"
+#include <qplatformdefs.h>
#include "QtCore/qscopedpointer.h"
#include <qabstracteventdispatcher.h>
#include <qcoreapplication.h>
#include <qmetaobject.h>
+#include <qscopeguard.h>
#include <qstringlist.h>
#include <qthread.h>
#include <qurl.h>
@@ -53,6 +57,15 @@
#ifdef Q_OS_UNIX
# include <unistd.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# if defined(AI_ADDRCONFIG)
+# define Q_ADDRCONFIG AI_ADDRCONFIG
+# endif
+#elif defined Q_OS_WIN
+# include <ws2tcpip.h>
+
+# define QT_SOCKLEN_T int
#endif
QT_BEGIN_NAMESPACE
@@ -64,8 +77,8 @@ Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
namespace {
struct ToBeLookedUpEquals {
typedef bool result_type;
- explicit ToBeLookedUpEquals(const QString &toBeLookedUp) Q_DECL_NOTHROW : m_toBeLookedUp(toBeLookedUp) {}
- result_type operator()(QHostInfoRunnable* lookup) const Q_DECL_NOTHROW
+ explicit ToBeLookedUpEquals(const QString &toBeLookedUp) noexcept : m_toBeLookedUp(toBeLookedUp) {}
+ result_type operator()(QHostInfoRunnable* lookup) const noexcept
{
return m_toBeLookedUp == lookup->toBeLookedUp;
}
@@ -73,13 +86,6 @@ private:
QString m_toBeLookedUp;
};
-// ### C++11: remove once we can use std::any_of()
-template<class InputIt, class UnaryPredicate>
-bool any_of(InputIt first, InputIt last, UnaryPredicate p)
-{
- return std::find_if(first, last, p) != last;
-}
-
template <typename InputIt, typename OutputIt1, typename OutputIt2, typename UnaryPredicate>
std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputIt1 dest1, OutputIt2 dest2, UnaryPredicate p)
{
@@ -96,16 +102,6 @@ std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputI
return std::make_pair(dest1, dest2);
}
-int get_signal_index()
-{
- static auto senderMetaObject = &QHostInfoResult::staticMetaObject;
- static auto signal = &QHostInfoResult::resultsReady;
- int signal_index = -1;
- void *args[] = { &signal_index, &signal };
- senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
- return signal_index + QMetaObjectPrivate::signalOffset(senderMetaObject);
-}
-
}
/*
@@ -123,38 +119,59 @@ void QHostInfoResult::postResultsReady(const QHostInfo &info)
{
// queued connection will take care of dispatching to right thread
if (!slotObj) {
- emitResultsReady(info);
+ emit resultsReady(info);
return;
}
- static const int signal_index = get_signal_index();
-
// we used to have a context object, but it's already destroyed
if (withContextObject && !receiver)
return;
- /* QHostInfoResult c'tor moves the result object to the thread of receiver.
- If we don't have a receiver, then the result object will not live in a
- thread that runs an event loop - so move it to this' thread, which is the thread
- that initiated the lookup, and required to have a running event loop. */
- auto result = new QHostInfoResult(receiver, slotObj);
- if (!receiver)
- result->moveToThread(thread());
+ static const int signal_index = []() -> int {
+ auto senderMetaObject = &QHostInfoResult::staticMetaObject;
+ auto signal = &QHostInfoResult::resultsReady;
+ int signal_index = -1;
+ void *args[] = { &signal_index, &signal };
+ senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
+ return signal_index + QMetaObjectPrivate::signalOffset(senderMetaObject);
+ }();
+
+ // a long-living version of this
+ auto result = new QHostInfoResult(this);
Q_CHECK_PTR(result);
+
const int nargs = 2;
- auto types = reinterpret_cast<int *>(malloc(nargs * sizeof(int)));
- Q_CHECK_PTR(types);
+ auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs);
+ Q_CHECK_PTR(metaCallEvent);
+ void **args = metaCallEvent->args();
+ int *types = metaCallEvent->types();
types[0] = QMetaType::type("void");
types[1] = QMetaType::type("QHostInfo");
- auto args = reinterpret_cast<void **>(malloc(nargs * sizeof(void *)));
- Q_CHECK_PTR(args);
- args[0] = 0;
+ args[0] = nullptr;
args[1] = QMetaType::create(types[1], &info);
Q_CHECK_PTR(args[1]);
- auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs, types, args);
- Q_CHECK_PTR(metaCallEvent);
qApp->postEvent(result, metaCallEvent);
}
+/*
+ Receives the event posted by postResultsReady, and calls the functor.
+*/
+bool QHostInfoResult::event(QEvent *event)
+{
+ if (event->type() == QEvent::MetaCall) {
+ Q_ASSERT(slotObj);
+ auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
+ auto args = metaCallEvent->args();
+ // we didn't have a context object, or it's still alive
+ if (!withContextObject || receiver)
+ slotObj->call(const_cast<QObject*>(receiver.data()), args);
+ slotObj->destroyIfLastRef();
+
+ deleteLater();
+ return true;
+ }
+ return QObject::event(event);
+}
+
/*!
\class QHostInfo
\brief The QHostInfo class provides static functions for host name lookups.
@@ -249,64 +266,9 @@ static int nextId()
\sa abortHostLookup(), addresses(), error(), fromName()
*/
-int QHostInfo::lookupHost(const QString &name, QObject *receiver,
- const char *member)
+int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)
{
-#if defined QHOSTINFO_DEBUG
- qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
- name.toLatin1().constData(), receiver, member ? member + 1 : 0);
-#endif
-
- if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
- qWarning("QHostInfo::lookupHost() called with no event dispatcher");
- return -1;
- }
-
- qRegisterMetaType<QHostInfo>();
-
- int id = nextId(); // generate unique ID
-
- if (name.isEmpty()) {
- if (!receiver)
- return -1;
-
- QHostInfo hostInfo(id);
- hostInfo.setError(QHostInfo::HostNotFound);
- hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
- QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
- QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
- receiver, member, Qt::QueuedConnection);
- result.data()->emitResultsReady(hostInfo);
- return id;
- }
-
- QHostInfoLookupManager *manager = theHostInfoLookupManager();
-
- if (manager) {
- // the application is still alive
- if (manager->cache.isEnabled()) {
- // check cache first
- bool valid = false;
- QHostInfo info = manager->cache.get(name, &valid);
- if (valid) {
- if (!receiver)
- return -1;
-
- info.setLookupId(id);
- QHostInfoResult result;
- QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
- result.emitResultsReady(info);
- return id;
- }
- }
-
- // cache is not enabled or it was not in the cache, do normal lookup
- QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
- if (receiver)
- QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
- manager->scheduleLookup(runnable);
- }
- return id;
+ return QHostInfoPrivate::lookupHostImpl(name, receiver, nullptr, member);
}
/*!
@@ -416,7 +378,7 @@ QHostInfo QHostInfo::fromName(const QString &name)
#endif
QHostInfo hostInfo = QHostInfoAgent::fromName(name);
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
manager->cache.put(name, hostInfo);
return hostInfo;
}
@@ -429,7 +391,7 @@ QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointer<QNetwor
#endif
QHostInfo hostInfo = QHostInfoAgent::fromName(name, session);
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
manager->cache.put(name, hostInfo);
return hostInfo;
}
@@ -442,6 +404,162 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetw
}
#endif
+QHostInfo QHostInfoAgent::reverseLookup(const QHostAddress &address)
+{
+ QHostInfo results;
+ // Reverse lookup
+ sockaddr_in sa4;
+ sockaddr_in6 sa6;
+ sockaddr *sa = 0;
+ QT_SOCKLEN_T saSize;
+ if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ sa = reinterpret_cast<sockaddr *>(&sa4);
+ saSize = sizeof(sa4);
+ memset(&sa4, 0, sizeof(sa4));
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ } else {
+ sa = reinterpret_cast<sockaddr *>(&sa6);
+ saSize = sizeof(sa6);
+ memset(&sa6, 0, sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr));
+ }
+
+ char hbuf[NI_MAXHOST];
+ if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), nullptr, 0, 0) == 0)
+ results.setHostName(QString::fromLatin1(hbuf));
+
+ if (results.hostName().isEmpty())
+ results.setHostName(address.toString());
+ results.setAddresses(QList<QHostAddress>() << address);
+
+ return results;
+}
+
+/*
+ Call getaddrinfo, and returns the results as QHostInfo::addresses
+*/
+QHostInfo QHostInfoAgent::lookup(const QString &hostName)
+{
+ QHostInfo results;
+
+ // IDN support
+ QByteArray aceHostname = QUrl::toAce(hostName);
+ results.setHostName(hostName);
+ if (aceHostname.isEmpty()) {
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(hostName.isEmpty() ?
+ QCoreApplication::translate("QHostInfoAgent", "No host name given") :
+ QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
+ return results;
+ }
+
+ addrinfo *res = 0;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+#ifdef Q_ADDRCONFIG
+ hints.ai_flags = Q_ADDRCONFIG;
+#endif
+
+ int result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res);
+# ifdef Q_ADDRCONFIG
+ if (result == EAI_BADFLAGS) {
+ // if the lookup failed with AI_ADDRCONFIG set, try again without it
+ hints.ai_flags = 0;
+ result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res);
+ }
+# endif
+
+ if (result == 0) {
+ addrinfo *node = res;
+ QList<QHostAddress> addresses;
+ while (node) {
+#ifdef QHOSTINFO_DEBUG
+ qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family
+ << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol
+ << "ai_addrlen:" << node->ai_addrlen;
+#endif
+ switch (node->ai_family) {
+ case AF_INET: {
+ QHostAddress addr;
+ addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ break;
+ }
+ case AF_INET6: {
+ QHostAddress addr;
+ sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
+ addr.setAddress(sa6->sin6_addr.s6_addr);
+ if (sa6->sin6_scope_id)
+ addr.setScopeId(QString::number(sa6->sin6_scope_id));
+ if (!addresses.contains(addr))
+ addresses.append(addr);
+ break;
+ }
+ default:
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type"));
+ }
+ node = node->ai_next;
+ }
+ if (addresses.isEmpty()) {
+ // Reached the end of the list, but no addresses were found; this
+ // means the list contains one or more unknown address types.
+ results.setError(QHostInfo::UnknownError);
+ results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type"));
+ }
+
+ results.setAddresses(addresses);
+ freeaddrinfo(res);
+ } else {
+ switch (result) {
+#ifdef Q_OS_WIN
+ case WSAHOST_NOT_FOUND: //authoritative not found
+ case WSATRY_AGAIN: //non authoritative not found
+ case WSANO_DATA: //valid name, no associated address
+#else
+ case EAI_NONAME:
+ case EAI_FAIL:
+# ifdef EAI_NODATA // EAI_NODATA is deprecated in RFC 3493
+ case EAI_NODATA:
+# endif
+#endif
+ results.setError(QHostInfo::HostNotFound);
+ results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Host not found"));
+ break;
+ default:
+ results.setError(QHostInfo::UnknownError);
+#ifdef Q_OS_WIN
+ results.setErrorString(QString::fromWCharArray(gai_strerror(result)));
+#else
+ results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
+#endif
+ break;
+ }
+ }
+
+#if defined(QHOSTINFO_DEBUG)
+ if (results.error() != QHostInfo::NoError) {
+ qDebug("QHostInfoAgent::fromName(): error #%d %s",
+ h_errno, results.errorString().toLatin1().constData());
+ } else {
+ QString tmp;
+ QList<QHostAddress> addresses = results.addresses();
+ for (int i = 0; i < addresses.count(); ++i) {
+ if (i != 0) tmp += QLatin1String(", ");
+ tmp += addresses.at(i).toString();
+ }
+ qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
+ addresses.count(), aceHostname.constData(),
+ tmp.toLatin1().constData());
+ }
+#endif
+
+ return results;
+}
/*!
\enum QHostInfo::HostInfoError
@@ -462,8 +580,9 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetw
\sa lookupId()
*/
QHostInfo::QHostInfo(int id)
- : d(new QHostInfoPrivate)
+ : d_ptr(new QHostInfoPrivate)
{
+ Q_D(QHostInfo);
d->lookupId = id;
}
@@ -471,17 +590,32 @@ QHostInfo::QHostInfo(int id)
Constructs a copy of \a other.
*/
QHostInfo::QHostInfo(const QHostInfo &other)
- : d(new QHostInfoPrivate(*other.d.data()))
+ : d_ptr(new QHostInfoPrivate(*other.d_ptr))
{
}
/*!
+ \fn QHostInfo(QHostInfo &&other)
+
+ Move-constructs a new QHostInfo from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 5.14
+*/
+
+/*!
Assigns the data of the \a other object to this host info object,
and returns a reference to it.
*/
QHostInfo &QHostInfo::operator=(const QHostInfo &other)
{
- *d.data() = *other.d.data();
+ if (d_ptr)
+ *d_ptr = *other.d_ptr;
+ else
+ d_ptr = new QHostInfoPrivate(*other.d_ptr);
return *this;
}
@@ -490,6 +624,7 @@ QHostInfo &QHostInfo::operator=(const QHostInfo &other)
*/
QHostInfo::~QHostInfo()
{
+ delete d_ptr;
}
/*!
@@ -504,6 +639,7 @@ QHostInfo::~QHostInfo()
*/
QList<QHostAddress> QHostInfo::addresses() const
{
+ Q_D(const QHostInfo);
return d->addrs;
}
@@ -514,6 +650,7 @@ QList<QHostAddress> QHostInfo::addresses() const
*/
void QHostInfo::setAddresses(const QList<QHostAddress> &addresses)
{
+ Q_D(QHostInfo);
d->addrs = addresses;
}
@@ -524,6 +661,7 @@ void QHostInfo::setAddresses(const QList<QHostAddress> &addresses)
*/
QString QHostInfo::hostName() const
{
+ Q_D(const QHostInfo);
return d->hostName;
}
@@ -534,6 +672,7 @@ QString QHostInfo::hostName() const
*/
void QHostInfo::setHostName(const QString &hostName)
{
+ Q_D(QHostInfo);
d->hostName = hostName;
}
@@ -545,6 +684,7 @@ void QHostInfo::setHostName(const QString &hostName)
*/
QHostInfo::HostInfoError QHostInfo::error() const
{
+ Q_D(const QHostInfo);
return d->err;
}
@@ -555,6 +695,7 @@ QHostInfo::HostInfoError QHostInfo::error() const
*/
void QHostInfo::setError(HostInfoError error)
{
+ Q_D(QHostInfo);
d->err = error;
}
@@ -565,6 +706,7 @@ void QHostInfo::setError(HostInfoError error)
*/
int QHostInfo::lookupId() const
{
+ Q_D(const QHostInfo);
return d->lookupId;
}
@@ -575,6 +717,7 @@ int QHostInfo::lookupId() const
*/
void QHostInfo::setLookupId(int id)
{
+ Q_D(QHostInfo);
d->lookupId = id;
}
@@ -586,6 +729,7 @@ void QHostInfo::setLookupId(int id)
*/
QString QHostInfo::errorString() const
{
+ Q_D(const QHostInfo);
return d->errorStr;
}
@@ -597,6 +741,7 @@ QString QHostInfo::errorString() const
*/
void QHostInfo::setErrorString(const QString &str)
{
+ Q_D(QHostInfo);
d->errorStr = str;
}
@@ -631,14 +776,32 @@ QString QHostInfo::localHostName()
\sa hostName()
*/
+// ### Qt 6 merge with function below
int QHostInfo::lookupHostImpl(const QString &name,
const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj)
{
+ return QHostInfoPrivate::lookupHostImpl(name, receiver, slotObj, nullptr);
+}
+/*
+ Called by the various lookupHost overloads to perform the lookup.
+
+ Signals either the functor encapuslated in the \a slotObj in the context
+ of \a receiver, or the \a member slot of the \a receiver.
+
+ \a receiver might be the nullptr, but only if a \a slotObj is provided.
+*/
+int QHostInfoPrivate::lookupHostImpl(const QString &name,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj,
+ const char *member)
+{
#if defined QHOSTINFO_DEBUG
- qDebug("QHostInfo::lookupHost(\"%s\", %p, %p)",
- name.toLatin1().constData(), receiver, slotObj);
+ qDebug("QHostInfoPrivate::lookupHostImpl(\"%s\", %p, %p, %s)",
+ name.toLatin1().constData(), receiver, slotObj, member ? member + 1 : 0);
#endif
+ Q_ASSERT(!member != !slotObj); // one of these must be set, but not both
+ Q_ASSERT(receiver || slotObj);
if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
qWarning("QHostInfo::lookupHost() called with no event dispatcher");
@@ -653,8 +816,13 @@ int QHostInfo::lookupHostImpl(const QString &name,
QHostInfo hostInfo(id);
hostInfo.setError(QHostInfo::HostNotFound);
hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
+
QHostInfoResult result(receiver, slotObj);
+ if (receiver && member)
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
+ receiver, member, Qt::QueuedConnection);
result.postResultsReady(hostInfo);
+
return id;
}
@@ -669,23 +837,24 @@ int QHostInfo::lookupHostImpl(const QString &name,
if (valid) {
info.setLookupId(id);
QHostInfoResult result(receiver, slotObj);
+ if (receiver && member)
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
+ receiver, member, Qt::QueuedConnection);
result.postResultsReady(info);
return id;
}
}
// cache is not enabled or it was not in the cache, do normal lookup
- QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
+ QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
+ if (receiver && member)
+ QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
+ receiver, member, Qt::QueuedConnection);
manager->scheduleLookup(runnable);
}
return id;
}
-QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i) : toBeLookedUp(hn), id(i)
-{
- setAutoDelete(true);
-}
-
QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj) :
toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj)
@@ -697,11 +866,10 @@ QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *re
void QHostInfoRunnable::run()
{
QHostInfoLookupManager *manager = theHostInfoLookupManager();
+ const auto sg = qScopeGuard([&] { manager->lookupFinished(this); });
// check aborted
- if (manager->wasAborted(id)) {
- manager->lookupFinished(this);
+ if (manager->wasAborted(id))
return;
- }
QHostInfo hostInfo;
@@ -723,10 +891,8 @@ void QHostInfoRunnable::run()
}
// check aborted again
- if (manager->wasAborted(id)) {
- manager->lookupFinished(this);
+ if (manager->wasAborted(id))
return;
- }
// signal emission
hostInfo.setLookupId(id);
@@ -750,16 +916,15 @@ void QHostInfoRunnable::run()
}
#endif
- manager->lookupFinished(this);
-
// thread goes back to QThreadPool
}
-QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
+QHostInfoLookupManager::QHostInfoLookupManager() : wasDeleted(false)
{
- moveToThread(QCoreApplicationPrivate::mainThread());
#if QT_CONFIG(thread)
- connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
+ QObject::connect(QCoreApplication::instance(), &QObject::destroyed,
+ &threadPool, [&](QObject *) { threadPool.waitForDone(); },
+ Qt::DirectConnection);
threadPool.setMaxThreadCount(20); // do up to 20 DNS lookups in parallel
#endif
}
@@ -794,10 +959,9 @@ void QHostInfoLookupManager::clear()
cache.clear();
}
-void QHostInfoLookupManager::work()
+// assumes mutex is locked by caller
+void QHostInfoLookupManager::rescheduleWithMutexHeld()
{
- QMutexLocker locker(&mutex);
-
if (wasDeleted)
return;
@@ -816,7 +980,7 @@ void QHostInfoLookupManager::work()
#if QT_CONFIG(thread)
auto isAlreadyRunning = [this](QHostInfoRunnable *lookup) {
- return any_of(currentLookups.cbegin(), currentLookups.cend(), ToBeLookedUpEquals(lookup->toBeLookedUp));
+ return std::any_of(currentLookups.cbegin(), currentLookups.cend(), ToBeLookedUpEquals(lookup->toBeLookedUp));
};
// Transfer any postponed lookups that aren't currently running to the scheduled list, keeping already-running lookups:
@@ -862,7 +1026,7 @@ void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
return;
scheduledLookups.enqueue(r);
- work();
+ rescheduleWithMutexHeld();
}
// called by QHostInfo
@@ -918,7 +1082,7 @@ void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
currentLookups.removeOne(r);
#endif
finishedLookups.append(r);
- work();
+ rescheduleWithMutexHeld();
}
// This function returns immediately when we had a result in the cache, else it will later emit a signal
@@ -928,7 +1092,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
*id = -1;
// check cache
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager && manager->cache.isEnabled()) {
QHostInfo info = manager->cache.get(name, valid);
if (*valid) {
@@ -937,7 +1101,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
}
// was not in cache, trigger lookup
- *id = QHostInfo::lookupHost(name, receiver, member);
+ *id = QHostInfoPrivate::lookupHostImpl(name, receiver, nullptr, member);
// return empty response, valid==false
return QHostInfo();
@@ -945,7 +1109,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char
void qt_qhostinfo_clear_cache()
{
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager) {
manager->clear();
}
@@ -954,7 +1118,7 @@ void qt_qhostinfo_clear_cache()
#ifdef QT_BUILD_INTERNAL
void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
{
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
if (manager) {
manager->cache.setEnabled(e);
}
@@ -962,7 +1126,7 @@ void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
void qt_qhostinfo_cache_inject(const QString &hostname, const QHostInfo &resolution)
{
- QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ QHostInfoLookupManager* manager = theHostInfoLookupManager();
if (!manager || !manager->cache.isEnabled())
return;
@@ -1018,9 +1182,4 @@ void QHostInfoCache::clear()
cache.clear();
}
-QAbstractHostInfoLookupManager* QAbstractHostInfoLookupManager::globalInstance()
-{
- return theHostInfoLookupManager();
-}
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
index 49871ad470..cda286b423 100644
--- a/src/network/kernel/qhostinfo.h
+++ b/src/network/kernel/qhostinfo.h
@@ -62,11 +62,12 @@ public:
explicit QHostInfo(int lookupId = -1);
QHostInfo(const QHostInfo &d);
+ QHostInfo(QHostInfo &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {}
QHostInfo &operator=(const QHostInfo &d);
- QHostInfo &operator=(QHostInfo &&other) Q_DECL_NOTHROW { swap(other); return *this; }
+ QHostInfo &operator=(QHostInfo &&other) noexcept { swap(other); return *this; }
~QHostInfo();
- void swap(QHostInfo &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QHostInfo &other) noexcept { qSwap(d_ptr, other.d_ptr); }
QString hostName() const;
void setHostName(const QString &name);
@@ -147,7 +148,8 @@ public:
#endif // Q_QDOC
private:
- QScopedPointer<QHostInfoPrivate> d;
+ QHostInfoPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QHostInfo)
static int lookupHostImpl(const QString &name,
const QObject *receiver,
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index fa6529bdfd..1798ceab0a 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -81,69 +81,50 @@ QT_BEGIN_NAMESPACE
class QHostInfoResult : public QObject
{
Q_OBJECT
-
- QPointer<const QObject> receiver = nullptr;
- QtPrivate::QSlotObjectBase *slotObj = nullptr;
- const bool withContextObject = false;
-
public:
- QHostInfoResult() = default;
- QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) :
- receiver(receiver),
- slotObj(slotObj),
- withContextObject(slotObj && receiver)
+ QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
+ : receiver(receiver), slotObj(slotObj),
+ withContextObject(slotObj && receiver)
{
- connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this,
- &QObject::deleteLater);
- if (slotObj && receiver)
+ if (receiver)
moveToThread(receiver->thread());
}
void postResultsReady(const QHostInfo &info);
-public Q_SLOTS:
- inline void emitResultsReady(const QHostInfo &info)
- {
- if (slotObj) {
- // we either didn't have a context object, or it's still alive
- if (!withContextObject || receiver) {
- QHostInfo copy = info;
- void *args[2] = { 0, reinterpret_cast<void *>(&copy) };
- slotObj->call(const_cast<QObject*>(receiver.data()), args);
- }
- slotObj->destroyIfLastRef();
- } else {
- emit resultsReady(info);
- }
- }
+Q_SIGNALS:
+ void resultsReady(const QHostInfo &info);
protected:
- bool event(QEvent *event) override
+ bool event(QEvent *event) override;
+
+private:
+ QHostInfoResult(const QHostInfoResult *other)
+ : receiver(other->receiver), slotObj(other->slotObj),
+ withContextObject(other->withContextObject)
{
- if (event->type() == QEvent::MetaCall) {
- auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
- auto args = metaCallEvent->args();
- auto hostInfo = reinterpret_cast<QHostInfo *>(args[1]);
- emitResultsReady(*hostInfo);
- deleteLater();
- return true;
- }
- return QObject::event(event);
+ // cleanup if the application terminates before results are delivered
+ connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
+ this, &QObject::deleteLater);
+ // maintain thread affinity
+ moveToThread(other->thread());
}
-Q_SIGNALS:
- void resultsReady(const QHostInfo &info);
+ QPointer<const QObject> receiver = nullptr;
+ QtPrivate::QSlotObjectBase *slotObj = nullptr;
+ const bool withContextObject = false;
};
-// needs to be QObject because fromName calls tr()
-class QHostInfoAgent : public QObject
+class QHostInfoAgent
{
- Q_OBJECT
public:
static QHostInfo fromName(const QString &hostName);
#ifndef QT_NO_BEARERMANAGEMENT
static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
#endif
+private:
+ static QHostInfo lookup(const QString &hostName);
+ static QHostInfo reverseLookup(const QHostAddress &address);
};
class QHostInfoPrivate
@@ -159,6 +140,10 @@ public:
//not a public API yet
static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession);
#endif
+ static int lookupHostImpl(const QString &name,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj,
+ const char *member);
QHostInfo::HostInfoError err;
QString errorStr;
@@ -203,7 +188,6 @@ private:
class QHostInfoRunnable : public QRunnable
{
public:
- QHostInfoRunnable(const QString &hn, int i);
QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj);
void run() override;
@@ -214,31 +198,13 @@ public:
};
-class QAbstractHostInfoLookupManager : public QObject
+class QHostInfoLookupManager
{
- Q_OBJECT
-
-public:
- ~QAbstractHostInfoLookupManager() {}
- virtual void clear() = 0;
-
- QHostInfoCache cache;
-
-protected:
- QAbstractHostInfoLookupManager() {}
- static QAbstractHostInfoLookupManager* globalInstance();
-
-};
-
-class QHostInfoLookupManager : public QAbstractHostInfoLookupManager
-{
- Q_OBJECT
public:
QHostInfoLookupManager();
~QHostInfoLookupManager();
- void clear() override;
- void work();
+ void clear();
// called from QHostInfo
void scheduleLookup(QHostInfoRunnable *r);
@@ -248,6 +214,8 @@ public:
void lookupFinished(QHostInfoRunnable *r);
bool wasAborted(int id);
+ QHostInfoCache cache;
+
friend class QHostInfoRunnable;
protected:
#if QT_CONFIG(thread)
@@ -265,10 +233,8 @@ protected:
bool wasDeleted;
-private slots:
-#if QT_CONFIG(thread)
- void waitForThreadPoolDone() { threadPool.waitForDone(); }
-#endif
+private:
+ void rescheduleWithMutexHeld();
};
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index e4810d68ee..78a05f8407 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -72,17 +72,6 @@
QT_BEGIN_NAMESPACE
-// Almost always the same. If not, specify in qplatformdefs.h.
-#if !defined(QT_SOCKOPTLEN_T)
-# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
-#endif
-
-// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe
-// with this flag. So disable it in that platform.
-#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX)
-# define Q_ADDRCONFIG AI_ADDRCONFIG
-#endif
-
enum LibResolvFeature {
NeedResInit,
NeedResNInit
@@ -197,132 +186,10 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
local_res_init();
QHostAddress address;
- if (address.setAddress(hostName)) {
- // Reverse lookup
- sockaddr_in sa4;
- sockaddr_in6 sa6;
- sockaddr *sa = 0;
- QT_SOCKLEN_T saSize = 0;
- if (address.protocol() == QAbstractSocket::IPv4Protocol) {
- sa = (sockaddr *)&sa4;
- saSize = sizeof(sa4);
- memset(&sa4, 0, sizeof(sa4));
- sa4.sin_family = AF_INET;
- sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
- }
- else {
- sa = (sockaddr *)&sa6;
- saSize = sizeof(sa6);
- memset(&sa6, 0, sizeof(sa6));
- sa6.sin6_family = AF_INET6;
- memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr));
- }
-
- char hbuf[NI_MAXHOST];
- if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
- results.setHostName(QString::fromLatin1(hbuf));
-
- if (results.hostName().isEmpty())
- results.setHostName(address.toString());
- results.setAddresses(QList<QHostAddress>() << address);
- return results;
- }
-
- // IDN support
- QByteArray aceHostname = QUrl::toAce(hostName);
- results.setHostName(hostName);
- if (aceHostname.isEmpty()) {
- results.setError(QHostInfo::HostNotFound);
- results.setErrorString(hostName.isEmpty() ?
- QCoreApplication::translate("QHostInfoAgent", "No host name given") :
- QCoreApplication::translate("QHostInfoAgent", "Invalid hostname"));
- return results;
- }
-
- // Call getaddrinfo, and place all IPv4 addresses at the start and
- // the IPv6 addresses at the end of the address list in results.
- addrinfo *res = 0;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
-#ifdef Q_ADDRCONFIG
- hints.ai_flags = Q_ADDRCONFIG;
-#endif
+ if (address.setAddress(hostName))
+ return reverseLookup(address);
- int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res);
-# ifdef Q_ADDRCONFIG
- if (result == EAI_BADFLAGS) {
- // if the lookup failed with AI_ADDRCONFIG set, try again without it
- hints.ai_flags = 0;
- result = getaddrinfo(aceHostname.constData(), 0, &hints, &res);
- }
-# endif
-
- if (result == 0) {
- addrinfo *node = res;
- QList<QHostAddress> addresses;
- while (node) {
-#ifdef QHOSTINFO_DEBUG
- qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen;
-#endif
- if (node->ai_family == AF_INET) {
- QHostAddress addr;
- addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
- if (!addresses.contains(addr))
- addresses.append(addr);
- }
- else if (node->ai_family == AF_INET6) {
- QHostAddress addr;
- sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
- addr.setAddress(sa6->sin6_addr.s6_addr);
- if (sa6->sin6_scope_id)
- addr.setScopeId(QString::number(sa6->sin6_scope_id));
- if (!addresses.contains(addr))
- addresses.append(addr);
- }
- node = node->ai_next;
- }
- if (addresses.isEmpty() && node == 0) {
- // Reached the end of the list, but no addresses were found; this
- // means the list contains one or more unknown address types.
- results.setError(QHostInfo::UnknownError);
- results.setErrorString(tr("Unknown address type"));
- }
-
- results.setAddresses(addresses);
- freeaddrinfo(res);
- } else if (result == EAI_NONAME
- || result == EAI_FAIL
-#ifdef EAI_NODATA
- // EAI_NODATA is deprecated in RFC 3493
- || result == EAI_NODATA
-#endif
- ) {
- results.setError(QHostInfo::HostNotFound);
- results.setErrorString(tr("Host not found"));
- } else {
- results.setError(QHostInfo::UnknownError);
- results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
- }
-
-
-#if defined(QHOSTINFO_DEBUG)
- if (results.error() != QHostInfo::NoError) {
- qDebug("QHostInfoAgent::fromName(): error #%d %s",
- h_errno, results.errorString().toLatin1().constData());
- } else {
- QString tmp;
- QList<QHostAddress> addresses = results.addresses();
- for (int i = 0; i < addresses.count(); ++i) {
- if (i != 0) tmp += ", ";
- tmp += addresses.at(i).toString();
- }
- qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
- addresses.count(), hostName.toLatin1().constData(),
- tmp.toLatin1().constData());
- }
-#endif
- return results;
+ return lookup(hostName);
}
QString QHostInfo::localDomainName()
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
index c51e9968f8..0b5cc98970 100644
--- a/src/network/kernel/qhostinfo_win.cpp
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -51,27 +51,10 @@ QT_BEGIN_NAMESPACE
//#define QHOSTINFO_DEBUG
//###
-#define QT_SOCKLEN_T int
#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
#define NI_MAXHOST 1024
#endif
-static void translateWSAError(int error, QHostInfo *results)
-{
- switch (error) {
- case WSAHOST_NOT_FOUND: //authoritative not found
- case WSATRY_AGAIN: //non authoritative not found
- case WSANO_DATA: //valid name, no associated address
- results->setError(QHostInfo::HostNotFound);
- results->setErrorString(QHostInfoAgent::tr("Host not found"));
- return;
- default:
- results->setError(QHostInfo::UnknownError);
- results->setErrorString(QHostInfoAgent::tr("Unknown error (%1)").arg(error));
- return;
- }
-}
-
QHostInfo QHostInfoAgent::fromName(const QString &hostName)
{
QSysInfo::machineHostName(); // this initializes ws2_32.dll
@@ -79,98 +62,15 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QHostInfo results;
#if defined(QHOSTINFO_DEBUG)
- qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)",
- hostName.toLatin1().constData(),
- (getaddrinfo && freeaddrinfo) ? "enabled" : "disabled");
+ qDebug("QHostInfoAgent::fromName(%s) looking up...",
+ hostName.toLatin1().constData());
#endif
QHostAddress address;
- if (address.setAddress(hostName)) {
- // Reverse lookup
- sockaddr_in sa4;
- sockaddr_in6 sa6;
- sockaddr *sa;
- QT_SOCKLEN_T saSize;
- if (address.protocol() == QAbstractSocket::IPv4Protocol) {
- sa = reinterpret_cast<sockaddr *>(&sa4);
- saSize = sizeof(sa4);
- memset(&sa4, 0, sizeof(sa4));
- sa4.sin_family = AF_INET;
- sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
- } else {
- sa = reinterpret_cast<sockaddr *>(&sa6);
- saSize = sizeof(sa6);
- memset(&sa6, 0, sizeof(sa6));
- sa6.sin6_family = AF_INET6;
- memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr));
- }
-
- char hbuf[NI_MAXHOST];
- if (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
- results.setHostName(QString::fromLatin1(hbuf));
-
- if (results.hostName().isEmpty())
- results.setHostName(address.toString());
- results.setAddresses(QList<QHostAddress>() << address);
- return results;
- }
+ if (address.setAddress(hostName))
+ return reverseLookup(address);
- // IDN support
- QByteArray aceHostname = QUrl::toAce(hostName);
- results.setHostName(hostName);
- if (aceHostname.isEmpty()) {
- results.setError(QHostInfo::HostNotFound);
- results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname"));
- return results;
- }
-
- addrinfo *res;
- int err = getaddrinfo(aceHostname.constData(), 0, 0, &res);
- if (err == 0) {
- QList<QHostAddress> addresses;
- for (addrinfo *p = res; p != 0; p = p->ai_next) {
- switch (p->ai_family) {
- case AF_INET: {
- QHostAddress addr;
- addr.setAddress(ntohl(reinterpret_cast<sockaddr_in *>(p->ai_addr)->sin_addr.s_addr));
- if (!addresses.contains(addr))
- addresses.append(addr);
- }
- break;
- case AF_INET6: {
- QHostAddress addr;
- addr.setAddress(reinterpret_cast<const sockaddr_in6 *>(p->ai_addr)->sin6_addr.s6_addr);
- if (!addresses.contains(addr))
- addresses.append(addr);
- }
- break;
- default:
- results.setError(QHostInfo::UnknownError);
- results.setErrorString(tr("Unknown address type"));
- }
- }
- results.setAddresses(addresses);
- freeaddrinfo(res);
- } else {
- translateWSAError(WSAGetLastError(), &results);
- }
-
-#if defined(QHOSTINFO_DEBUG)
- if (results.error() != QHostInfo::NoError) {
- qDebug("QHostInfoAgent::run(): error (%s)",
- results.errorString().toLatin1().constData());
- } else {
- QString tmp;
- QList<QHostAddress> addresses = results.addresses();
- for (int i = 0; i < addresses.count(); ++i) {
- if (i != 0) tmp += ", ";
- tmp += addresses.at(i).toString();
- }
- qDebug("QHostInfoAgent::run(): found %i entries: {%s}",
- addresses.count(), tmp.toLatin1().constData());
- }
-#endif
- return results;
+ return lookup(hostName);
}
// QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp
diff --git a/src/network/kernel/qnetconmonitor_darwin.mm b/src/network/kernel/qnetconmonitor_darwin.mm
new file mode 100644
index 0000000000..f6daf9ed50
--- /dev/null
+++ b/src/network/kernel/qnetconmonitor_darwin.mm
@@ -0,0 +1,419 @@
+/****************************************************************************
+**
+** 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>
+
+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;
+};
+
+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::isNetworkAccessible()
+{
+ // 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()
+{
+ return true;
+}
+
+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..282bac5081
--- /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 Q_AUTOTEST_EXPORT 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 Q_AUTOTEST_EXPORT QNetworkStatusMonitor : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNetworkStatusMonitor();
+ ~QNetworkStatusMonitor();
+
+ bool isNetworkAccessible();
+
+ 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..1ad4e9ba5a
--- /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::isNetworkAccessible()
+{
+ return false;
+}
+
+bool QNetworkStatusMonitor::isEnabled()
+{
+ return false;
+}
+
+void QNetworkStatusMonitor::reachabilityChanged(bool online)
+{
+ Q_UNUSED(online)
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp
new file mode 100644
index 0000000000..1566e7f914
--- /dev/null
+++ b/src/network/kernel/qnetconmonitor_win.cpp
@@ -0,0 +1,712 @@
+/****************************************************************************
+**
+** 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"
+
+#include <QtCore/quuid.h>
+#include <QtCore/qmetaobject.h>
+
+#include <QtNetwork/qnetworkinterface.h>
+
+#include <objbase.h>
+#include <netlistmgr.h>
+#include <wrl/client.h>
+#include <wrl/wrappers/corewrappers.h>
+#include <comdef.h>
+#include <iphlpapi.h>
+
+#include <algorithm>
+
+using namespace Microsoft::WRL;
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor");
+
+namespace {
+QString errorStringFromHResult(HRESULT hr)
+{
+ _com_error error(hr);
+ return QString::fromWCharArray(error.ErrorMessage());
+}
+
+template<typename T>
+bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
+{
+ if (riid == __uuidof(T)) {
+ *ppvObject = static_cast<T *>(from);
+ from->AddRef();
+ return true;
+ }
+ return false;
+}
+
+QNetworkInterface getInterfaceFromHostAddress(const QHostAddress &local)
+{
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ auto it = std::find_if(
+ interfaces.cbegin(), interfaces.cend(), [&local](const QNetworkInterface &iface) {
+ const auto &entries = iface.addressEntries();
+ return std::any_of(entries.cbegin(), entries.cend(),
+ [&local](const QNetworkAddressEntry &entry) {
+ return entry.ip().isEqual(local,
+ QHostAddress::TolerantConversion);
+ });
+ });
+ if (it == interfaces.cend()) {
+ qCWarning(lcNetMon, "Could not find the interface for the local address.");
+ return {};
+ }
+ return *it;
+}
+} // anonymous namespace
+
+class QNetworkConnectionEvents : public INetworkConnectionEvents
+{
+public:
+ QNetworkConnectionEvents(QNetworkConnectionMonitorPrivate *monitor);
+ virtual ~QNetworkConnectionEvents();
+
+ 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
+ NetworkConnectionConnectivityChanged(GUID connectionId, NLM_CONNECTIVITY connectivity) override;
+ HRESULT STDMETHODCALLTYPE NetworkConnectionPropertyChanged(
+ GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE flags) override;
+
+ Q_REQUIRED_RESULT
+ bool setTarget(const QNetworkInterface &iface);
+ Q_REQUIRED_RESULT
+ bool startMonitoring();
+ Q_REQUIRED_RESULT
+ bool stopMonitoring();
+
+private:
+ ComPtr<INetworkConnection> getNetworkConnectionFromAdapterGuid(QUuid guid);
+
+ QUuid currentConnectionId{};
+
+ ComPtr<INetworkListManager> networkListManager;
+ ComPtr<IConnectionPoint> connectionPoint;
+
+ QNetworkConnectionMonitorPrivate *monitor = nullptr;
+
+ QAtomicInteger<ULONG> ref = 0;
+ DWORD cookie = 0;
+};
+
+class QNetworkConnectionMonitorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QNetworkConnectionMonitor);
+
+public:
+ QNetworkConnectionMonitorPrivate();
+ ~QNetworkConnectionMonitorPrivate();
+
+ Q_REQUIRED_RESULT
+ bool setTargets(const QHostAddress &local, const QHostAddress &remote);
+ Q_REQUIRED_RESULT
+ bool startMonitoring();
+ void stopMonitoring();
+
+ void setConnectivity(NLM_CONNECTIVITY newConnectivity);
+
+private:
+ ComPtr<QNetworkConnectionEvents> connectionEvents;
+ // We can assume we have access to internet/subnet when this class is created because
+ // connection has already been established to the peer:
+ NLM_CONNECTIVITY connectivity =
+ NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET
+ | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET);
+
+ bool sameSubnet = false;
+ bool monitoring = false;
+ bool comInitFailed = false;
+ bool remoteIsIPv6 = false;
+};
+
+QNetworkConnectionEvents::QNetworkConnectionEvents(QNetworkConnectionMonitorPrivate *monitor)
+ : monitor(monitor)
+{
+ auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
+ IID_INetworkListManager, &networkListManager);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Could not get a NetworkListManager instance:"
+ << errorStringFromHResult(hr);
+ return;
+ }
+
+ ComPtr<IConnectionPointContainer> connectionPointContainer;
+ hr = networkListManager.As(&connectionPointContainer);
+ if (SUCCEEDED(hr)) {
+ hr = connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents,
+ &connectionPoint);
+ }
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to get connection point for network events:"
+ << errorStringFromHResult(hr);
+ }
+}
+
+QNetworkConnectionEvents::~QNetworkConnectionEvents()
+{
+ Q_ASSERT(ref == 0);
+}
+
+ComPtr<INetworkConnection> QNetworkConnectionEvents::getNetworkConnectionFromAdapterGuid(QUuid guid)
+{
+ ComPtr<IEnumNetworkConnections> connections;
+ auto hr = networkListManager->GetNetworkConnections(connections.GetAddressOf());
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to enumerate network connections:"
+ << errorStringFromHResult(hr);
+ return nullptr;
+ }
+ ComPtr<INetworkConnection> connection = nullptr;
+ do {
+ hr = connections->Next(1, connection.GetAddressOf(), nullptr);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to get next network connection in enumeration:"
+ << errorStringFromHResult(hr);
+ break;
+ }
+ if (connection) {
+ GUID adapterId;
+ hr = connection->GetAdapterId(&adapterId);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to get adapter ID from network connection:"
+ << errorStringFromHResult(hr);
+ continue;
+ }
+ if (guid == adapterId)
+ return connection;
+ }
+ } while (connection);
+ return nullptr;
+}
+
+HRESULT STDMETHODCALLTYPE QNetworkConnectionEvents::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject)
+ return E_INVALIDARG;
+
+ return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
+ || QueryInterfaceImpl<INetworkConnectionEvents>(this, riid, ppvObject)
+ ? S_OK
+ : E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE QNetworkConnectionEvents::NetworkConnectionConnectivityChanged(
+ GUID connectionId, 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
+ QMetaObject::invokeMethod(monitor->q_ptr,
+ [this, connectionId, newConnectivity, monitor = this->monitor]() {
+ if (connectionId == currentConnectionId)
+ monitor->setConnectivity(newConnectivity);
+ },
+ Qt::QueuedConnection);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QNetworkConnectionEvents::NetworkConnectionPropertyChanged(
+ GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE flags)
+{
+ Q_UNUSED(connectionId);
+ Q_UNUSED(flags);
+ return E_NOTIMPL;
+}
+
+bool QNetworkConnectionEvents::setTarget(const QNetworkInterface &iface)
+{
+ // Unset this in case it's already set to something
+ currentConnectionId = QUuid{};
+
+ NET_LUID luid;
+ if (ConvertInterfaceIndexToLuid(iface.index(), &luid) != NO_ERROR) {
+ qCWarning(lcNetMon, "Could not get the LUID for the interface.");
+ return false;
+ }
+ GUID guid;
+ if (ConvertInterfaceLuidToGuid(&luid, &guid) != NO_ERROR) {
+ qCWarning(lcNetMon, "Could not get the GUID for the interface.");
+ return false;
+ }
+ ComPtr<INetworkConnection> connection = getNetworkConnectionFromAdapterGuid(guid);
+ if (!connection) {
+ qCWarning(lcNetMon, "Could not get the INetworkConnection instance for the adapter GUID.");
+ return false;
+ }
+ auto hr = connection->GetConnectionId(&guid);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to get the connection's GUID:" << errorStringFromHResult(hr);
+ return false;
+ }
+ currentConnectionId = guid;
+
+ return true;
+}
+
+bool QNetworkConnectionEvents::startMonitoring()
+{
+ if (currentConnectionId.isNull()) {
+ qCWarning(lcNetMon, "Can not start monitoring, set targets first");
+ return false;
+ }
+ if (!connectionPoint) {
+ qCWarning(lcNetMon,
+ "We don't have the connection point, cannot start listening to events!");
+ return false;
+ }
+
+ auto hr = connectionPoint->Advise(this, &cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to subscribe to network connectivity events:"
+ << errorStringFromHResult(hr);
+ return false;
+ }
+ return true;
+}
+
+bool QNetworkConnectionEvents::stopMonitoring()
+{
+ auto hr = connectionPoint->Unadvise(cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to unsubscribe from network connection events:"
+ << errorStringFromHResult(hr);
+ return false;
+ }
+ cookie = 0;
+ currentConnectionId = QUuid{};
+ return true;
+}
+
+QNetworkConnectionMonitorPrivate::QNetworkConnectionMonitorPrivate()
+{
+ auto hr = CoInitialize(nullptr);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to initialize COM:" << errorStringFromHResult(hr);
+ comInitFailed = true;
+ return;
+ }
+
+ connectionEvents = new QNetworkConnectionEvents(this);
+}
+
+QNetworkConnectionMonitorPrivate::~QNetworkConnectionMonitorPrivate()
+{
+ if (comInitFailed)
+ return;
+ if (monitoring)
+ stopMonitoring();
+ connectionEvents.Reset();
+ CoUninitialize();
+}
+
+bool QNetworkConnectionMonitorPrivate::setTargets(const QHostAddress &local,
+ const QHostAddress &remote)
+{
+ if (comInitFailed)
+ return false;
+
+ QNetworkInterface iface = getInterfaceFromHostAddress(local);
+ if (!iface.isValid())
+ return false;
+ const auto &addressEntries = iface.addressEntries();
+ auto it = std::find_if(
+ addressEntries.cbegin(), addressEntries.cend(),
+ [&local](const QNetworkAddressEntry &entry) { return entry.ip() == local; });
+ if (Q_UNLIKELY(it == addressEntries.cend())) {
+ qCWarning(lcNetMon, "The address entry we were working with disappeared");
+ return false;
+ }
+ sameSubnet = remote.isInSubnet(local, it->prefixLength());
+ remoteIsIPv6 = remote.protocol() == QAbstractSocket::IPv6Protocol;
+
+ return connectionEvents->setTarget(iface);
+}
+
+void QNetworkConnectionMonitorPrivate::setConnectivity(NLM_CONNECTIVITY newConnectivity)
+{
+ Q_Q(QNetworkConnectionMonitor);
+ const bool reachable = q->isReachable();
+ connectivity = newConnectivity;
+ const bool newReachable = q->isReachable();
+ if (reachable != newReachable)
+ emit q->reachabilityChanged(newReachable);
+}
+
+bool QNetworkConnectionMonitorPrivate::startMonitoring()
+{
+ Q_ASSERT(connectionEvents);
+ Q_ASSERT(!monitoring);
+ if (connectionEvents->startMonitoring())
+ monitoring = true;
+ return monitoring;
+}
+
+void QNetworkConnectionMonitorPrivate::stopMonitoring()
+{
+ Q_ASSERT(connectionEvents);
+ Q_ASSERT(monitoring);
+ if (connectionEvents->stopMonitoring())
+ monitoring = false;
+}
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor()
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+}
+
+QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local,
+ const QHostAddress &remote)
+ : QObject(*new QNetworkConnectionMonitorPrivate)
+{
+ setTargets(local, remote);
+}
+
+QNetworkConnectionMonitor::~QNetworkConnectionMonitor() = default;
+
+bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote)
+{
+ 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;
+ }
+ // Silently return false for loopback addresses instead of printing warnings later
+ if (remote.isLoopback())
+ return false;
+
+ return d_func()->setTargets(local, remote);
+}
+
+bool QNetworkConnectionMonitor::startMonitoring()
+{
+ Q_D(QNetworkConnectionMonitor);
+ if (isMonitoring()) {
+ qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ return false;
+ }
+ return d->startMonitoring();
+}
+
+bool QNetworkConnectionMonitor::isMonitoring() const
+{
+ return d_func()->monitoring;
+}
+
+void QNetworkConnectionMonitor::stopMonitoring()
+{
+ Q_D(QNetworkConnectionMonitor);
+ if (!isMonitoring()) {
+ qCWarning(lcNetMon, "stopMonitoring was called when not monitoring!");
+ return;
+ }
+ d->stopMonitoring();
+}
+
+bool QNetworkConnectionMonitor::isReachable()
+{
+ Q_D(QNetworkConnectionMonitor);
+ NLM_CONNECTIVITY required = d->sameSubnet
+ ? (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_SUBNET : NLM_CONNECTIVITY_IPV4_SUBNET)
+ : (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET : NLM_CONNECTIVITY_IPV4_INTERNET);
+ return d_func()->connectivity & required;
+}
+
+class QNetworkListManagerEvents : public INetworkListManagerEvents
+{
+public:
+ QNetworkListManagerEvents(QNetworkStatusMonitorPrivate *monitor);
+ 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;
+
+ Q_REQUIRED_RESULT
+ bool start();
+ Q_REQUIRED_RESULT
+ bool stop();
+
+private:
+ ComPtr<INetworkListManager> networkListManager = nullptr;
+ ComPtr<IConnectionPoint> connectionPoint = nullptr;
+
+ QNetworkStatusMonitorPrivate *monitor = nullptr;
+
+ QAtomicInteger<ULONG> ref = 0;
+ DWORD cookie = 0;
+};
+
+class QNetworkStatusMonitorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QNetworkStatusMonitor);
+
+public:
+ QNetworkStatusMonitorPrivate();
+ ~QNetworkStatusMonitorPrivate();
+
+ Q_REQUIRED_RESULT
+ bool start();
+ void stop();
+
+ void setConnectivity(NLM_CONNECTIVITY newConnectivity);
+
+private:
+ friend class QNetworkListManagerEvents;
+
+ ComPtr<QNetworkListManagerEvents> managerEvents;
+ NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED;
+
+ bool monitoring = false;
+ bool comInitFailed = false;
+};
+
+QNetworkListManagerEvents::QNetworkListManagerEvents(QNetworkStatusMonitorPrivate *monitor)
+ : monitor(monitor)
+{
+ auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
+ IID_INetworkListManager, &networkListManager);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Could not get a NetworkListManager instance:"
+ << errorStringFromHResult(hr);
+ return;
+ }
+
+ // Set initial connectivity
+ hr = networkListManager->GetConnectivity(&monitor->connectivity);
+ if (FAILED(hr))
+ qCWarning(lcNetMon) << "Could not get connectivity:" << errorStringFromHResult(hr);
+
+ ComPtr<IConnectionPointContainer> connectionPointContainer;
+ hr = networkListManager.As(&connectionPointContainer);
+ if (SUCCEEDED(hr)) {
+ hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
+ &connectionPoint);
+ }
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "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
+ QMetaObject::invokeMethod(monitor->q_ptr,
+ [newConnectivity, monitor = this->monitor]() {
+ monitor->setConnectivity(newConnectivity);
+ },
+ Qt::QueuedConnection);
+ return S_OK;
+}
+
+bool QNetworkListManagerEvents::start()
+{
+ if (!connectionPoint) {
+ qCWarning(lcNetMon, "Initialization failed, can't start!");
+ return false;
+ }
+ auto hr = connectionPoint->Advise(this, &cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to subscribe to network connectivity events:"
+ << errorStringFromHResult(hr);
+ return false;
+ }
+ return true;
+}
+
+bool QNetworkListManagerEvents::stop()
+{
+ Q_ASSERT(connectionPoint);
+ auto hr = connectionPoint->Unadvise(cookie);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to unsubscribe from network connectivity events:"
+ << errorStringFromHResult(hr);
+ return false;
+ }
+ cookie = 0;
+ return true;
+}
+
+QNetworkStatusMonitorPrivate::QNetworkStatusMonitorPrivate()
+{
+ auto hr = CoInitialize(nullptr);
+ if (FAILED(hr)) {
+ qCWarning(lcNetMon) << "Failed to initialize COM:" << errorStringFromHResult(hr);
+ comInitFailed = true;
+ return;
+ }
+ managerEvents = new QNetworkListManagerEvents(this);
+}
+
+QNetworkStatusMonitorPrivate::~QNetworkStatusMonitorPrivate()
+{
+ if (comInitFailed)
+ return;
+ if (monitoring)
+ stop();
+ managerEvents.Reset();
+ CoUninitialize();
+}
+
+void QNetworkStatusMonitorPrivate::setConnectivity(NLM_CONNECTIVITY newConnectivity)
+{
+ Q_Q(QNetworkStatusMonitor);
+
+ const bool oldAccessibility = q->isNetworkAccessible();
+ connectivity = newConnectivity;
+ const bool accessibility = q->isNetworkAccessible();
+ if (oldAccessibility != accessibility)
+ emit q->onlineStateChanged(accessibility);
+}
+
+bool QNetworkStatusMonitorPrivate::start()
+{
+ if (comInitFailed)
+ return false;
+ Q_ASSERT(managerEvents);
+ Q_ASSERT(!monitoring);
+ if (managerEvents->start())
+ monitoring = true;
+ return monitoring;
+}
+
+void QNetworkStatusMonitorPrivate::stop()
+{
+ Q_ASSERT(managerEvents);
+ Q_ASSERT(monitoring);
+ if (managerEvents->stop())
+ monitoring = false;
+}
+
+QNetworkStatusMonitor::QNetworkStatusMonitor() : QObject(*new QNetworkStatusMonitorPrivate) {}
+
+QNetworkStatusMonitor::~QNetworkStatusMonitor() {}
+
+bool QNetworkStatusMonitor::start()
+{
+ if (isMonitoring()) {
+ qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ return false;
+ }
+
+ return d_func()->start();
+}
+
+void QNetworkStatusMonitor::stop()
+{
+ if (!isMonitoring()) {
+ qCWarning(lcNetMon, "stopMonitoring was called when not monitoring!");
+ return;
+ }
+
+ d_func()->stop();
+}
+
+bool QNetworkStatusMonitor::isMonitoring() const
+{
+ return d_func()->monitoring;
+}
+
+bool QNetworkStatusMonitor::isNetworkAccessible()
+{
+ return d_func()->connectivity
+ & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET
+ | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET);
+}
+
+bool QNetworkStatusMonitor::isEnabled()
+{
+ return true;
+}
+
+void QNetworkStatusMonitor::reachabilityChanged(bool online)
+{
+ Q_UNUSED(online);
+ Q_UNREACHABLE();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkdatagram.h b/src/network/kernel/qnetworkdatagram.h
index 1acb44a1e0..70958fea42 100644
--- a/src/network/kernel/qnetworkdatagram.h
+++ b/src/network/kernel/qnetworkdatagram.h
@@ -61,13 +61,13 @@ public:
~QNetworkDatagram()
{ if (d) destroy(d); }
- QNetworkDatagram(QNetworkDatagram &&other) Q_DECL_NOTHROW
+ QNetworkDatagram(QNetworkDatagram &&other) noexcept
: d(other.d)
{ other.d = nullptr; }
- QNetworkDatagram &operator=(QNetworkDatagram &&other) Q_DECL_NOTHROW
+ QNetworkDatagram &operator=(QNetworkDatagram &&other) noexcept
{ swap(other); return *this; }
- void swap(QNetworkDatagram &other) Q_DECL_NOTHROW
+ void swap(QNetworkDatagram &other) noexcept
{ qSwap(d, other.d); }
void clear();
diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h
index 148fd5e10d..4caedaa38f 100644
--- a/src/network/kernel/qnetworkinterface.h
+++ b/src/network/kernel/qnetworkinterface.h
@@ -64,13 +64,11 @@ public:
QNetworkAddressEntry();
QNetworkAddressEntry(const QNetworkAddressEntry &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkAddressEntry &operator=(QNetworkAddressEntry &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkAddressEntry &operator=(QNetworkAddressEntry &&other) noexcept { swap(other); return *this; }
QNetworkAddressEntry &operator=(const QNetworkAddressEntry &other);
~QNetworkAddressEntry();
- void swap(QNetworkAddressEntry &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkAddressEntry &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkAddressEntry &other) const;
inline bool operator!=(const QNetworkAddressEntry &other) const
@@ -142,13 +140,11 @@ public:
QNetworkInterface();
QNetworkInterface(const QNetworkInterface &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkInterface &operator=(QNetworkInterface &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkInterface &operator=(QNetworkInterface &&other) noexcept { swap(other); return *this; }
QNetworkInterface &operator=(const QNetworkInterface &other);
~QNetworkInterface();
- void swap(QNetworkInterface &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkInterface &other) noexcept { qSwap(d, other.d); }
bool isValid() const;
diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h
index 87a46b75fa..44e27a7e34 100644
--- a/src/network/kernel/qnetworkinterface_p.h
+++ b/src/network/kernel/qnetworkinterface_p.h
@@ -82,7 +82,7 @@ public:
class QNetworkInterfacePrivate: public QSharedData
{
public:
- QNetworkInterfacePrivate() : index(0), flags(0)
+ QNetworkInterfacePrivate() : index(0), flags(nullptr)
{ }
~QNetworkInterfacePrivate()
{ }
diff --git a/src/network/kernel/qnetworkinterface_unix_p.h b/src/network/kernel/qnetworkinterface_unix_p.h
index c085194e3c..553af5a303 100644
--- a/src/network/kernel/qnetworkinterface_unix_p.h
+++ b/src/network/kernel/qnetworkinterface_unix_p.h
@@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE
static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
{
- QNetworkInterface::InterfaceFlags flags = 0;
+ QNetworkInterface::InterfaceFlags flags = nullptr;
flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index febddfd880..a2a89ed94b 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -254,8 +254,7 @@ class QGlobalNetworkProxy
{
public:
QGlobalNetworkProxy()
- : mutex(QMutex::Recursive)
- , applicationLevelProxy(0)
+ : applicationLevelProxy(0)
, applicationLevelProxyFactory(0)
#if QT_CONFIG(socks5)
, socks5SocketEngineHandler(0)
@@ -338,7 +337,7 @@ public:
QList<QNetworkProxy> proxyForQuery(const QNetworkProxyQuery &query);
private:
- QMutex mutex;
+ QRecursiveMutex mutex;
QNetworkProxy *applicationLevelProxy;
QNetworkProxyFactory *applicationLevelProxyFactory;
#if QT_CONFIG(socks5)
@@ -483,7 +482,7 @@ public:
template<> void QSharedDataPointer<QNetworkProxyPrivate>::detach()
{
- if (d && d->ref.load() == 1)
+ if (d && d->ref.loadRelaxed() == 1)
return;
QNetworkProxyPrivate *x = (d ? new QNetworkProxyPrivate(*d)
: new QNetworkProxyPrivate);
@@ -927,7 +926,7 @@ public:
template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
{
- if (d && d->ref.load() == 1)
+ if (d && d->ref.loadRelaxed() == 1)
return;
QNetworkProxyQueryPrivate *x = (d ? new QNetworkProxyQueryPrivate(*d)
: new QNetworkProxyQueryPrivate);
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
index 7e3e6906a8..302a2ce6ca 100644
--- a/src/network/kernel/qnetworkproxy.h
+++ b/src/network/kernel/qnetworkproxy.h
@@ -89,13 +89,11 @@ public:
QueryType queryType = TcpServer);
#endif
QNetworkProxyQuery(const QNetworkProxyQuery &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkProxyQuery &operator=(QNetworkProxyQuery &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkProxyQuery &operator=(QNetworkProxyQuery &&other) noexcept { swap(other); return *this; }
QNetworkProxyQuery &operator=(const QNetworkProxyQuery &other);
~QNetworkProxyQuery();
- void swap(QNetworkProxyQuery &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkProxyQuery &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkProxyQuery &other) const;
inline bool operator!=(const QNetworkProxyQuery &other) const
@@ -161,13 +159,11 @@ public:
QNetworkProxy(ProxyType type, const QString &hostName = QString(), quint16 port = 0,
const QString &user = QString(), const QString &password = QString());
QNetworkProxy(const QNetworkProxy &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QNetworkProxy &operator=(QNetworkProxy &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QNetworkProxy &operator=(QNetworkProxy &&other) noexcept { swap(other); return *this; }
QNetworkProxy &operator=(const QNetworkProxy &other);
~QNetworkProxy();
- void swap(QNetworkProxy &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QNetworkProxy &other) noexcept { qSwap(d, other.d); }
bool operator==(const QNetworkProxy &other) const;
inline bool operator!=(const QNetworkProxy &other) const
diff --git a/src/network/network.pro b/src/network/network.pro
index 9082439f1c..d8453e879c 100644
--- a/src/network/network.pro
+++ b/src/network/network.pro
@@ -26,7 +26,7 @@ qtConfig(bearermanagement) {
ANDROID_BUNDLED_JAR_DEPENDENCIES = \
jar/QtAndroidBearer.jar
ANDROID_LIB_DEPENDENCIES = \
- plugins/bearer/libqandroidbearer.so
+ plugins/bearer/libplugins_bearer_qandroidbearer.so
MODULE_PLUGIN_TYPES = \
bearer
ANDROID_PERMISSIONS += \
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 8eebb06a4d..112e7032d6 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -88,7 +88,7 @@ public:
static QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &, QObject *parent);
static QAbstractSocketEngine *createSocketEngine(qintptr socketDescriptor, QObject *parent);
- QAbstractSocketEngine(QObject *parent = 0);
+ QAbstractSocketEngine(QObject *parent = nullptr);
enum SocketOption {
NonBlockingSocketOption,
@@ -155,7 +155,7 @@ public:
virtual qint64 pendingDatagramSize() const = 0;
#endif // QT_NO_UDPSOCKET
- virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = 0,
+ virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = nullptr,
PacketHeaderOptions = WantNone) = 0;
virtual qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header) = 0;
virtual qint64 bytesToWrite() const = 0;
@@ -163,11 +163,11 @@ public:
virtual int option(SocketOption option) const = 0;
virtual bool setOption(SocketOption option, int value) = 0;
- virtual bool waitForRead(int msecs = 30000, bool *timedOut = 0) = 0;
- virtual bool waitForWrite(int msecs = 30000, bool *timedOut = 0) = 0;
+ virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0;
+ virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0;
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = 0) = 0;
+ int msecs = 30000, bool *timedOut = nullptr) = 0;
QAbstractSocket::SocketError error() const;
QString errorString() const;
@@ -202,7 +202,7 @@ public Q_SLOTS:
public:
void setReceiver(QAbstractSocketEngineReceiver *receiver);
protected:
- QAbstractSocketEngine(QAbstractSocketEnginePrivate &dd, QObject* parent = 0);
+ QAbstractSocketEngine(QAbstractSocketEnginePrivate &dd, QObject* parent = nullptr);
void setError(QAbstractSocket::SocketError error, const QString &errorString) const;
void setState(QAbstractSocket::SocketState state);
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index bfde3870c4..c67b273937 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -524,7 +524,7 @@ void QHttpSocketEngine::slotSocketConnected()
//qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);
if (priv && priv->method != QAuthenticatorPrivate::None) {
d->credentialsSent = true;
- data += "Proxy-Authorization: " + priv->calculateResponse(method, path);
+ data += "Proxy-Authorization: " + priv->calculateResponse(method, path, d->proxy.hostName());
data += "\r\n";
}
data += "\r\n";
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index bbcc09eee9..0c2c450c81 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -79,7 +79,7 @@ public:
ReadResponseContent,
ReadResponseHeader
};
- QHttpSocketEngine(QObject *parent = 0);
+ QHttpSocketEngine(QObject *parent = nullptr);
~QHttpSocketEngine();
bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override;
@@ -126,11 +126,11 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = 0) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override;
+ bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = 0) override;
+ int msecs = 30000, bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index 2c073908cb..92616e59ce 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -78,7 +78,7 @@ class QLocalServerPrivate : public QObjectPrivate
public:
QLocalServerPrivate() :
#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN)
- listenSocket(-1), socketNotifier(0),
+ listenSocket(-1), socketNotifier(nullptr),
#endif
maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError),
socketOptions(QLocalServer::NoOptions)
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 2292566265..e5f0701d14 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -125,7 +125,7 @@ class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine
{
Q_OBJECT
public:
- QNativeSocketEngine(QObject *parent = 0);
+ QNativeSocketEngine(QObject *parent = nullptr);
~QNativeSocketEngine();
bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override;
@@ -161,7 +161,7 @@ public:
qint64 pendingDatagramSize() const override;
#endif // QT_NO_UDPSOCKET
- qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = nullptr,
PacketHeaderOptions = WantNone) override;
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) override;
qint64 bytesToWrite() const override;
@@ -177,11 +177,11 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = 0) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override;
+ bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = 0) override;
+ int msecs = 30000, bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 24c17124dc..3ca586e247 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -1000,8 +1000,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
// parse the ancillary data
struct cmsghdr *cmsgptr;
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_CLANG("-Wsign-compare")
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
+ QT_WARNING_POP
if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
&& cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) {
in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
diff --git a/src/network/socket/qsctpserver.cpp b/src/network/socket/qsctpserver.cpp
index 77cb997192..2aa694b3fd 100644
--- a/src/network/socket/qsctpserver.cpp
+++ b/src/network/socket/qsctpserver.cpp
@@ -229,13 +229,12 @@ QSctpSocket *QSctpServer::nextPendingDatagramConnection()
{
Q_D(QSctpServer);
- QMutableListIterator<QTcpSocket *> i(d->pendingConnections);
- while (i.hasNext()) {
- QSctpSocket *socket = qobject_cast<QSctpSocket *>(i.next());
+ for (auto it = d->pendingConnections.begin(), end = d->pendingConnections.end(); it != end; ++it) {
+ QSctpSocket *socket = qobject_cast<QSctpSocket *>(*it);
Q_ASSERT(socket);
if (socket->isInDatagramMode()) {
- i.remove();
+ d->pendingConnections.erase(it);
Q_ASSERT(d->socketEngine);
d->socketEngine->setReadNotificationEnabled(true);
return socket;
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 18b3ce9db2..8a030601dc 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -322,8 +322,8 @@ public:
protected:
void timerEvent(QTimerEvent * event) override;
- QMutex mutex;
- int sweepTimerId;
+ QRecursiveMutex mutex;
+ int sweepTimerId = -1;
//socket descriptor, data, timestamp
QHash<int, QSocks5BindData *> store;
};
@@ -331,8 +331,6 @@ protected:
Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
QSocks5BindStore::QSocks5BindStore()
- : mutex(QMutex::Recursive)
- , sweepTimerId(-1)
{
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() != thread())
@@ -801,9 +799,9 @@ void QSocks5SocketEnginePrivate::sendRequestMethod()
QByteArray buf;
buf.reserve(270); // big enough for domain name;
- buf[0] = S5_VERSION_5;
- buf[1] = command;
- buf[2] = 0x00;
+ buf.append(char(S5_VERSION_5));
+ buf.append(command);
+ buf.append('\0');
if (peerName.isEmpty() && !qt_socks5_set_host_address_and_port(address, port, &buf)) {
QSOCKS5_DEBUG << "error setting address" << address << " : " << port;
//### set error code ....
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
index ef9d771753..c256987e2d 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -65,7 +65,7 @@ class Q_AUTOTEST_EXPORT QSocks5SocketEngine : public QAbstractSocketEngine
{
Q_OBJECT
public:
- QSocks5SocketEngine(QObject *parent = 0);
+ QSocks5SocketEngine(QObject *parent = nullptr);
~QSocks5SocketEngine();
bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override;
@@ -104,7 +104,7 @@ public:
qint64 pendingDatagramSize() const override;
#endif // QT_NO_UDPSOCKET
- qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
+ qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = nullptr,
PacketHeaderOptions = WantNone) override;
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) override;
qint64 bytesToWrite() const override;
@@ -112,11 +112,11 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = 0) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override;
+ bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = 0) override;
+ int msecs = 30000, bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
index 44ff5b7b39..c3a98ea31a 100644
--- a/src/network/socket/socket.pri
+++ b/src/network/socket/socket.pri
@@ -58,7 +58,7 @@ unix {
msvc: QMAKE_MOC_OPTIONS += -D_WINSOCK_DEPRECATED_NO_WARNINGS
win32:!winrt:SOURCES += socket/qnativesocketengine_win.cpp
-win32:!winrt:LIBS_PRIVATE += -ladvapi32
+win32:!winrt: QMAKE_USE_PRIVATE += advapi32
winrt {
SOURCES += socket/qnativesocketengine_winrt.cpp
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
index 22948e3ca5..020b5aa1af 100644
--- a/src/network/ssl/qasn1element_p.h
+++ b/src/network/ssl/qasn1element_p.h
@@ -156,10 +156,10 @@ public:
static QAsn1Element fromVector(const QVector<QAsn1Element> &items);
static QAsn1Element fromObjectId(const QByteArray &id);
- bool toBool(bool *ok = 0) const;
+ bool toBool(bool *ok = nullptr) const;
QDateTime toDateTime() const;
QMultiMap<QByteArray, QString> toInfo() const;
- qint64 toInteger(bool *ok = 0) const;
+ qint64 toInteger(bool *ok = nullptr) const;
QVector<QAsn1Element> toVector() const;
QByteArray toObjectId() const;
QByteArray toObjectName() const;
diff --git a/src/network/ssl/qdtls.cpp b/src/network/ssl/qdtls.cpp
index 3185bfa124..a2280a7d10 100644
--- a/src/network/ssl/qdtls.cpp
+++ b/src/network/ssl/qdtls.cpp
@@ -342,7 +342,7 @@ QT_BEGIN_NAMESPACE
QSslConfiguration QDtlsBasePrivate::configuration() const
{
auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
- copyPrivate->ref.store(0); // the QSslConfiguration constructor refs up
+ copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
QSslConfiguration copy(copyPrivate);
copyPrivate->sessionCipher = sessionCipher;
copyPrivate->sessionProtocol = sessionProtocol;
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
index 8be53df24f..d9ddcceb40 100644
--- a/src/network/ssl/qdtls_openssl.cpp
+++ b/src/network/ssl/qdtls_openssl.cpp
@@ -729,7 +729,7 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
// Create a deep copy of our configuration
auto configurationCopy = new QSslConfigurationPrivate(dtlsBase->dtlsConfiguration);
- configurationCopy->ref.store(0); // the QSslConfiguration constructor refs up
+ configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
// DTLSTODO: check we do not set something DTLS-incompatible there ...
TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode,
diff --git a/src/network/ssl/qocspresponse.cpp b/src/network/ssl/qocspresponse.cpp
index d564e817ca..bf27bb768b 100644
--- a/src/network/ssl/qocspresponse.cpp
+++ b/src/network/ssl/qocspresponse.cpp
@@ -133,7 +133,7 @@ QOcspResponse::QOcspResponse(const QOcspResponse &) = default;
Move-constructs a QOcspResponse instance.
*/
-QOcspResponse::QOcspResponse(QOcspResponse &&) Q_DECL_NOTHROW = default;
+QOcspResponse::QOcspResponse(QOcspResponse &&) noexcept = default;
/*!
\since 5.13
@@ -154,7 +154,7 @@ QOcspResponse &QOcspResponse::operator=(const QOcspResponse &) = default;
Move-assigns to this QOcspResponse instance.
*/
-QOcspResponse &QOcspResponse::operator=(QOcspResponse &&) Q_DECL_NOTHROW = default;
+QOcspResponse &QOcspResponse::operator=(QOcspResponse &&) noexcept = default;
/*!
\fn void QOcspResponse::swap(QOcspResponse &other)
@@ -239,7 +239,7 @@ Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &
\since 5.13
\relates QHash
*/
-uint qHash(const QOcspResponse &response, uint seed)
+uint qHash(const QOcspResponse &response, uint seed) noexcept
{
const QOcspResponsePrivate *d = response.d.data();
Q_ASSERT(d);
diff --git a/src/network/ssl/qocspresponse.h b/src/network/ssl/qocspresponse.h
index 552a088ba5..cf6be5a369 100644
--- a/src/network/ssl/qocspresponse.h
+++ b/src/network/ssl/qocspresponse.h
@@ -73,7 +73,7 @@ enum class QOcspRevocationReason
};
class QOcspResponse;
-Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed = 0);
+Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed = 0) noexcept;
class QOcspResponsePrivate;
class Q_NETWORK_EXPORT QOcspResponse
@@ -82,11 +82,11 @@ public:
QOcspResponse();
QOcspResponse(const QOcspResponse &other);
- QOcspResponse(QOcspResponse && other) Q_DECL_NOEXCEPT;
+ QOcspResponse(QOcspResponse && other) noexcept;
~QOcspResponse();
QOcspResponse &operator = (const QOcspResponse &other);
- QOcspResponse &operator = (QOcspResponse &&other) Q_DECL_NOTHROW;
+ QOcspResponse &operator = (QOcspResponse &&other) noexcept;
QOcspCertificateStatus certificateStatus() const;
QOcspRevocationReason revocationReason() const;
@@ -94,13 +94,13 @@ public:
class QSslCertificate responder() const;
QSslCertificate subject() const;
- void swap(QOcspResponse &other) Q_DECL_NOTHROW { d.swap(other.d); }
+ void swap(QOcspResponse &other) noexcept { d.swap(other.d); }
private:
friend class QSslSocketBackendPrivate;
friend Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs);
- friend Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed);
+ friend Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed) noexcept;
QSharedDataPointer<QOcspResponsePrivate> d;
};
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index 266fcdacb4..69901b526c 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -66,7 +66,7 @@ class QStringList;
class QSslCertificate;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-Q_NETWORK_EXPORT uint qHash(const QSslCertificate &key, uint seed = 0) Q_DECL_NOTHROW;
+Q_NETWORK_EXPORT uint qHash(const QSslCertificate &key, uint seed = 0) noexcept;
class QSslCertificatePrivate;
class Q_NETWORK_EXPORT QSslCertificate
@@ -88,12 +88,10 @@ public:
explicit QSslCertificate(const QByteArray &data = QByteArray(), QSsl::EncodingFormat format = QSsl::Pem);
QSslCertificate(const QSslCertificate &other);
~QSslCertificate();
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslCertificate &operator=(QSslCertificate &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslCertificate &operator=(QSslCertificate &&other) noexcept { swap(other); return *this; }
QSslCertificate &operator=(const QSslCertificate &other);
- void swap(QSslCertificate &other) Q_DECL_NOTHROW
+ void swap(QSslCertificate &other) noexcept
{ qSwap(d, other.d); }
bool operator==(const QSslCertificate &other) const;
@@ -169,7 +167,7 @@ private:
friend class QSslCertificatePrivate;
friend class QSslSocketBackendPrivate;
- friend Q_NETWORK_EXPORT uint qHash(const QSslCertificate &key, uint seed) Q_DECL_NOTHROW;
+ friend Q_NETWORK_EXPORT uint qHash(const QSslCertificate &key, uint seed) noexcept;
};
Q_DECLARE_SHARED(QSslCertificate)
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp
index 899c8a0d2d..6f1fb26add 100644
--- a/src/network/ssl/qsslcertificate_openssl.cpp
+++ b/src/network/ssl/qsslcertificate_openssl.cpp
@@ -45,12 +45,19 @@
#include "qsslcertificateextension_p.h"
#include <QtCore/qendian.h>
+#include <QtCore/qmutex.h>
-#if QT_CONFIG(thread)
-#include <QtCore/private/qmutexpool_p.h>
-#endif
QT_BEGIN_NAMESPACE
+Q_CONSTEXPR int MutexPoolSize = 17;
+static QBasicMutex mutexPool[MutexPoolSize];
+namespace QMutexPool {
+ static QBasicMutex *globalInstanceGet(const void *addr)
+ {
+ return mutexPool + (quintptr(addr) % MutexPoolSize);
+ }
+}
+
// forward declaration
static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
@@ -65,7 +72,7 @@ bool QSslCertificate::operator==(const QSslCertificate &other) const
return false;
}
-uint qHash(const QSslCertificate &key, uint seed) Q_DECL_NOTHROW
+uint qHash(const QSslCertificate &key, uint seed) noexcept
{
if (X509 * const x509 = key.d->x509) {
const EVP_MD *sha1 = q_EVP_sha1();
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4b331d4c4e..234cd45ceb 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -87,7 +87,7 @@ class QSslCertificatePrivate
{
public:
QSslCertificatePrivate()
- : null(true), x509(0)
+ : null(true), x509(nullptr)
{
#ifndef QT_NO_SSL
QSslSocketPrivate::ensureInitialized();
diff --git a/src/network/ssl/qsslcertificate_qt.cpp b/src/network/ssl/qsslcertificate_qt.cpp
index cce59b5ef3..8b5035ad96 100644
--- a/src/network/ssl/qsslcertificate_qt.cpp
+++ b/src/network/ssl/qsslcertificate_qt.cpp
@@ -64,7 +64,7 @@ bool QSslCertificate::operator==(const QSslCertificate &other) const
return d->derData == other.d->derData;
}
-uint qHash(const QSslCertificate &key, uint seed) Q_DECL_NOTHROW
+uint qHash(const QSslCertificate &key, uint seed) noexcept
{
// DER is the native encoding here, so toDer() is just "return d->derData":
return qHash(key.toDer(), seed);
diff --git a/src/network/ssl/qsslcertificateextension.h b/src/network/ssl/qsslcertificateextension.h
index c2910e1707..7cc8a888be 100644
--- a/src/network/ssl/qsslcertificateextension.h
+++ b/src/network/ssl/qsslcertificateextension.h
@@ -55,13 +55,11 @@ class Q_NETWORK_EXPORT QSslCertificateExtension
public:
QSslCertificateExtension();
QSslCertificateExtension(const QSslCertificateExtension &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslCertificateExtension &operator=(QSslCertificateExtension &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslCertificateExtension &operator=(QSslCertificateExtension &&other) noexcept { swap(other); return *this; }
QSslCertificateExtension &operator=(const QSslCertificateExtension &other);
~QSslCertificateExtension();
- void swap(QSslCertificateExtension &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QSslCertificateExtension &other) noexcept { qSwap(d, other.d); }
QString oid() const;
QString name() const;
diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h
index c6328e0169..6994f590ae 100644
--- a/src/network/ssl/qsslcipher.h
+++ b/src/network/ssl/qsslcipher.h
@@ -59,13 +59,11 @@ public:
explicit QSslCipher(const QString &name);
QSslCipher(const QString &name, QSsl::SslProtocol protocol);
QSslCipher(const QSslCipher &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslCipher &operator=(QSslCipher &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslCipher &operator=(QSslCipher &&other) noexcept { swap(other); return *this; }
QSslCipher &operator=(const QSslCipher &other);
~QSslCipher();
- void swap(QSslCipher &other) Q_DECL_NOTHROW
+ void swap(QSslCipher &other) noexcept
{ qSwap(d, other.d); }
bool operator==(const QSslCipher &other) const;
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 8f53e25a53..c25c2686de 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -85,12 +85,10 @@ public:
QSslConfiguration();
QSslConfiguration(const QSslConfiguration &other);
~QSslConfiguration();
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslConfiguration &operator=(QSslConfiguration &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslConfiguration &operator=(QSslConfiguration &&other) noexcept { swap(other); return *this; }
QSslConfiguration &operator=(const QSslConfiguration &other);
- void swap(QSslConfiguration &other) Q_DECL_NOTHROW
+ void swap(QSslConfiguration &other) noexcept
{ qSwap(d, other.d); }
bool operator==(const QSslConfiguration &other) const;
diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp
index 21a5c779f7..db023b7331 100644
--- a/src/network/ssl/qsslcontext_openssl11.cpp
+++ b/src/network/ssl/qsslcontext_openssl11.cpp
@@ -193,7 +193,6 @@ init_context:
minVersion = TLS1_2_VERSION;
maxVersion = 0;
break;
-#if QT_CONFIG(dtls)
case QSsl::DtlsV1_0:
minVersion = DTLS1_VERSION;
maxVersion = DTLS1_VERSION;
@@ -210,7 +209,6 @@ init_context:
minVersion = DTLS1_2_VERSION;
maxVersion = DTLS_MAX_VERSION;
break;
-#endif // dtls
case QSsl::TlsV1_3OrLater:
#ifdef TLS1_3_VERSION
minVersion = TLS1_3_VERSION;
diff --git a/src/network/ssl/qsslcontext_openssl_p.h b/src/network/ssl/qsslcontext_openssl_p.h
index 48beebf134..1fa27279c7 100644
--- a/src/network/ssl/qsslcontext_openssl_p.h
+++ b/src/network/ssl/qsslcontext_openssl_p.h
@@ -89,7 +89,7 @@ public:
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
// must be public because we want to use it from an OpenSSL callback
struct NPNContext {
- NPNContext() : data(0),
+ NPNContext() : data(nullptr),
len(0),
status(QSslConfiguration::NextProtocolNegotiationNone)
{ }
diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp
index 65041d4456..7807afaa30 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters.cpp
@@ -213,7 +213,7 @@ QSslDiffieHellmanParameters &QSslDiffieHellmanParameters::operator=(const QSslDi
Setting an empty QSslDiffieHellmanParameters instance on a QSslSocket-based
server will disable Diffie-Hellman key exchange.
*/
-bool QSslDiffieHellmanParameters::isEmpty() const Q_DECL_NOTHROW
+bool QSslDiffieHellmanParameters::isEmpty() const noexcept
{
return d->derData.isNull() && d->error == QSslDiffieHellmanParameters::NoError;
}
@@ -229,7 +229,7 @@ bool QSslDiffieHellmanParameters::isEmpty() const Q_DECL_NOTHROW
\sa error()
*/
-bool QSslDiffieHellmanParameters::isValid() const Q_DECL_NOTHROW
+bool QSslDiffieHellmanParameters::isValid() const noexcept
{
return d->error == QSslDiffieHellmanParameters::NoError;
}
@@ -253,7 +253,7 @@ bool QSslDiffieHellmanParameters::isValid() const Q_DECL_NOTHROW
Returns the error that caused the QSslDiffieHellmanParameters object
to be invalid.
*/
-QSslDiffieHellmanParameters::Error QSslDiffieHellmanParameters::error() const Q_DECL_NOTHROW
+QSslDiffieHellmanParameters::Error QSslDiffieHellmanParameters::error() const noexcept
{
return d->error;
}
@@ -262,7 +262,7 @@ QSslDiffieHellmanParameters::Error QSslDiffieHellmanParameters::error() const Q_
Returns a human-readable description of the error that caused the
QSslDiffieHellmanParameters object to be invalid.
*/
-QString QSslDiffieHellmanParameters::errorString() const Q_DECL_NOTHROW
+QString QSslDiffieHellmanParameters::errorString() const noexcept
{
switch (d->error) {
case QSslDiffieHellmanParameters::NoError:
@@ -283,7 +283,7 @@ QString QSslDiffieHellmanParameters::errorString() const Q_DECL_NOTHROW
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
*/
-bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) Q_DECL_NOTHROW
+bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
{
return lhs.d->derData == rhs.d->derData;
}
@@ -316,7 +316,7 @@ QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparam)
Returns an hash value for \a dhparam, using \a seed to seed
the calculation.
*/
-uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed) Q_DECL_NOTHROW
+uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed) noexcept
{
return qHash(dhparam.d->derData, seed);
}
diff --git a/src/network/ssl/qssldiffiehellmanparameters.h b/src/network/ssl/qssldiffiehellmanparameters.h
index 497d2bebfb..f62a3b8f44 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.h
+++ b/src/network/ssl/qssldiffiehellmanparameters.h
@@ -56,16 +56,16 @@ class QSslDiffieHellmanParametersPrivate;
class QSslDiffieHellmanParameters;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-Q_NETWORK_EXPORT uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed = 0) Q_DECL_NOTHROW;
+Q_NETWORK_EXPORT uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed = 0) noexcept;
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparams);
#endif
-Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) Q_DECL_NOTHROW;
+Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
-inline bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) Q_DECL_NOTHROW
+inline bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
{
return !operator==(lhs, rhs);
}
@@ -83,30 +83,30 @@ public:
Q_NETWORK_EXPORT QSslDiffieHellmanParameters();
Q_NETWORK_EXPORT QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other);
- QSslDiffieHellmanParameters(QSslDiffieHellmanParameters &&other) Q_DECL_NOTHROW : d(other.d) { other.d = nullptr; }
+ QSslDiffieHellmanParameters(QSslDiffieHellmanParameters &&other) noexcept : d(other.d) { other.d = nullptr; }
Q_NETWORK_EXPORT ~QSslDiffieHellmanParameters();
Q_NETWORK_EXPORT QSslDiffieHellmanParameters &operator=(const QSslDiffieHellmanParameters &other);
- QSslDiffieHellmanParameters &operator=(QSslDiffieHellmanParameters &&other) Q_DECL_NOTHROW { swap(other); return *this; }
+ QSslDiffieHellmanParameters &operator=(QSslDiffieHellmanParameters &&other) noexcept { swap(other); return *this; }
- void swap(QSslDiffieHellmanParameters &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QSslDiffieHellmanParameters &other) noexcept { qSwap(d, other.d); }
Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat format = QSsl::Pem);
Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
- Q_NETWORK_EXPORT bool isEmpty() const Q_DECL_NOTHROW;
- Q_NETWORK_EXPORT bool isValid() const Q_DECL_NOTHROW;
- Q_NETWORK_EXPORT Error error() const Q_DECL_NOTHROW;
- Q_NETWORK_EXPORT QString errorString() const Q_DECL_NOTHROW;
+ Q_NETWORK_EXPORT bool isEmpty() const noexcept;
+ Q_NETWORK_EXPORT bool isValid() const noexcept;
+ Q_NETWORK_EXPORT Error error() const noexcept;
+ Q_NETWORK_EXPORT QString errorString() const noexcept;
private:
QSslDiffieHellmanParametersPrivate *d;
friend class QSslContext;
- friend Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) Q_DECL_NOTHROW;
+ friend Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
#ifndef QT_NO_DEBUG_STREAM
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparam);
#endif
- friend Q_NETWORK_EXPORT uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed) Q_DECL_NOTHROW;
+ friend Q_NETWORK_EXPORT uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed) noexcept;
};
Q_DECLARE_SHARED(QSslDiffieHellmanParameters)
diff --git a/src/network/ssl/qsslellipticcurve.h b/src/network/ssl/qsslellipticcurve.h
index 57dda19bad..28de3a03b4 100644
--- a/src/network/ssl/qsslellipticcurve.h
+++ b/src/network/ssl/qsslellipticcurve.h
@@ -52,11 +52,11 @@ QT_BEGIN_NAMESPACE
class QSslEllipticCurve;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed = 0) Q_DECL_NOTHROW;
+Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed = 0) noexcept;
class QSslEllipticCurve {
public:
- Q_DECL_CONSTEXPR QSslEllipticCurve() Q_DECL_NOTHROW
+ Q_DECL_CONSTEXPR QSslEllipticCurve() noexcept
: id(0)
{
}
@@ -67,18 +67,18 @@ public:
Q_REQUIRED_RESULT Q_NETWORK_EXPORT QString shortName() const;
Q_REQUIRED_RESULT Q_NETWORK_EXPORT QString longName() const;
- Q_DECL_CONSTEXPR bool isValid() const Q_DECL_NOTHROW
+ Q_DECL_CONSTEXPR bool isValid() const noexcept
{
return id != 0;
}
- Q_NETWORK_EXPORT bool isTlsNamedCurve() const Q_DECL_NOTHROW;
+ Q_NETWORK_EXPORT bool isTlsNamedCurve() const noexcept;
private:
int id;
- friend Q_DECL_CONSTEXPR bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW;
- friend Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed) Q_DECL_NOTHROW;
+ friend Q_DECL_CONSTEXPR bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept;
+ friend Q_DECL_CONSTEXPR uint qHash(QSslEllipticCurve curve, uint seed) noexcept;
friend class QSslContext;
friend class QSslSocketPrivate;
@@ -87,13 +87,13 @@ private:
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
-Q_DECL_CONSTEXPR inline uint qHash(QSslEllipticCurve curve, uint seed) Q_DECL_NOTHROW
+Q_DECL_CONSTEXPR inline uint qHash(QSslEllipticCurve curve, uint seed) noexcept
{ return qHash(curve.id, seed); }
-Q_DECL_CONSTEXPR inline bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW
+Q_DECL_CONSTEXPR inline bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
{ return lhs.id == rhs.id; }
-Q_DECL_CONSTEXPR inline bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) Q_DECL_NOTHROW
+Q_DECL_CONSTEXPR inline bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
{ return !operator==(lhs, rhs); }
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp
index 93e081b9e0..1313e06875 100644
--- a/src/network/ssl/qsslellipticcurve_dummy.cpp
+++ b/src/network/ssl/qsslellipticcurve_dummy.cpp
@@ -63,7 +63,7 @@ QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
return QSslEllipticCurve();
}
-bool QSslEllipticCurve::isTlsNamedCurve() const Q_DECL_NOTHROW
+bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
{
return false;
}
diff --git a/src/network/ssl/qsslellipticcurve_openssl.cpp b/src/network/ssl/qsslellipticcurve_openssl.cpp
index 8cd14837f0..b5e38ada53 100644
--- a/src/network/ssl/qsslellipticcurve_openssl.cpp
+++ b/src/network/ssl/qsslellipticcurve_openssl.cpp
@@ -170,7 +170,7 @@ static const int tlsNamedCurveNIDs[] = {
static const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
-bool QSslEllipticCurve::isTlsNamedCurve() const Q_DECL_NOTHROW
+bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
{
const int * const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp
index 02dd16a58d..cdc018a508 100644
--- a/src/network/ssl/qsslerror.cpp
+++ b/src/network/ssl/qsslerror.cpp
@@ -86,6 +86,7 @@
\value UnspecifiedError
\value NoSslSupport
\value CertificateBlacklisted
+ \value CertificateStatusUnknown
\value OcspNoResponseFound
\value OcspMalformedRequest
\value OcspMalformedResponse
@@ -361,11 +362,11 @@ QSslCertificate QSslError::certificate() const
\since 5.4
\relates QHash
*/
-uint qHash(const QSslError &key, uint seed) Q_DECL_NOTHROW
+uint qHash(const QSslError &key, uint seed) noexcept
{
- // 2x boost::hash_combine inlined:
- seed ^= qHash(key.error()) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
- seed ^= qHash(key.certificate()) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.error());
+ seed = hash(seed, key.certificate());
return seed;
}
diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h
index 513b8afd7f..28eb1a9ea8 100644
--- a/src/network/ssl/qsslerror.h
+++ b/src/network/ssl/qsslerror.h
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
class QSslErrorPrivate;
class Q_NETWORK_EXPORT QSslError
{
+ Q_GADGET
public:
enum SslError {
NoError,
@@ -94,6 +95,7 @@ public:
OcspStatusUnknown,
UnspecifiedError = -1
};
+ Q_ENUM(SslError)
// RVCT compiler in debug build does not like about default values in const-
// So as an workaround we define all constructor overloads here explicitly
@@ -103,13 +105,11 @@ public:
QSslError(const QSslError &other);
- void swap(QSslError &other) Q_DECL_NOTHROW
+ void swap(QSslError &other) noexcept
{ qSwap(d, other.d); }
~QSslError();
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslError &operator=(QSslError &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslError &operator=(QSslError &&other) noexcept { swap(other); return *this; }
QSslError &operator=(const QSslError &other);
bool operator==(const QSslError &other) const;
inline bool operator!=(const QSslError &other) const
@@ -124,7 +124,7 @@ private:
};
Q_DECLARE_SHARED(QSslError)
-Q_NETWORK_EXPORT uint qHash(const QSslError &key, uint seed = 0) Q_DECL_NOTHROW;
+Q_NETWORK_EXPORT uint qHash(const QSslError &key, uint seed = 0) noexcept;
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h
index 6de02b1e44..74be406539 100644
--- a/src/network/ssl/qsslkey.h
+++ b/src/network/ssl/qsslkey.h
@@ -71,13 +71,12 @@ public:
const QByteArray &passPhrase = QByteArray());
explicit QSslKey(Qt::HANDLE handle, QSsl::KeyType type = QSsl::PrivateKey);
QSslKey(const QSslKey &other);
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslKey &operator=(QSslKey &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslKey(QSslKey &&other) noexcept;
+ QSslKey &operator=(QSslKey &&other) noexcept;
QSslKey &operator=(const QSslKey &other);
~QSslKey();
- void swap(QSslKey &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QSslKey &other) noexcept { qSwap(d, other.d); }
bool isNull() const;
void clear();
diff --git a/src/network/ssl/qsslkey_mac.cpp b/src/network/ssl/qsslkey_mac.cpp
index d460cbfdab..814fe1c4bc 100644
--- a/src/network/ssl/qsslkey_mac.cpp
+++ b/src/network/ssl/qsslkey_mac.cpp
@@ -42,7 +42,9 @@
#include <CommonCrypto/CommonCrypto.h>
-QT_USE_NAMESPACE
+#include <cstddef>
+
+QT_BEGIN_NAMESPACE
static QByteArray wrapCCCrypt(CCOperation ccOp,
QSslKeyPrivate::Cipher cipher,
@@ -64,17 +66,23 @@ static QByteArray wrapCCCrypt(CCOperation ccOp,
blockSize = kCCBlockSizeRC2;
ccAlgorithm = kCCAlgorithmRC2;
break;
- };
+ case QSslKeyPrivate::Aes128Cbc:
+ case QSslKeyPrivate::Aes192Cbc:
+ case QSslKeyPrivate::Aes256Cbc:
+ blockSize = kCCBlockSizeAES128;
+ ccAlgorithm = kCCAlgorithmAES;
+ break;
+ }
size_t plainLength = 0;
QByteArray plain(data.size() + blockSize, 0);
CCCryptorStatus status = CCCrypt(
ccOp, ccAlgorithm, kCCOptionPKCS7Padding,
- key.constData(), key.size(),
+ key.constData(), std::size_t(key.size()),
iv.constData(),
- data.constData(), data.size(),
- plain.data(), plain.size(), &plainLength);
+ data.constData(), std::size_t(data.size()),
+ plain.data(), std::size_t(plain.size()), &plainLength);
if (status == kCCSuccess)
- return plain.left(plainLength);
+ return plain.left(int(plainLength));
return QByteArray();
}
@@ -87,3 +95,5 @@ QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const
{
return wrapCCCrypt(kCCEncrypt, cipher, data, key, iv);
}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index 99c1a39c73..888058df22 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -333,6 +333,15 @@ static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
type = q_EVP_rc2_cbc();
#endif
break;
+ case QSslKeyPrivate::Aes128Cbc:
+ type = q_EVP_aes_128_cbc();
+ break;
+ case QSslKeyPrivate::Aes192Cbc:
+ type = q_EVP_aes_192_cbc();
+ break;
+ case QSslKeyPrivate::Aes256Cbc:
+ type = q_EVP_aes_256_cbc();
+ break;
}
if (type == nullptr)
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index 5c90719fcd..b0d6c729f9 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -385,6 +385,24 @@ QSslKey::QSslKey(const QSslKey &other) : d(other.d)
{
}
+QSslKey::QSslKey(QSslKey &&other) noexcept
+ : d(nullptr)
+{
+ qSwap(d, other.d);
+}
+
+QSslKey &QSslKey::operator=(QSslKey &&other) noexcept
+{
+ if (this == &other)
+ return *this;
+
+ // If no one else is referencing the key data we want to make sure
+ // before we swap the d-ptr that it is not left in memory.
+ d.reset();
+ qSwap(d, other.d);
+ return *this;
+}
+
/*!
Destroys the QSslKey object.
*/
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index 06403b5479..dd1a31b0e5 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -68,7 +68,7 @@ class QSslKeyPrivate
public:
inline QSslKeyPrivate()
: algorithm(QSsl::Opaque)
- , opaque(0)
+ , opaque(nullptr)
{
clear(false);
}
@@ -105,7 +105,10 @@ public:
enum Cipher {
DesCbc,
DesEde3Cbc,
- Rc2Cbc
+ Rc2Cbc,
+ Aes128Cbc,
+ Aes192Cbc,
+ Aes256Cbc
};
Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index 5ebd8ac3bd..43969c3d28 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -48,6 +48,8 @@
#include <QtNetwork/qpassworddigestor.h>
+#include <cstring>
+
QT_USE_NAMESPACE
static const quint8 bits_table[256] = {
@@ -124,6 +126,37 @@ static int numberOfBits(const QByteArray &modulus)
return bits;
}
+static QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
+{
+ // This is somewhat simplified and shortened version of what OpenSSL does.
+ // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
+ // in their code for what they pass as arguments to EVP_BytesToKey when
+ // deriving encryption keys (when reading/writing pems files with encrypted
+ // keys).
+
+ Q_ASSERT(iv.size() >= 8);
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ QByteArray data(passPhrase);
+ data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
+
+ hash.addData(data);
+
+ if (cipher == QSslKeyPrivate::Aes128Cbc)
+ return hash.result();
+
+ QByteArray key(hash.result());
+ hash.reset();
+ hash.addData(key);
+ hash.addData(data);
+
+ if (cipher == QSslKeyPrivate::Aes192Cbc)
+ return key.append(hash.result().constData(), 8);
+
+ return key.append(hash.result());
+}
+
static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
{
QByteArray key;
@@ -145,14 +178,19 @@ static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &pas
case QSslKeyPrivate::Rc2Cbc:
key = hash.result();
break;
+ case QSslKeyPrivate::Aes128Cbc:
+ case QSslKeyPrivate::Aes192Cbc:
+ case QSslKeyPrivate::Aes256Cbc:
+ return deriveAesKey(cipher, passPhrase, iv);
}
return key;
}
void QSslKeyPrivate::clear(bool deep)
{
- Q_UNUSED(deep);
isNull = true;
+ if (deep)
+ std::memset(derData.data(), 0, derData.size());
derData.clear();
keyLength = -1;
}
@@ -378,6 +416,12 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
cipher = DesEde3Cbc;
} else if (dekInfo.first() == "RC2-CBC") {
cipher = Rc2Cbc;
+ } else if (dekInfo.first() == "AES-128-CBC") {
+ cipher = Aes128Cbc;
+ } else if (dekInfo.first() == "AES-192-CBC") {
+ cipher = Aes192Cbc;
+ } else if (dekInfo.first() == "AES-256-CBC") {
+ cipher = Aes256Cbc;
} else {
clear(deepClear);
return;
@@ -554,6 +598,10 @@ static EncryptionData readPbes2(const QVector<QAsn1Element> &element, const QByt
return {};
break;
} // @todo(?): case (RC5 , AES)
+ case QSslKeyPrivate::Cipher::Aes128Cbc:
+ case QSslKeyPrivate::Cipher::Aes192Cbc:
+ case QSslKeyPrivate::Cipher::Aes256Cbc:
+ Q_UNREACHABLE();
}
if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
diff --git a/src/network/ssl/qsslkey_schannel.cpp b/src/network/ssl/qsslkey_schannel.cpp
index 5694068860..1e21d123f4 100644
--- a/src/network/ssl/qsslkey_schannel.cpp
+++ b/src/network/ssl/qsslkey_schannel.cpp
@@ -57,6 +57,10 @@ const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
return BCRYPT_3DES_ALGORITHM;
case QSslKeyPrivate::Cipher::Rc2Cbc:
return BCRYPT_RC2_ALGORITHM;
+ case QSslKeyPrivate::Cipher::Aes128Cbc:
+ case QSslKeyPrivate::Cipher::Aes192Cbc:
+ case QSslKeyPrivate::Cipher::Aes256Cbc:
+ return BCRYPT_AES_ALGORITHM;
}
Q_UNREACHABLE();
}
diff --git a/src/network/ssl/qsslkey_winrt.cpp b/src/network/ssl/qsslkey_winrt.cpp
index f2ed813965..69eaaa387f 100644
--- a/src/network/ssl/qsslkey_winrt.cpp
+++ b/src/network/ssl/qsslkey_winrt.cpp
@@ -83,6 +83,15 @@ struct SslKeyGlobal
hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"RC2_CBC").Get(),
&keyProviders[QSslKeyPrivate::Rc2Cbc]);
Q_ASSERT_SUCCEEDED(hr);
+ hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"AES_CBC").Get(),
+ &keyProviders[QSslKeyPrivate::Aes128Cbc]);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"AES_CBC").Get(),
+ &keyProviders[QSslKeyPrivate::Aes192Cbc]);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"AES_CBC").Get(),
+ &keyProviders[QSslKeyPrivate::Aes256Cbc]);
+ Q_ASSERT_SUCCEEDED(hr);
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
&bufferFactory);
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h
index 423f7731b4..5d714dc34e 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.h
@@ -59,11 +59,9 @@ public:
Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator(const QSslPreSharedKeyAuthenticator &authenticator);
Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator &operator=(const QSslPreSharedKeyAuthenticator &authenticator);
-#ifdef Q_COMPILER_RVALUE_REFS
- QSslPreSharedKeyAuthenticator &operator=(QSslPreSharedKeyAuthenticator &&other) Q_DECL_NOTHROW { swap(other); return *this; }
-#endif
+ QSslPreSharedKeyAuthenticator &operator=(QSslPreSharedKeyAuthenticator &&other) noexcept { swap(other); return *this; }
- void swap(QSslPreSharedKeyAuthenticator &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QSslPreSharedKeyAuthenticator &other) noexcept { qSwap(d, other.d); }
Q_NETWORK_EXPORT QByteArray identityHint() const;
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index e164217e4e..e302aa1761 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -761,8 +761,8 @@ qint64 QSslSocket::bytesAvailable() const
{
Q_D(const QSslSocket);
if (d->mode == UnencryptedMode)
- return QIODevice::bytesAvailable() + (d->plainSocket ? d->plainSocket->bytesAvailable() : 0);
- return QIODevice::bytesAvailable();
+ return QAbstractSocket::bytesAvailable() + (d->plainSocket ? d->plainSocket->bytesAvailable() : 0);
+ return QAbstractSocket::bytesAvailable();
}
/*!
@@ -818,8 +818,8 @@ bool QSslSocket::canReadLine() const
{
Q_D(const QSslSocket);
if (d->mode == UnencryptedMode)
- return QIODevice::canReadLine() || (d->plainSocket && d->plainSocket->canReadLine());
- return QIODevice::canReadLine();
+ return QAbstractSocket::canReadLine() || (d->plainSocket && d->plainSocket->canReadLine());
+ return QAbstractSocket::canReadLine();
}
/*!
@@ -849,8 +849,8 @@ bool QSslSocket::atEnd() const
{
Q_D(const QSslSocket);
if (d->mode == UnencryptedMode)
- return QIODevice::atEnd() && (!d->plainSocket || d->plainSocket->atEnd());
- return QIODevice::atEnd();
+ return QAbstractSocket::atEnd() && (!d->plainSocket || d->plainSocket->atEnd());
+ return QAbstractSocket::atEnd();
}
/*!
@@ -924,7 +924,7 @@ QSslConfiguration QSslSocket::sslConfiguration() const
// create a deep copy of our configuration
QSslConfigurationPrivate *copy = new QSslConfigurationPrivate(d->configuration);
- copy->ref.store(0); // the QSslConfiguration constructor refs up
+ copy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
copy->sessionCipher = d->sessionCipher();
copy->sessionProtocol = d->sessionProtocol();
@@ -1209,12 +1209,21 @@ void QSslSocket::setPrivateKey(const QSslKey &key)
void QSslSocket::setPrivateKey(const QString &fileName, QSsl::KeyAlgorithm algorithm,
QSsl::EncodingFormat format, const QByteArray &passPhrase)
{
- Q_D(QSslSocket);
QFile file(fileName);
- if (file.open(QIODevice::ReadOnly)) {
- d->configuration.privateKey = QSslKey(file.readAll(), algorithm,
- format, QSsl::PrivateKey, passPhrase);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(lcSsl, "QSslSocket::setPrivateKey: Couldn't open file for reading");
+ return;
+ }
+
+ QSslKey key(file.readAll(), algorithm, format, QSsl::PrivateKey, passPhrase);
+ if (key.isNull()) {
+ qCWarning(lcSsl, "QSslSocket::setPrivateKey: "
+ "The specified file does not contain a valid key");
+ return;
}
+
+ Q_D(QSslSocket);
+ d->configuration.privateKey = key;
}
/*!
@@ -1503,7 +1512,7 @@ bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFor
SSL socket's CA certificate database is initialized to the default
CA certificate database.
- \sa QSslConfiguration::defaultCaCertificates(), addCaCertificates()
+ \sa QSslConfiguration::caCertificates(), addCaCertificates()
*/
void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
{
@@ -2369,7 +2378,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
if (!global)
return;
- ptr->ref.store(1);
+ ptr->ref.storeRelaxed(1);
ptr->peerCertificate = global->peerCertificate;
ptr->peerCertificateChain = global->peerCertificateChain;
ptr->localCertificateChain = global->localCertificateChain;
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index e290ba79dd..e0e065679d 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -215,7 +215,7 @@ void QSecureTransportContext::reset(SSLContextRef newContext)
context = newContext;
}
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_securetransport_mutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
//#define QSSLSOCKET_DEBUG
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index c0035d23a8..d4bad1b1a5 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -523,11 +523,12 @@ bool QSslSocketBackendPrivate::initSslContext()
{
Q_Q(QSslSocket);
- // If no external context was set (e.g. bei QHttpNetworkConnection) we will create a default context
+ // If no external context was set (e.g. by QHttpNetworkConnection) we will
+ // create a default context
if (!sslContextPointer) {
// create a deep copy of our configuration
QSslConfigurationPrivate *configurationCopy = new QSslConfigurationPrivate(configuration);
- configurationCopy->ref.store(0); // the QSslConfiguration constructor refs up
+ configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
sslContextPointer = QSslContext::sharedFromConfiguration(mode, configurationCopy, allowRootCertOnDemandLoading);
}
diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp
index b60b8be41f..1d935c5217 100644
--- a/src/network/ssl/qsslsocket_openssl11.cpp
+++ b/src/network/ssl/qsslsocket_openssl11.cpp
@@ -68,10 +68,11 @@
#include <QtCore/qfile.h>
#include <QtCore/qmutex.h>
#include <QtCore/qlibrary.h>
+#include <QtCore/qoperatingsystemversion.h>
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_opensslInitMutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
void QSslSocketPrivate::deinitialize()
{
@@ -142,13 +143,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
if (!s_loadRootCertsOnDemand)
setDefaultCaCertificates(systemCaCertificates());
#ifdef Q_OS_WIN
- //Enabled for fetching additional root certs from windows update on windows 6+
+ //Enabled for fetching additional root certs from windows update on windows.
//This flag is set false by setDefaultCaCertificates() indicating the app uses
//its own cert bundle rather than the system one.
//Same logic that disables the unix on demand cert loading.
//Unlike unix, we do preload the certificates from the cert store.
- if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_0)
- s_loadRootCertsOnDemand = true;
+ s_loadRootCertsOnDemand = true;
#endif
}
diff --git a/src/network/ssl/qsslsocket_openssl11_symbols_p.h b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
index 150617e3d2..0fe0899d4f 100644
--- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
@@ -82,6 +82,7 @@ Q_AUTOTEST_EXPORT const BIO_METHOD *q_BIO_s_mem();
int q_DSA_bits(DSA *a);
int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_up_ref(EVP_PKEY *a);
int q_EVP_PKEY_base_id(EVP_PKEY *a);
int q_RSA_bits(RSA *a);
Q_AUTOTEST_EXPORT int q_OPENSSL_sk_num(OPENSSL_STACK *a);
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 74ac852bcd..1fcfdf9f16 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -63,13 +63,11 @@
# include <QtCore/qlibrary.h>
#endif
#include <QtCore/qmutex.h>
-#if QT_CONFIG(thread)
-#include <private/qmutexpool_p.h>
-#endif
#include <QtCore/qdatetime.h>
#if defined(Q_OS_UNIX)
#include <QtCore/qdir.h>
#endif
+#include <QtCore/private/qmemory_p.h>
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
#include <link.h>
#endif
@@ -150,6 +148,7 @@ DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return nullptr, return)
DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return)
DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
DEFINEFUNC(int, EVP_CIPHER_CTX_reset, EVP_CIPHER_CTX *c, c, return 0, return)
+DEFINEFUNC(int, EVP_PKEY_up_ref, EVP_PKEY *a, a, return 0, return)
DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
@@ -363,6 +362,11 @@ DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return null
#ifndef OPENSSL_NO_RC2
DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
#endif
+#ifndef OPENSSL_NO_AES
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_128_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_192_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_256_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+#endif
DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
@@ -371,6 +375,7 @@ DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
#endif
+DEFINEFUNC2(int, EVP_PKEY_cmp, const EVP_PKEY *a, a, const EVP_PKEY *b, b, return -1, return)
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
@@ -592,8 +597,8 @@ DEFINEFUNC2(PKCS12 *, d2i_PKCS12_bio, BIO *bio, bio, PKCS12 **pkcs12, pkcs12, re
DEFINEFUNC(void, PKCS12_free, PKCS12 *pkcs12, pkcs12, return, DUMMYARG)
#define RESOLVEFUNC(func) \
- if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \
- && !(_q_##func = _q_PTR_##func(libs.second->resolve(#func)))) \
+ if (!(_q_##func = _q_PTR_##func(libs.ssl->resolve(#func))) \
+ && !(_q_##func = _q_PTR_##func(libs.crypto->resolve(#func)))) \
qsslSocketCannotResolveSymbolWarning(#func);
#if !defined QT_LINKED_OPENSSL
@@ -692,7 +697,7 @@ static QStringList libraryPathList()
// discover paths of already loaded libraries
QSet<QString> loadedPaths;
dl_iterate_phdr(dlIterateCallback, &loadedPaths);
- paths.append(loadedPaths.toList());
+ paths.append(loadedPaths.values());
#endif
return paths;
@@ -729,34 +734,31 @@ static QStringList findAllLibCrypto()
# endif
#ifdef Q_OS_WIN
-static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, QPair<QSystemLibrary*, QSystemLibrary*> &pair)
-{
- pair.first = 0;
- pair.second = 0;
- QSystemLibrary *ssleay32 = new QSystemLibrary(ssleay32LibName);
+struct LoadedOpenSsl {
+ std::unique_ptr<QSystemLibrary> ssl, crypto;
+};
+
+static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result)
+{
+ auto ssleay32 = qt_make_unique<QSystemLibrary>(ssleay32LibName);
if (!ssleay32->load(false)) {
- delete ssleay32;
return FALSE;
}
- QSystemLibrary *libeay32 = new QSystemLibrary(libeay32LibName);
+ auto libeay32 = qt_make_unique<QSystemLibrary>(libeay32LibName);
if (!libeay32->load(false)) {
- delete ssleay32;
- delete libeay32;
return FALSE;
}
- pair.first = ssleay32;
- pair.second = libeay32;
+ result.ssl = std::move(ssleay32);
+ result.crypto = std::move(libeay32);
return TRUE;
}
-static QPair<QSystemLibrary*, QSystemLibrary*> loadOpenSslWin32()
+static LoadedOpenSsl loadOpenSsl()
{
- QPair<QSystemLibrary*,QSystemLibrary*> pair;
- pair.first = 0;
- pair.second = 0;
+ LoadedOpenSsl result;
#if QT_CONFIG(opensslv11)
// With OpenSSL 1.1 the names have changed to libssl-1_1(-x64) and libcrypto-1_1(-x64), for builds using
@@ -769,7 +771,7 @@ static QPair<QSystemLibrary*, QSystemLibrary*> loadOpenSslWin32()
#endif // !Q_PROCESSOR_x86_64
tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX),
- QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), pair);
+ QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result);
#undef QT_SSL_SUFFIX
@@ -778,28 +780,30 @@ static QPair<QSystemLibrary*, QSystemLibrary*> loadOpenSslWin32()
// When OpenSSL is built using MSVC then the libraries are named 'ssleay32.dll' and 'libeay32'dll'.
// When OpenSSL is built using GCC then different library names are used (depending on the OpenSSL version)
// The oldest version of a GCC-based OpenSSL which can be detected by the code below is 0.9.8g (released in 2007)
- if (!tryToLoadOpenSslWin32Library(QLatin1String("ssleay32"), QLatin1String("libeay32"), pair)) {
- if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-10"), QLatin1String("libcrypto-10"), pair)) {
- if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-8"), QLatin1String("libcrypto-8"), pair)) {
- tryToLoadOpenSslWin32Library(QLatin1String("libssl-7"), QLatin1String("libcrypto-7"), pair);
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("ssleay32"), QLatin1String("libeay32"), result)) {
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-10"), QLatin1String("libcrypto-10"), result)) {
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-8"), QLatin1String("libcrypto-8"), result)) {
+ tryToLoadOpenSslWin32Library(QLatin1String("libssl-7"), QLatin1String("libcrypto-7"), result);
}
}
}
#endif // !QT_CONFIG(opensslv11)
- return pair;
+ return result;
}
#else
-static QPair<QLibrary*, QLibrary*> loadOpenSsl()
+struct LoadedOpenSsl {
+ std::unique_ptr<QLibrary> ssl, crypto;
+};
+
+static LoadedOpenSsl loadOpenSsl()
{
- QPair<QLibrary*,QLibrary*> pair;
+ LoadedOpenSsl result = {qt_make_unique<QLibrary>(), qt_make_unique<QLibrary>()};
# if defined(Q_OS_UNIX)
- QLibrary *&libssl = pair.first;
- QLibrary *&libcrypto = pair.second;
- libssl = new QLibrary;
- libcrypto = new QLibrary;
+ QLibrary * const libssl = result.ssl.get();
+ QLibrary * const libcrypto = result.crypto.get();
// Try to find the libssl library on the system.
//
@@ -843,7 +847,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER));
if (libcrypto->load() && libssl->load()) {
// libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
- return pair;
+ return result;
} else {
libssl->unload();
libcrypto->unload();
@@ -862,7 +866,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
libssl->setFileNameAndVersion(QLatin1String("ssl"), fallbackSoname);
libcrypto->setFileNameAndVersion(QLatin1String("crypto"), fallbackSoname);
if (libcrypto->load() && libssl->load()) {
- return pair;
+ return result;
} else {
libssl->unload();
libcrypto->unload();
@@ -899,7 +903,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
# endif
if (libcrypto->load() && libssl->load()) {
// libssl.so.0 and libcrypto.so.0 found
- return pair;
+ return result;
} else {
libssl->unload();
libcrypto->unload();
@@ -924,7 +928,7 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
if (libssl->load()) {
// libssl.so.x and libcrypto.so.x found
- return pair;
+ return result;
} else {
libssl->unload();
}
@@ -934,41 +938,33 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl()
}
// failed to load anything
- delete libssl;
- delete libcrypto;
- libssl = libcrypto = 0;
- return pair;
+ result = {};
+ return result;
# else
// not implemented for this platform yet
- return pair;
+ return result;
# endif
}
#endif
+static QBasicMutex symbolResolveMutex;
+static QBasicAtomicInt symbolsResolved = Q_BASIC_ATOMIC_INITIALIZER(false);
+static bool triedToResolveSymbols = false;
+
bool q_resolveOpenSslSymbols()
{
- static bool symbolsResolved = false;
- static bool triedToResolveSymbols = false;
-#if QT_CONFIG(thread)
-#if QT_CONFIG(opensslv11)
- QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&q_OPENSSL_init_ssl));
-#else
- QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&q_SSL_library_init));
-#endif
-#endif
- if (symbolsResolved)
+ if (symbolsResolved.loadAcquire())
+ return true;
+ QMutexLocker locker(&symbolResolveMutex);
+ if (symbolsResolved.loadRelaxed())
return true;
if (triedToResolveSymbols)
return false;
triedToResolveSymbols = true;
-#ifdef Q_OS_WIN
- QPair<QSystemLibrary *, QSystemLibrary *> libs = loadOpenSslWin32();
-#else
- QPair<QLibrary *, QLibrary *> libs = loadOpenSsl();
-#endif
- if (!libs.first || !libs.second)
+ LoadedOpenSsl libs = loadOpenSsl();
+ if (!libs.ssl || !libs.crypto)
// failed to load them
return false;
@@ -978,6 +974,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OPENSSL_init_crypto)
RESOLVEFUNC(ASN1_STRING_get0_data)
RESOLVEFUNC(EVP_CIPHER_CTX_reset)
+ RESOLVEFUNC(EVP_PKEY_up_ref)
RESOLVEFUNC(EVP_PKEY_base_id)
RESOLVEFUNC(RSA_bits)
RESOLVEFUNC(OPENSSL_sk_new_null)
@@ -1016,8 +1013,6 @@ bool q_resolveOpenSslSymbols()
if (!_q_OpenSSL_version) {
// Apparently, we were built with OpenSSL 1.1 enabled but are now using
// a wrong library.
- delete libs.first;
- delete libs.second;
qCWarning(lcSsl, "Incompatible version of OpenSSL");
return false;
}
@@ -1139,8 +1134,6 @@ bool q_resolveOpenSslSymbols()
// OpenSSL 1.1 has deprecated and removed SSLeay. We consider a failure to
// resolve this symbol as a failure to resolve symbols.
// The right operand of '||' above is ... a bit of paranoia.
- delete libs.first;
- delete libs.second;
qCWarning(lcSsl, "Incompatible version of OpenSSL");
return false;
}
@@ -1204,6 +1197,11 @@ bool q_resolveOpenSslSymbols()
#ifndef OPENSSL_NO_RC2
RESOLVEFUNC(EVP_rc2_cbc)
#endif
+#ifndef OPENSSL_NO_AES
+ RESOLVEFUNC(EVP_aes_128_cbc)
+ RESOLVEFUNC(EVP_aes_192_cbc)
+ RESOLVEFUNC(EVP_aes_256_cbc)
+#endif
RESOLVEFUNC(EVP_sha1)
RESOLVEFUNC(EVP_PKEY_assign)
RESOLVEFUNC(EVP_PKEY_set1_RSA)
@@ -1212,6 +1210,7 @@ bool q_resolveOpenSslSymbols()
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
#endif
+ RESOLVEFUNC(EVP_PKEY_cmp)
RESOLVEFUNC(EVP_PKEY_free)
RESOLVEFUNC(EVP_PKEY_get1_DSA)
RESOLVEFUNC(EVP_PKEY_get1_RSA)
@@ -1405,9 +1404,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(d2i_PKCS12_bio)
RESOLVEFUNC(PKCS12_free)
- symbolsResolved = true;
- delete libs.first;
- delete libs.second;
+ symbolsResolved.storeRelease(true);
return true;
}
#endif // QT_CONFIG(library)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index 7b604b2ab8..69b2b90fbd 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -281,14 +281,20 @@ const EVP_CIPHER *q_EVP_des_ede3_cbc();
#ifndef OPENSSL_NO_RC2
const EVP_CIPHER *q_EVP_rc2_cbc();
#endif
+#ifndef OPENSSL_NO_AES
+const EVP_CIPHER *q_EVP_aes_128_cbc();
+const EVP_CIPHER *q_EVP_aes_192_cbc();
+const EVP_CIPHER *q_EVP_aes_256_cbc();
+#endif
Q_AUTOTEST_EXPORT const EVP_MD *q_EVP_sha1();
int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c);
Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
-int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
-int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
#ifndef OPENSSL_NO_EC
-int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
#endif
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
Q_AUTOTEST_EXPORT void q_EVP_PKEY_free(EVP_PKEY *a);
RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp
index f5aab821ea..2af437f0fa 100644
--- a/src/network/ssl/qsslsocket_opensslpre11.cpp
+++ b/src/network/ssl/qsslsocket_opensslpre11.cpp
@@ -67,7 +67,6 @@
#include <QtCore/qthread.h>
#include <QtCore/qfile.h>
#include <QtCore/qmutex.h>
-#include <QtCore/qlibrary.h>
QT_BEGIN_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_qt.cpp b/src/network/ssl/qsslsocket_qt.cpp
index b0fb60ea76..9ff9a66c05 100644
--- a/src/network/ssl/qsslsocket_qt.cpp
+++ b/src/network/ssl/qsslsocket_qt.cpp
@@ -72,6 +72,7 @@ static QAsn1Element _q_PKCS7_data(const QByteArray &data)
Some test vectors:
http://www.drh-consultancy.demon.co.uk/test.txt
+ \internal
*/
static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
{
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index 339ecf4da2..d7fb080b49 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -435,7 +435,7 @@ QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_schannel_mutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
void QSslSocketPrivate::ensureInitialized()
{
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index d54ac2ad73..39c1ce55e3 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -177,6 +177,7 @@ void QSslSocketPrivate::ensureInitialized()
long QSslSocketPrivate::sslLibraryVersionNumber()
{
+ // ### Qt 6: Find a proper replacement for the deprecated method below.
return QSysInfo::windowsVersion();
}