diff options
Diffstat (limited to 'src/network')
39 files changed, 349 insertions, 223 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 87a70d8a55..93afcf0ee1 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -219,7 +219,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]; @@ -234,7 +235,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); @@ -242,6 +243,11 @@ void QHttp2ProtocolHandler::_q_replyDestroyed(QObject *reply) } } +void QHttp2ProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData) +{ + streamIDs.remove(uploadData); +} + void QHttp2ProtocolHandler::_q_readyRead() { _q_receiveReply(); @@ -1249,7 +1255,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*))); @@ -1261,7 +1267,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); } } @@ -1343,10 +1351,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 9165808302..b582123961 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -93,6 +93,7 @@ public: private slots: void _q_uploadDataReadyRead(); void _q_replyDestroyed(QObject* reply); + void _q_uploadDataDestroyed(QObject* uploadData); private: using Stream = Http2::Stream; @@ -156,6 +157,7 @@ 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; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 2e38ac2dcf..1f1de478ea 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -1579,19 +1579,21 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN // dialog is displaying pauseConnection(); QHttpNetworkReply *reply; -#ifndef QT_NO_SSL - if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY) { + if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 + || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct +#if QT_CONFIG(ssl) + || connectionType == QHttpNetworkConnection::ConnectionTypeSPDY +#endif + ) { + // we choose the reply to emit the proxyAuth signal from somewhat arbitrarily, // but that does not matter because the signal will ultimately be emitted // by the QNetworkAccessManager. Q_ASSERT(chan->spdyRequestsToSend.count() > 0); reply = chan->spdyRequestsToSend.cbegin().value().second; } else { // HTTP -#endif // QT_NO_SSL reply = chan->reply; -#ifndef QT_NO_SSL } -#endif // QT_NO_SSL Q_ASSERT(reply); emit reply->proxyAuthenticationRequired(proxy, auth); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 9309d718e4..3c9d53c5b5 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -209,6 +209,9 @@ void QHttpNetworkConnectionChannel::init() void QHttpNetworkConnectionChannel::close() { + if (state == QHttpNetworkConnectionChannel::ClosingState) + return; + if (!socket) state = QHttpNetworkConnectionChannel::IdleState; else if (socket->state() == QAbstractSocket::UnconnectedState) @@ -1125,11 +1128,13 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth) { if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct #ifndef QT_NO_SSL || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY #endif ) { - connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth); + if (spdyRequestsToSend.count() > 0) + connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth); } else { // HTTP // Need to dequeue the request before we can emit the error. if (!reply) 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/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 9f8a42ad89..ee91dc20b3 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -59,6 +59,9 @@ using namespace emscripten; static void q_requestErrorCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; quintptr func = xhr["data-handler"].as<quintptr>(); @@ -77,19 +80,24 @@ static void q_requestErrorCallback(val event) static void q_progressCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); Q_ASSERT(reply); - if (xhr["lengthComputable"].as<bool>() && xhr["status"].as<int>() < 400) - reply->emitDataReadProgress(xhr["loaded"].as<qint64>(), xhr["total"].as<qint64>()); - + if (xhr["status"].as<int>() < 400) + reply->emitDataReadProgress(event["loaded"].as<int>(), event["total"].as<int>()); } static void q_loadCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; QNetworkReplyWasmImplPrivate *reply = @@ -121,6 +129,7 @@ static void q_loadCallback(val event) reader.set("data-handler", xhr["data-handler"]); reader.call<void>("readAsArrayBuffer", blob); + val::global("Module").delete_(reader); } @@ -136,6 +145,9 @@ static void q_loadCallback(val event) static void q_responseHeadersCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; if (xhr["readyState"].as<int>() == 2) { // HEADERS_RECEIVED @@ -152,12 +164,18 @@ static void q_responseHeadersCallback(val event) static void q_readBinary(val event) { + if (event.isNull() || event.isUndefined()) + return; + val fileReader = event["target"]; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fileReader["data-handler"].as<quintptr>()); Q_ASSERT(reply); + if (reply->state == QNetworkReplyPrivate::Finished || reply->state == QNetworkReplyPrivate::Aborted) + return; + // Set up source typed array val result = fileReader["result"]; // ArrayBuffer val Uint8Array = val::global("Uint8Array"); @@ -171,6 +189,10 @@ static void q_readBinary(val event) reinterpret_cast<quintptr>(buffer.data()), size); destinationTypedArray.call<void>("set", sourceTypedArray); reply->dataReceived(buffer, buffer.size()); + + event.delete_(fileReader); + Uint8Array.delete_(sourceTypedArray); + QCoreApplication::processEvents(); } @@ -194,19 +216,27 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate() { + m_xhr.set("onerror", val::null()); + m_xhr.set("onload", val::null()); + m_xhr.set("onprogress", val::null()); + m_xhr.set("onreadystatechange", val::null()); + m_xhr.set("data-handler", val::null()); } -QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() +QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) + : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent) { + Q_D( QNetworkReplyWasmImpl); + d->state = QNetworkReplyPrivate::Idle; } -QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) - : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent) +QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() { } QByteArray QNetworkReplyWasmImpl::methodName() const { + const Q_D( QNetworkReplyWasmImpl); switch (operation()) { case QNetworkAccessManager::HeadOperation: return "HEAD"; @@ -218,6 +248,8 @@ QByteArray QNetworkReplyWasmImpl::methodName() const return "POST"; case QNetworkAccessManager::DeleteOperation: return "DELETE"; + case QNetworkAccessManager::CustomOperation: + return d->request.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray(); default: break; } @@ -226,19 +258,23 @@ QByteArray QNetworkReplyWasmImpl::methodName() const void QNetworkReplyWasmImpl::close() { + QNetworkReply::close(); setFinished(true); emit finished(); - - QNetworkReply::close(); } void QNetworkReplyWasmImpl::abort() { - Q_D(const QNetworkReplyWasmImpl); - setError( QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); + Q_D( QNetworkReplyWasmImpl); + if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) + return; + + setError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); + d->doAbort(); close(); + d->state = QNetworkReplyPrivate::Aborted; } qint64 QNetworkReplyWasmImpl::bytesAvailable() const diff --git a/src/network/bearer/qbearerengine.cpp b/src/network/bearer/qbearerengine.cpp index 677da08cb6..a7c139fe63 100644 --- a/src/network/bearer/qbearerengine.cpp +++ b/src/network/bearer/qbearerengine.cpp @@ -46,24 +46,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) { } diff --git a/src/network/bearer/qbearerengine_p.h b/src/network/bearer/qbearerengine_p.h index a5a020a857..c69f478b26 100644 --- a/src/network/bearer/qbearerengine_p.h +++ b/src/network/bearer/qbearerengine_p.h @@ -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/qnetworkconfigmanager.cpp b/src/network/bearer/qnetworkconfigmanager.cpp index 81b5e01d6a..cd87c3669c 100644 --- a/src/network/bearer/qnetworkconfigmanager.cpp +++ b/src/network/bearer/qnetworkconfigmanager.cpp @@ -233,19 +233,20 @@ QNetworkConfigurationManager::QNetworkConfigurationManager(QObject *parent) : QObject(parent) { QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate(); - - connect(priv, SIGNAL(configurationAdded(QNetworkConfiguration)), - this, SIGNAL(configurationAdded(QNetworkConfiguration))); - connect(priv, SIGNAL(configurationRemoved(QNetworkConfiguration)), - this, SIGNAL(configurationRemoved(QNetworkConfiguration))); - connect(priv, SIGNAL(configurationChanged(QNetworkConfiguration)), - this, SIGNAL(configurationChanged(QNetworkConfiguration))); - connect(priv, SIGNAL(onlineStateChanged(bool)), - this, SIGNAL(onlineStateChanged(bool))); - connect(priv, SIGNAL(configurationUpdateComplete()), - this, SIGNAL(updateCompleted())); - - priv->enablePolling(); + if (priv) { + connect(priv, SIGNAL(configurationAdded(QNetworkConfiguration)), + this, SIGNAL(configurationAdded(QNetworkConfiguration))); + connect(priv, SIGNAL(configurationRemoved(QNetworkConfiguration)), + this, SIGNAL(configurationRemoved(QNetworkConfiguration))); + connect(priv, SIGNAL(configurationChanged(QNetworkConfiguration)), + this, SIGNAL(configurationChanged(QNetworkConfiguration))); + connect(priv, SIGNAL(onlineStateChanged(bool)), + this, SIGNAL(onlineStateChanged(bool))); + connect(priv, SIGNAL(configurationUpdateComplete()), + this, SIGNAL(updateCompleted())); + + priv->enablePolling(); + } } /*! diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index a903ecda5f..91ea063af1 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate() - : QObject(), pollTimer(0), mutex(QMutex::Recursive), + : QObject(), pollTimer(0), loader(QBearerEngineFactoryInterface_iid, QLatin1String("/bearer")), forcedPolling(0), firstUpdate(true) { 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_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.cpp b/src/network/bearer/qnetworksession.cpp index 471d322998..1636bcee97 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -258,7 +258,8 @@ QNetworkSession::QNetworkSession(const QNetworkConfiguration &connectionConfig, // invalid configuration if (!connectionConfig.identifier().isEmpty()) { - const auto engines = qNetworkConfigurationManagerPrivate()->engines(); + auto priv = qNetworkConfigurationManagerPrivate(); + const auto engines = priv ? priv->engines() : QList<QBearerEngine *>(); for (QBearerEngine *engine : engines) { if (engine->hasIdentifier(connectionConfig.identifier())) { d = engine->createSessionBackend(); 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/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf index 4f667eed9d..5465b1c0af 100644 --- a/src/network/doc/qtnetwork.qdocconf +++ b/src/network/doc/qtnetwork.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtbase.qdocconf) project = QtNetwork description = Qt Network Reference Documentation diff --git a/src/network/doc/src/dontdocument.qdoc b/src/network/doc/src/dontdocument.qdoc new file mode 100644 index 0000000000..fe2e54b34c --- /dev/null +++ b/src/network/doc/src/dontdocument.qdoc @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \dontdocument (QTypeInfo QMetaTypeId QIPv6Address) +*/ diff --git a/src/network/doc/src/ssl.qdoc b/src/network/doc/src/ssl.qdoc index a3af1d0477..e485a1b393 100644 --- a/src/network/doc/src/ssl.qdoc +++ b/src/network/doc/src/ssl.qdoc @@ -77,11 +77,12 @@ \section1 Import and Export Restrictions - Due to import and export restrictions in some parts of the world, we - are unable to supply the OpenSSL Toolkit with Qt packages. Developers wishing - to use SSL communication in their deployed applications should either ensure - that their users have the appropriate libraries installed, or they should - consult a suitably qualified legal professional to ensure that applications - using code from the OpenSSL project are correctly certified for import - and export in relevant regions of the world. + Qt binary installers include the OpenSSL libraries used by QtNetwork. However, + those are not automatically deployed with applications that are built with Qt. + Import and export restrictions apply for some types of software, and for + some parts of the world. Developers wishing to use SSL communication in their + deployed applications should either ensure that their users have the appropriate + libraries installed, or they should consult a suitably qualified legal + professional to ensure that applications using code from the OpenSSL project + are correctly certified for import and export in relevant regions of the world. */ diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 3ca8806c2b..4100dfd784 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -52,7 +52,6 @@ #ifdef Q_OS_WIN #include <qmutex.h> -#include <private/qmutexpool_p.h> #include <rpc.h> #endif 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/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 9374728244..25ff873307 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -891,7 +891,7 @@ void QHostInfoRunnable::run() // thread goes back to QThreadPool } -QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false) +QHostInfoLookupManager::QHostInfoLookupManager() : wasDeleted(false) { moveToThread(QCoreApplicationPrivate::mainThread()); #if QT_CONFIG(thread) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 3c0ee2a0d8..7df3f5414c 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -252,7 +252,7 @@ protected: #if QT_CONFIG(thread) QThreadPool threadPool; #endif - QMutex mutex; + QRecursiveMutex mutex; bool wasDeleted; diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 3646a9526a..110550c423 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); @@ -925,7 +924,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/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 24e8eabb6e..b429b3c365 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -608,13 +608,13 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() socketType = qt_socket_getType(socketDescriptor); #if defined (QNATIVESOCKETENGINE_DEBUG) - QString socketProtocolStr = "UnknownProtocol"; - if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; - else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; + QString socketProtocolStr = QStringLiteral("UnknownProtocol"); + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol"); + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QStringLiteral("IPv6Protocol"); - QString socketTypeStr = "UnknownSocketType"; - if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; - else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; + QString socketTypeStr = QStringLiteral("UnknownSocketType"); + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket"); + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket"); qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() localAddress == %s, localPort = %i, peerAddress == %s, peerPort = %i, socketProtocol == %s, socketType == %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort, socketProtocolStr.toLatin1().constData(), socketTypeStr.toLatin1().constData()); #endif @@ -1477,8 +1477,8 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %li) == %li", - data, qt_prettyDebug(data, qMin((int)ret, 16), (int)ret).data(), (int)len, (int)ret); + qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %lli) == %lli", + data, qt_prettyDebug(data, qMin(int(ret), 16), int(ret)).data(), len, ret); #endif return ret; @@ -1520,11 +1520,11 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) #if defined (QNATIVESOCKETENGINE_DEBUG) if (ret != -2) { - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %li) == %li", - data, qt_prettyDebug(data, qMin((int)bytesRead, 16), (int)bytesRead).data(), (int)maxLength, (int)ret); + qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli", + data, qt_prettyDebug(data, qMin(int(bytesRead), 16), int(bytesRead)).data(), maxLength, ret); } else { - qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %li) == -2 (WOULD BLOCK)", - data, int(maxLength)); + qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %lli) == -2 (WOULD BLOCK)", + data, maxLength); } #endif diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 27657956df..4207832c4c 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 .... @@ -1188,6 +1186,8 @@ void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification() break; case RequestMethodSent: parseRequestMethodReply(); + if (socks5State == Connected && data->controlSocket->bytesAvailable()) + _q_controlSocketReadNotification(); break; case Connected: { QByteArray buf; @@ -1611,8 +1611,10 @@ qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHea QSocks5RevivedDatagram datagram = d->udpData->pendingDatagrams.dequeue(); int copyLen = qMin<int>(maxlen, datagram.data.size()); memcpy(data, datagram.data.constData(), copyLen); - header->senderAddress = datagram.address; - header->senderPort = datagram.port; + if (header) { + header->senderAddress = datagram.address; + header->senderPort = datagram.port; + } return copyLen; #else Q_UNUSED(data) @@ -1749,6 +1751,11 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) return false; if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; + if (bytesAvailable() && d->readNotificationPending) { + // We've got some data incoming, but the queued call hasn't been performed yet. + // The data is where we expect it to be already, so just return true. + return true; + } // we're connected if (d->mode == QSocks5SocketEnginePrivate::ConnectMode || 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 79f0cfd1d4..bf27bb768b 100644 --- a/src/network/ssl/qocspresponse.cpp +++ b/src/network/ssl/qocspresponse.cpp @@ -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 0e134d236b..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 @@ -100,7 +100,7 @@ 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/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index fe81bd5fcf..ca6c58117d 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -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(); @@ -2378,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_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 6a8269b521..d4bad1b1a5 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -71,6 +71,10 @@ #include "qwindowscarootfetcher_p.h" #endif +#if !QT_CONFIG(opensslv11) +#include <openssl/x509_vfy.h> +#endif + #include <QtCore/qdatetime.h> #include <QtCore/qdebug.h> #include <QtCore/qdir.h> @@ -137,6 +141,55 @@ static unsigned int q_ssl_psk_server_callback(SSL *ssl, Q_ASSERT(d); return d->tlsPskServerCallback(identity, psk, max_psk_len); } + +#ifdef TLS1_3_VERSION +#ifndef OPENSSL_NO_PSK +static unsigned int q_ssl_psk_restore_client(SSL *ssl, + const char *hint, + char *identity, unsigned int max_identity_len, + unsigned char *psk, unsigned int max_psk_len) +{ + Q_UNUSED(hint); + Q_UNUSED(identity); + Q_UNUSED(max_identity_len); + Q_UNUSED(psk); + Q_UNUSED(max_psk_len); + +#ifdef QT_DEBUG + QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData)); + Q_ASSERT(d); + Q_ASSERT(d->mode == QSslSocket::SslClientMode); +#endif + q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback); + + return 0; +} +#endif // !OPENSSL_NO_PSK + +static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, + size_t *idlen, SSL_SESSION **sess) +{ + Q_UNUSED(ssl); + Q_UNUSED(md); + Q_UNUSED(id); + Q_UNUSED(idlen); + Q_UNUSED(sess); + +#ifndef OPENSSL_NO_PSK +#ifdef QT_DEBUG + QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData)); + Q_ASSERT(d); + Q_ASSERT(d->mode == QSslSocket::SslClientMode); +#endif + + // Temporarily rebind the psk because it will be called next. The function will restore it. + q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_restore_client); +#endif + + return 1; // need to return 1 or else "the connection setup fails." +} +#endif // TLS1_3_VERSION + #endif #if QT_CONFIG(ocsp) @@ -345,47 +398,41 @@ bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, #endif // ocsp -// ### This list is shared between all threads, and protected by a -// mutex. Investigate using thread local storage instead. Or better properly -// use OpenSSL's ability to attach application data to an SSL/SSL_CTX -// and extract it in a callback. See how it's done, for example, in PSK -// callback or in DTLS verification callback. -struct QSslErrorList -{ - QMutex mutex; - QVector<QSslErrorEntry> errors; -}; - -Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList) - int q_X509Callback(int ok, X509_STORE_CTX *ctx) { if (!ok) { // Store the error and at which depth the error was detected. - _q_sslErrorList()->errors << QSslErrorEntry::fromStoreContext(ctx); -#if !QT_CONFIG(opensslv11) -#ifdef QSSLSOCKET_DEBUG - qCDebug(lcSsl) << "verification error: dumping bad certificate"; - qCDebug(lcSsl) << QSslCertificatePrivate::QSslCertificate_from_X509(q_X509_STORE_CTX_get_current_cert(ctx)).toPem(); - qCDebug(lcSsl) << "dumping chain"; - const auto certs = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(q_X509_STORE_CTX_get_chain(ctx)); - for (const QSslCertificate &cert : certs) { - qCDebug(lcSsl) << "Issuer:" << "O=" << cert.issuerInfo(QSslCertificate::Organization) - << "CN=" << cert.issuerInfo(QSslCertificate::CommonName) - << "L=" << cert.issuerInfo(QSslCertificate::LocalityName) - << "OU=" << cert.issuerInfo(QSslCertificate::OrganizationalUnitName) - << "C=" << cert.issuerInfo(QSslCertificate::CountryName) - << "ST=" << cert.issuerInfo(QSslCertificate::StateOrProvinceName); - qCDebug(lcSsl) << "Subject:" << "O=" << cert.subjectInfo(QSslCertificate::Organization) - << "CN=" << cert.subjectInfo(QSslCertificate::CommonName) - << "L=" << cert.subjectInfo(QSslCertificate::LocalityName) - << "OU=" << cert.subjectInfo(QSslCertificate::OrganizationalUnitName) - << "C=" << cert.subjectInfo(QSslCertificate::CountryName) - << "ST=" << cert.subjectInfo(QSslCertificate::StateOrProvinceName); - qCDebug(lcSsl) << "Valid:" << cert.effectiveDate() << '-' << cert.expiryDate(); + + using ErrorListPtr = QVector<QSslErrorEntry>*; + ErrorListPtr errors = nullptr; + + // Error list is attached to either 'SSL' or 'X509_STORE'. + if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) { // We try store first: +#if QT_CONFIG(opensslv11) + errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0)); +#else + errors = ErrorListPtr(q_CRYPTO_get_ex_data(&store->ex_data, 0)); +#endif // opensslv11 } -#endif // QSSLSOCKET_DEBUG -#endif // !QT_CONFIG(opensslv11) + + if (!errors) { + // Not found on store? Try SSL and its external data then. According to the OpenSSL's + // documentation: + // + // "Whenever a X509_STORE_CTX object is created for the verification of the peers certificate + // during a handshake, a pointer to the SSL object is stored into the X509_STORE_CTX object + // to identify the connection affected. To retrieve this pointer the X509_STORE_CTX_get_ex_data() + // function can be used with the correct index." + if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()))) + errors = ErrorListPtr(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData + 1)); + } + + if (!errors) { + qCWarning(lcSsl, "Neither X509_STORE, nor SSL contains error list, handshake failure"); + return 0; + } + + errors->append(QSslErrorEntry::fromStoreContext(ctx)); } // Always return OK to allow verification to continue. We handle the // errors gracefully after collecting all errors, after verification has @@ -481,7 +528,7 @@ bool QSslSocketBackendPrivate::initSslContext() 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); } @@ -541,11 +588,7 @@ bool QSslSocketBackendPrivate::initSslContext() else q_SSL_set_accept_state(ssl); -#if OPENSSL_VERSION_NUMBER >= 0x10001000L - // Save a pointer to this object into the SSL structure. - if (QSslSocket::sslLibraryVersionNumber() >= 0x10001000L) - q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this); -#endif + q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this); #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) // Set the client callback for PSK @@ -556,6 +599,13 @@ bool QSslSocketBackendPrivate::initSslContext() q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback); } #endif +#if OPENSSL_VERSION_NUMBER >= 0x10101006L + // Set the client callback for TLSv1.3 PSK + if (mode == QSslSocket::SslClientMode + && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) { + q_SSL_set_psk_use_session_callback(ssl, &q_ssl_psk_use_session_callback); + } +#endif // openssl version >= 0x10101006L #if QT_CONFIG(ocsp) if (configuration.ocspStaplingEnabled) { @@ -1123,14 +1173,14 @@ bool QSslSocketBackendPrivate::startHandshake() if (inSetAndEmitError) return false; - QMutexLocker locker(&_q_sslErrorList()->mutex); - _q_sslErrorList()->errors.clear(); + QVector<QSslErrorEntry> lastErrors; + q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + 1, &lastErrors); int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl); + q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + 1, nullptr); - const auto &lastErrors = _q_sslErrorList()->errors; if (!lastErrors.isEmpty()) storePeerCertificates(); - for (const auto ¤tError : lastErrors) { + for (const auto ¤tError : qAsConst(lastErrors)) { emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code, configuration.peerCertificateChain.value(currentError.depth))); if (q->state() != QAbstractSocket::ConnectedState) @@ -1138,7 +1188,6 @@ bool QSslSocketBackendPrivate::startHandshake() } errorList << lastErrors; - locker.unlock(); // Connection aborted during handshake phase. if (q->state() != QAbstractSocket::ConnectedState) @@ -1520,28 +1569,14 @@ bool QSslSocketBackendPrivate::checkOcspStatus() // 3) It checks CertID in response. // 4) Ensures the responder is authorized to sign the status respond. // - // Here it's important to notice that it calls X509_cert_verify and - // as a result, possibly, our verification callback. Given this callback - // at the moment uses a global variable, we have to lock. This will change - // as soon as we fix our verification procedure. - // Also note, OpenSSL prior to 1.0.2b would only use bs->certs to + // Note, OpenSSL prior to 1.0.2b would only use bs->certs to // verify the responder's chain (see their commit 4ba9a4265bd). // Working this around - is too much fuss for ancient versions we // are dropping quite soon anyway. - { - const unsigned long verificationFlags = 0; - const QMutexLocker locker(&_q_sslErrorList()->mutex); - // Before unlocking the mutex, startHandshake() stores errors (found in SSL_connect() - // or SSL_accept()) into the local variable, so it's safe to clear it here - as soon - // as we managed to lock, whoever had the lock before, already stored their own copy - // of errors. - _q_sslErrorList()->errors.clear(); - const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags); - if (success <= 0 || _q_sslErrorList()->errors.size()) { - _q_sslErrorList()->errors.clear(); - ocspErrors.push_back(QSslError::OcspResponseCannotBeTrusted); - } - } + const unsigned long verificationFlags = 0; + const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags); + if (success <= 0) + ocspErrors.push_back(QSslError::OcspResponseCannotBeTrusted); if (q_OCSP_resp_count(basicResponse) != 1) { ocspErrors.push_back(QSslError::OcspMalformedResponse); @@ -1752,7 +1787,20 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & } } - QMutexLocker sslErrorListMutexLocker(&_q_sslErrorList()->mutex); + QVector<QSslErrorEntry> lastErrors; +#if QT_CONFIG(opensslv11) + if (!q_X509_STORE_set_ex_data(certStore, 0, &lastErrors)) { + qCWarning(lcSsl) << "Unable to attach external data (error list) to a store"; + errors << QSslError(QSslError::UnspecifiedError); + return errors; + } +#else + if (!q_CRYPTO_set_ex_data(&certStore->ex_data, 0, &lastErrors)) { + qCWarning(lcSsl) << "Unable to attach external data (error list) to a store"; + errors << QSslError(QSslError::UnspecifiedError); + return errors; + } +#endif // opensslv11 // Register a custom callback to get all verification errors. q_X509_STORE_set_verify_cb(certStore, q_X509Callback); @@ -1802,12 +1850,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates); // Now process the errors - const auto errorList = std::move(_q_sslErrorList()->errors); - _q_sslErrorList()->errors.clear(); - sslErrorListMutexLocker.unlock(); - - // Translate the errors if (QSslCertificatePrivate::isBlacklisted(certificateChain[0])) { QSslError error(QSslError::CertificateBlacklisted, certificateChain[0]); errors << error; @@ -1821,8 +1864,8 @@ QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> & } // Translate errors from the error list into QSslErrors. - errors.reserve(errors.size() + errorList.size()); - for (const auto &error : qAsConst(errorList)) + errors.reserve(errors.size() + lastErrors.size()); + for (const auto &error : qAsConst(lastErrors)) errors << _q_OpenSSL_to_QSslError(error.code, certificateChain.value(error.depth)); q_X509_STORE_free(certStore); diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp index b60b8be41f..cc2d6ea2d9 100644 --- a/src/network/ssl/qsslsocket_openssl11.cpp +++ b/src/network/ssl/qsslsocket_openssl11.cpp @@ -68,6 +68,7 @@ #include <QtCore/qfile.h> #include <QtCore/qmutex.h> #include <QtCore/qlibrary.h> +#include <QtCore/qoperatingsystemversion.h> QT_BEGIN_NAMESPACE @@ -147,7 +148,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() //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) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::WindowsVista) 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 9d0a14360d..0fe0899d4f 100644 --- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h @@ -107,6 +107,8 @@ Q_AUTOTEST_EXPORT void q_X509_up_ref(X509 *a); long q_X509_get_version(X509 *a); EVP_PKEY *q_X509_get_pubkey(X509 *a); void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb); +int q_X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data); +void *q_X509_STORE_get_ex_data(X509_STORE *r, int idx); STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx); void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); int q_DH_bits(DH *dh); @@ -184,4 +186,10 @@ const OCSP_CERTID *q_OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x); #define q_SSL_CTX_set_max_proto_version(ctx, version) \ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr) +extern "C" { +typedef int (*q_SSL_psk_use_session_cb_func_t)(SSL *, const EVP_MD *, const unsigned char **, size_t *, + SSL_SESSION **); +} +void q_SSL_set_psk_use_session_callback(SSL *s, q_SSL_psk_use_session_cb_func_t); + #endif diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 6f935a02e4..2eb9763e90 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -164,6 +164,7 @@ DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return) DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return) #ifdef TLS1_3_VERSION DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return) +DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG) #endif DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return) DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return) @@ -179,6 +180,8 @@ DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return nullptr, return) DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return) DEFINEFUNC(EVP_PKEY *, X509_get_pubkey, X509 *a, a, return nullptr, return) DEFINEFUNC2(void, X509_STORE_set_verify_cb, X509_STORE *a, a, X509_STORE_CTX_verify_cb verify_cb, verify_cb, return, DUMMYARG) +DEFINEFUNC3(int, X509_STORE_set_ex_data, X509_STORE *a, a, int idx, idx, void *data, data, return 0, return) +DEFINEFUNC2(void *, X509_STORE_get_ex_data, X509_STORE *r, r, int idx, idx, return nullptr, return) DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get0_chain, X509_STORE_CTX *a, a, return nullptr, return) DEFINEFUNC3(void, CRYPTO_free, void *str, str, const char *file, file, int line, line, return, DUMMYARG) DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return) @@ -253,6 +256,8 @@ DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return) DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG) DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG) DEFINEFUNC(void, CRYPTO_free, void *a, a, return, DUMMYARG) +DEFINEFUNC3(int, CRYPTO_set_ex_data, CRYPTO_EX_DATA *ad, ad, int idx, idx, void *val, val, return 0, return) +DEFINEFUNC2(void *, CRYPTO_get_ex_data, const CRYPTO_EX_DATA *ad, ad, int idx, idx, return nullptr, return) DEFINEFUNC(unsigned long, ERR_peek_last_error, DUMMYARG, DUMMYARG, return 0, return) DEFINEFUNC(void, ERR_free_strings, void, DUMMYARG, return, DUMMYARG) DEFINEFUNC(void, EVP_CIPHER_CTX_cleanup, EVP_CIPHER_CTX *a, a, return, DUMMYARG) @@ -525,6 +530,7 @@ DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, ret DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, return) DEFINEFUNC(int, X509_STORE_CTX_get_error_depth, X509_STORE_CTX *a, a, return -1, return) DEFINEFUNC(X509 *, X509_STORE_CTX_get_current_cert, X509_STORE_CTX *a, a, return nullptr, return) +DEFINEFUNC(X509_STORE *, X509_STORE_CTX_get0_store, X509_STORE_CTX *ctx, ctx, return nullptr, return) DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC2(void *, X509_STORE_CTX_get_ex_data, X509_STORE_CTX *ctx, ctx, int idx, idx, return nullptr, return) DEFINEFUNC(int, SSL_get_ex_data_X509_STORE_CTX_idx, DUMMYARG, DUMMYARG, return -1, return) @@ -975,6 +981,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(SSL_CTX_set_options) #ifdef TLS1_3_VERSION RESOLVEFUNC(SSL_CTX_set_ciphersuites) + RESOLVEFUNC(SSL_set_psk_use_session_callback) #endif // TLS 1.3 or OpenSSL > 1.1.1 RESOLVEFUNC(SSL_get_client_random) RESOLVEFUNC(SSL_SESSION_get_master_key) @@ -992,6 +999,8 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(X509_get_version) RESOLVEFUNC(X509_get_pubkey) RESOLVEFUNC(X509_STORE_set_verify_cb) + RESOLVEFUNC(X509_STORE_set_ex_data) + RESOLVEFUNC(X509_STORE_get_ex_data) RESOLVEFUNC(CRYPTO_free) RESOLVEFUNC(OpenSSL_version_num) RESOLVEFUNC(OpenSSL_version) @@ -1063,6 +1072,8 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(CRYPTO_num_locks) RESOLVEFUNC(CRYPTO_set_id_callback) RESOLVEFUNC(CRYPTO_set_locking_callback) + RESOLVEFUNC(CRYPTO_set_ex_data) + RESOLVEFUNC(CRYPTO_get_ex_data) RESOLVEFUNC(ERR_peek_last_error) RESOLVEFUNC(ERR_free_strings) RESOLVEFUNC(EVP_CIPHER_CTX_cleanup) @@ -1324,6 +1335,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(X509_STORE_CTX_get_error) RESOLVEFUNC(X509_STORE_CTX_get_error_depth) RESOLVEFUNC(X509_STORE_CTX_get_current_cert) + RESOLVEFUNC(X509_STORE_CTX_get0_store) RESOLVEFUNC(X509_cmp) RESOLVEFUNC(X509_STORE_CTX_get_ex_data) diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index fcf96dbd47..69b2b90fbd 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -464,6 +464,7 @@ int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); int q_X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); int q_X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +X509_STORE *q_X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx); // Diffie-Hellman support DH *q_DH_new(); 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_opensslpre11_symbols_p.h b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h index 46b6505346..f5626d5d16 100644 --- a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h +++ b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h @@ -84,6 +84,8 @@ int q_CRYPTO_num_locks(); void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int)); void q_CRYPTO_set_id_callback(unsigned long (*a)()); void q_CRYPTO_free(void *a); +int q_CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val); +void *q_CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx); unsigned long q_ERR_peek_last_error(); void q_ERR_free_strings(); void q_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a); diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp index 0bbe6fe57d..cb0e86fa1f 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(); } |